đČ â mikrobloggeriet olorm â olorm-20 · olorm-21 · olorm-22
PĂ„ prosjektet har vi en relasjonsdatabase med en ganske stor tabell med over 30 millioner rader. Innslagene inneholder tidspunkt med âitemâs status med mer. Ca slik:
+----------+---------+------------+---------+----
| id | item_id | version_id | state | ...
+----------+---------+------------+---------+----
| 45649802 | 11111 | 1 | A |
| 45649811 | 11111 | 2 | B |
| 45649817 | 12222 | 2 | C |
Vi oppdaget at noen status-innslag manglet, og trengte Ă„ hente ut
alle disses item_id
. Vi ville finne alle som har state
B
, men ikke har hatt state A
. Jeg liker
HAVING SUM(CASE
for slike spĂžrringer:
SELECT item_id
FROM history
GROUP BY item_id
HAVING SUM(CASE WHEN state = 'A' THEN 1 ELSE 0 END) = 0
AND SUM(CASE WHEN state = 'B' THEN 1 ELSE 0 END) > 0
Men nÄr rekkefÞlge teller, liker jeg
LEFT JOIN WHERE NULL
:
SELECT t1.item_id
FROM history t1
LEFT JOIN history t2
ON t2.item_id = t1.item_id
AND t2.version_id > t1.version_id
LEFT JOIN history t0
ON t0.item_id = t1.item_id
AND t0.version_id < t1.version_id
AND t0.state = 'A'
WHERE t1.state = 'B'
AND t0.item_id IS NULL
AND t2.item_id IS NULL ;
Denne sier to ting:
B
er siste status (t2
med nyere rad
finnes ikke; IS NULL
).A
finnes
(t0
).Hvis dette feiler (SQLâen tar for lang tid), kan man velge Ă„ frigjĂžre seg fra databasen:
mysqldump -u USER -p \
--single-transaction --quick --lock-tables=false \
DATABASE history > hist.sql
grep INSERT hist.sql | tr \( \\n | grep , > hist.csv
sort -s -t , -k 2 -k 3 hist.csv > sorted.csv
De fĂžrste kommandoene her tar noen minutter. sort
bruker
lenger tid pÄ store filer, men er veldig robust.
< sorted.csv awk -F "'?,'?" '{
if ($2 != prev) {
if (match(states, "B$") && !match(states, ",A,"))
print prev
states = ""
}
states = states "," $4
prev = $2 }' > itemIDs.txt
For hver item_id
($2
= kolonne 2): print
hvis siste state var B
og ingen tidligere state
A
fantes.
Det er sikkert mange mulige mÄter Ä lÞse denne oppgaven pÄ, dette var én mÄte.
For meg virket LEFT JOIN
-teknikken bra, og jeg synes de
deklarative SQL-spÞrringene er enklere Ä lese og forstÄ enn den mer
imperative AWK-koden.
Jeg liker dog at man har muligheten til Ä lÞse (og dobbeltsjekke) oppgaven pÄ flere mÄter.
Send gjerne spÞrsmÄl eller kommentarer til Richard Tingstad :)