There are situations where InnoDB deadlock would come up when you least expect it. For example, SELECT queries can perform locks on the gen_clust_index, aka the Clustered Index.
Here are three past questions I agressively looked over with @RedBlueThing, the person who asked these questions. @RedBlueThing found work arounds for his questions.
Just to keep your question in perspective, when you look over these answers (don't look too deeply, even I get dizzy looking at my own convoluted answers) it should be quickly apparent that even SELECT queries can lock InnoDB data. Although autocommit could be enabled (rendering each query its own transaction), a single SQL statement can still be victimized by deadlocks.
You also have special cases of SELECT where you can lock specific rows on demand.
Based on InnoDB Deadlocking link, the sequences of event to cause this situation could theoretically be as follows:
- Your SQL UPDATEs a single row but generates an error
- The UPDATE causes a rollback of the one row
- The row has a lingering lock
Personally, that last statement scares me. It would have been nice for MySQL to inform everyone of this quirk instead of just documenting and hopong you google for it. Yet, that statement is from the MySQL Documentation. (Oh yeah, Oracle owns InnoDB)
Using the techniques described here to rank items in MySQL, you can calculate the scores you need using a derived table and some hackery with user variables.
Here's your table with the sample data you provided:
CREATE TABLE blah (
id INT
, value INT
);
INSERT blah (id, value)
VALUES
(1, 3)
, (2, 5)
, (3, 2)
, (4, 5)
;
And here's the query you need:
-- find the min and max ranks for later use
SELECT
@min_rank := 1 AS min_rank
, @max_rank := (SELECT COUNT(DISTINCT value) FROM blah) AS max_rank
;
-- use the calculated min and max ranks to calculate score
SELECT
id
, value
, rank
, 10.0 * (@max_rank - rank) / (@max_rank - @min_rank) AS score
FROM (
SELECT
id
, value
, @curr_rank := IF(@prev_rank = value, @curr_rank, @curr_rank + 1) AS rank
, @prev_rank := value
FROM blah, (SELECT @curr_rank := 0) r, (SELECT @prev_rank := NULL) p
ORDER BY value DESC
) ranked_blah;
The output I get for the second query on SQL Fiddle is as follows:
| ID | VALUE | RANK | SCORE |
-----------------------------
| 2 | 5 | 1 | 10 |
| 4 | 5 | 1 | 10 |
| 1 | 3 | 2 | 5 |
| 3 | 2 | 3 | 0 |
Note that this approach will work best if you have an index on value
. This will let you find @max_rank
quickly using the COUNT
technique @ypercube described.
Best Answer
= is the assignement operator only for SET statements,in your case is a comparison operator,for SELECT use
rank := rank+1
Example
Result 0
Result 2