In assenza di funzioni della finestra, puoi ordinare tbl
e usa le variabili utente per calcolare tu stesso il rango sulle tue partizioni (valori "data"):
SELECT "date", -- D) Desired columns
id,
value,
rank
FROM (SELECT "date", -- C) Rank by date
id,
value,
CASE COALESCE(@partition, "date")
WHEN "date" THEN @rank := @rank + 1
ELSE @rank := 1
END AS rank,
@partition := "date" AS dummy
FROM (SELECT @rank := 0 AS rank, -- A) User var init
@partition := NULL AS partition) dummy
STRAIGHT_JOIN
( SELECT "date", -- B) Ordering query
id,
value
FROM tbl
ORDER BY date, value) tbl_ordered;
Aggiorna
Allora, che cosa sta facendo quella query?
Stiamo utilizzando variabili utente per "scorrere" in un set di risultati ordinato, incrementando o azzerando un contatore (@rank
) a seconda del segmento contiguo del set di risultati (tracciato in @partition
) ci siamo.
Nella query A inizializziamo due variabili utente. Nella query B otteniamo i record della tua tabella nell'ordine di cui abbiamo bisogno:prima per data e poi per valore. A e B insieme creano una tabella derivata, tbl_ordered
, assomiglia a questo:
rank | partition | "date" | id | value
---- + --------- + ------ + ---- + -----
0 | NULL | d1 | id2 | 1
0 | NULL | d1 | id1 | 2
0 | NULL | d2 | id1 | 10
0 | NULL | d2 | id2 | 11
Ricorda, non ci interessano le colonne dummy.rank
e dummy.partition
— sono solo casualità di come inizializziamo le variabili @rank
e @partition
.
Nella query C esaminiamo i record della tabella derivata. Quello che stiamo facendo è più o meno quello che fa il seguente pseudocodice:
rank = 0
partition = nil
foreach row in fetch_rows(sorted_query):
(date, id, value) = row
if partition is nil or partition == date:
rank += 1
else:
rank = 1
partition = date
stdout.write(date, id, value, rank, partition)
Infine, interroga D proietta tutte le colonne da C tranne per la colonna contenente @partition
(che abbiamo chiamato dummy
e non è necessario visualizzare).