01. september 2008 - 15:09Der er
12 kommentarer og 1 løsning
Avanceret inner join - udregn time_diff imellem records
Jeg har en tabel, hvor i der findes en række events/records. Jeg ønsker at lave et udtræk som giver mig tidsforskellen imelle første og sidste event for en event.
stat ------ id (int) unikey (varchar(50)) dato (date) tid (time) rutine (tinyint)
(det er de væsentlige info - der er en masse uinteressante felter som beskriver eventen)
OK - de her event beskriver en fysisk handling hvor en medarbejder scanner en pakke i virksomheden. Et scan kan i feltet rutine enten være 1 : Modtaget 2 : Leveret 3 : Terminal (bruges ikke her)
Jeg ønsker at lave et udtræk hvor jeg finder unikke UNIKEY og udregner tidsforskellen i timer fra FØRSTE (rutine=1) til SIDSTE (rutine=2) - der kan være (i teorien uendeligt) en masse "mellem-scan" som kan have både 1,2,3
Her er hvad jeg nåede frem til: SELECT a.unikey, a.dato as datostart, a.tid as tidstart, b.dato as datoslut, b.tid as tidslut, TIMEDIFF( (concat(b.dato," ", b.tid) ),(concat(a.dato," ", a.tid) ) ) FROM stat_147 a INNER JOIN stat_147 b ON a.unikey = b.unikey WHERE a.rutine = 1 AND b.rutine = 2 AND a.unikey <> "" ORDER BY a.dato ASC, a.tid ASC, b.dato DESC, b.dato DESC LIMIT 500;
Problemet er bare at hvis jeg kører det her, så kopieres der 230.000 records over i tmp - jeg har indekseret flg :
id, unikey, dato,tid,rutine
Er der en venlig (og dygtig) sjæl som kan hjælpe her ??
Hov hov - det er kun hvis jeg "ORDER BY a.dato ASC, a.tid ASC, b.dato DESC, b.dato DESC " SÅ bliver der kopieret over i tmp - ellers går det hurtigt, men forkert.
SELECT unikey, mintimestamp, maxtimestamp, TIMEDIFF( sluttimestamp,starttimestamp) AS regtime FROM ( SELECT unikey, MIN(CONCAT.dato,' ', tid)) AS starttimestamp, MAX(CONCAT(dato, ' ', tid)) AS sluttimestamp FROM stat_147 GROUP BY unikey ) AS a
SELECT unikey, starttimestamp, sluttimestamp, TIMEDIFF( sluttimestamp,starttimestamp) AS regtime FROM ( SELECT unikey, MIN(CONCAT.dato,' ', tid)) AS starttimestamp, MAX(CONCAT(dato, ' ', tid)) AS sluttimestamp FROM stat_147 GROUP BY unikey ) AS a
Hvordan kan jeg evt. optimere på mine index's så det er hurtigst muligt, hvad bør jeg indexere ?? (der kommer omkring 10.000 linjer hver dag, så der kommer til at være mange data i databasen)
hmm - det er ikke altid at træerne vokser ind i himlen :-)
Det er væsenligt at der både findes en rutine = 1 SAMT rutine = 2, det betyder at pakken både er modtaget og afleveret - det bliver ikke kontrolleret i det query - kan du få den med ind i ??
Det var derfor at jeg i mit join havde "a.rutine = 1 AND b.rutine = 2" - jeg har aldrig arbejedet med subquery's - så jeg kan ikke gennemskue hvordan det hænger sammen.
Betyder det, at kun unikey, hvor der både findes en rutine 1 og en rutine 2 skal medtages?
I så fald kunne den måske ændres til:
SELECT unikey, starttimestamp, sluttimestamp, TIMEDIFF( sluttimestamp,starttimestamp) AS regtime FROM ( SELECT unikey, MIN(CONCAT.dato,' ', tid)) AS starttimestamp, MAX(CONCAT(dato, ' ', tid)) AS sluttimestamp FROM stat_147 GROUP BY unikey HAVING SUM(CASE WHERE rutine=1 THEN 1 ELSE 0 END) > 0 AND SUM(CASE WHERE rutine=2 THEN 1 ELSE 0 END) > 0 ) AS a
Mht. index, så bør der være et index på unikey feltet. Derudover kan jeg ikke umiddelbart se nogen grund til at indexere andre felter på baggrund af denne query.
kjulius > hvis du fortsat lytter med så har jeg brug for din hjælp til at rette lidt op på resultatet...
Her er mit query - jeg ændrede lidt på tabelstrukturen, primært for at få mere "korrekte" feltnavne :
SELECT stregkode, kundenr,termnr,bilnr,chauf, DAYNAME(starttimestamp) as startday, DAYNAME(sluttimestamp) as endday ,starttimestamp, sluttimestamp, IF ( ((DATEDIFF( sluttimestamp,(IF(DAYOFWEEK(starttimestamp) = 6, DATE_ADD(starttimestamp, INTERVAL 2 day), starttimestamp))) <= 2) ) , TRUE , FALSE ) as regok FROM (SELECT stregkode,kundenr,termnr,bilnr,chauf, MIN(datotid) AS starttimestamp, MAX(datotid) AS sluttimestamp FROM statdata GROUP BY stregkode HAVING SUM(CASE WHEN leveret=0 THEN 1 ELSE 0 END) > 0 AND SUM(CASE WHEN leveret=1 THEN 1 ELSE 0 END) > 0) AS a WHERE stregkode <> '' AND termnr = '010' ORDER BY termnr, bilnr, chauf
I ovenstående får jeg resultatet for en given bruger's scanning statistik - MEN problemet er (vist) at jeg kun får vist resultater hvor at det er den samme scanner som har udført BEGGE skanninger - (alle scanningerne)
Jeg vil gerne have et resultat hvor at mit WHERE termnr = '010' giver et resultat hvor at termnr 010 har lavet det SIDSTE scan (sluttimestamp) - enhver kan/må have lavet de tidligere scanninger.
Kan det lade sig gøre ??
Håber du kan/vil hjælpe med denne :-)
God weekend //Mark
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.