20. december 2005 - 16:28Der er
36 kommentarer og 1 løsning
Hjælp til sortering
Jeg har en lidt tricky sortering, som jeg helst skal have DB til at gøre for mig.
Data kommer fra et intranet system, så jeg har lidt svært ved at vise jer noget.
Men jeg har 2 felter til datoer vedrørende en ordre. Henholdsvis en deadline og en reelt udfyldelsesdato. Når jeg hiver data ud fra DB, så skal den sortere det efter følgende metode:
Ordre der IKKE er udført, med dem tættest på deadline øverst. Ordre der ER udført, med dem der overskred deadline mest øverst. Ordre der endnu ikke har fået en deadline.
Felternes struktur er følgende: Deadline: Navn: r530b. Standardværdi: NULL.
Udførte: Navn: r542a. Standardværdi: NULL.
Begge kan selvfølgelig indeholde en dato samt 0000-00-00, som skal sidestilles med NULL.
Min query ser indtil videre sådan ud:
SELECT o.id as id, o.ordre as ordre, o.rev as rev, o5.r530b, o5.r542a FROM ordre AS o, ordre0 AS o0 LEFT JOIN ordre5 AS o5 ON o0.tilbudsnummer=o5.tilbudsnummer WHERE o0.tilbudsnummer=o.id && (o5.r534=0 || o5.r534 IS NULL) && o5.r534a = 0 && (o5.r554=0 || o5.r554 IS NULL) ORDER BY
Ja, en bøvlet sortering det må du nok sige, den har også drillet mig et pænt stykke tid nu. Men lige for at uddybe.
Vi har altså 2 datoer, en der viser deadline og en til datoen hvor opgaven blev udført. Vi har så en oversigt der viser alle ordre, og det er denne der bl.a. skal kunne sorteres efter de 2 datoer. Så først vi de have: / Ordre hvor deadline er overskredet Ikke udført - Ordre hvor der er 1-4 dage til deadline \ Resten af ordrene der ikke er udført
/ Ordre der blev udført efter deadline Udført - Ordre der blev udført 1-4 dage før deadline \ Resten af ordrene der er udført
Begge skal det være sådan, at ordren der er overskredet med 1 dag kommer før den der har 4 dage til deadline, som igen kommer før ordren der har 20 dage til deadline.
Og, ja desværre kan der godt forkomme ordrer, som er udført men som ikke have en deadline.
Men kigger lige på din sortering, men som jeg lige umiddelbart forstår den, så tror jeg ikke den passer helt.
Synes godt om
Slettet bruger
21. december 2005 - 11:49#3
Mine forslag burde passe til din første beskrivelse, men under forudsætning af at udførte ordrer har en deadline.
I din nye beskrivelse er endnu ikke udførte ordrer uden deadline kommet op før de udførte, hvor de i den oprindelige beskrivelse lå bagefter. Hvis den nye beskrivelse er korrekt, vil det faktisk gøre sorteringen lidt mere simpel.
(o5.r542a IS NULL OR o5.r542a = '0000-00-00') AND (o5.r530b IS NOT NULL AND o5.r530b !='0000-00-00'), o5.r530b ASC, (o5.r542a IS NOT NULL AND o5.r542a != '0000-00-00'), (o5.r530b - o5.r542a) ASC, (o5.r530b IS NULL OR o5.r530b = '0000-00-00')
Ahh, der ligger en del ordre, som ikke har fået opdateret deres data i forhold til disse felter. Jeg laver lige en oprydning, for at se om det hjælper.
Nå, jeg kan få phpmyadmin til at vise forskellige resultater fra samme query, egentlig godt klaret, men tilbage til sorteringen, som jeg mener ikke virker helt perfekt endnu.
Den skal reel sortere dem således:
r542a (deadline) r530b (udført)
NULL/0000-00-00 Dato(Mest overskredne øverst) Dato(tættest på deadline øverst) Dato Dato NULL/0000-00-00 NULL/0000-00-00 NULL/0000-00-00
Linie 2 og 3 skal flettes samme, så de ordre der ingen deadline har med er udførte, bare bliver sorteret efter/sammen med linie 2. Den sidste linie, ved jeg pt. ikke helt præcist hvor de vil have, om den skal være helt øverst eller helt nederst.
Hold da k..., jeg har jo helt glemt datoforskellen. Hvis jeg gerne vil have den til at sortere dem der er mest overskredne øverst, så skal du da have et felt som viser hvor meget det er overskredet.
date530b returner forskellen fra deadline til dags dato.
Hmm, jeg paster lige hele min query. Den er lidt stor men se bort fra alt andet end de felter der har været bragt på bane.
SELECT o5.r542a, o5.r530b, (TO_DAYS(o5.r530b)-TO_DAYS(NOW())) AS date530b, o.id as id, o.ordre as ordre, o.rev as rev, concat(WEEKOFYEAR(o5.r542a), '-', DAYOFWEEK(o5.r542a)-1) AS statik, concat(WEEKOFYEAR(o5.r543a), '-', DAYOFWEEK(o5.r543a)-1) AS optegn, concat(WEEKOFYEAR(o5.r544a), '-', DAYOFWEEK(o5.r544a)-1) AS godkendt, WEEKOFYEAR(o5.r533c) AS lev, o5.r555 AS levtegn, concat(WEEKOFYEAR(o5.r530b), '-', DAYOFWEEK(o5.r530b)-1) AS deadSta, concat(WEEKOFYEAR(o5.r531b), '-', DAYOFWEEK(o5.r531b)-1) AS deadOp, concat(WEEKOFYEAR(o5.r577), '-', DAYOFWEEK(o5.r577)-1) AS nyDeadOp, concat(WEEKOFYEAR(o5.r532b), '-', DAYOFWEEK(o5.r532b)-1) AS deadGod, o0.r1 as projektleder, o0.r9 as kunde, o0.r18 as bygherre, o5.r540a, o5.r541, o5.r541a, o5.r542, o5.r580, o5.r543, o5.r531b, o5.r532b, o5.r539, DAYOFWEEK(o5.r547a)-1 AS godUgedag, WEEK(o5.r547a) AS godUge, o5.r544, o5.r548, o5.r552, o5.r571, o5.r572, o5.r573, o5.r574, o5.r575, o5.r555, o5.r575a, o5.r580a, datediff(o5.r530b, o5.r542a) AS date542a, (TO_DAYS(o5.r531b)-TO_DAYS(o5.r543a)) AS date543a, (TO_DAYS(o5.r532b)-TO_DAYS(o5.r544a)) AS date544a, (TO_DAYS(o5.r531b)-TO_DAYS(NOW())) AS date531b, (TO_DAYS(o5.r532b)-TO_DAYS(NOW())) AS date532b, o5.r543a, o5.r544a FROM ordre AS o, ordre0 AS o0 LEFT JOIN ordre5 AS o5 ON o0.tilbudsnummer=o5.tilbudsnummer WHERE o0.tilbudsnummer=o.id && (o5.r534=0 || o5.r534 IS NULL) && o5.r534a = 0 && (o5.r554=0 || o5.r554 IS NULL) ORDER BY (o5.r542a = '0000-00-00' OR o5.r542a IS NULL) AND (o5.r530b IS NOT NULL OR o5.r530b != '0000-00-00'), date530b DESC
Tester jeg den i phpmyadmin, så er det som om det ignorerer (o5.r542a = '0000-00-00' OR o5.r542a IS NULL). For den første post har en rigtigt dato i feltet, f.eks. 2005-10-03
Burde den ikke tage den med i overvejelserne også?
Synes godt om
Slettet bruger
21. december 2005 - 17:30#12
Der er nødt til at være noget, der styrer rækkefølgen, og de forskellige ordener:
IF( (o5.r542a IS NULL OR o5.r542a = '0000-00-00') AND (o5.r530b IS NOT NULL AND o5.r530b !='0000-00-00'), 1, IF( (o5.r542a IS NOT NULL AND o5.r542a != '0000-00-00'), 2,3 ) ) ASC
Den får dem ud i de tre hovedgrupper. Der er ingen speciel brug for at beregne afstanden fra nu til deadline, for alle ikke-uførte opgaver med en fastsat deadline skal jo bare vises i rækkefølge efter deadline - med ældst først.
Så kommer blokken, der står for sorteringen indenfor de enkelte grupper:
IF( (o5.r542a IS NULL OR o5.r542a = '0000-00-00'), o5.r530b, o5.r530b - o5.r542a ) ASC
Så ialt skulle det være klaret med denne klump:
ORDER BY IF((o5.r542a IS NULL OR o5.r542a = '0000-00-00') AND (o5.r530b IS NOT NULL AND o5.r530b !='0000-00-00'), 1, IF((o5.r542a IS NOT NULL AND o5.r542a != '0000-00-00'),2,3)) ASC, IF((o5.r542a IS NULL OR o5.r542a = '0000-00-00'),o5.r530b, o5.r530b - o5.r542a) ASC
Muligvis skal de if-blokke op i SELECT-delen og have navne, og så bruges med navnene i ORDER BY delen.
Den sorterer fint på ordre som kun har en deadline. Men på ordre som er udført er der enkelte fejl. Her skal den også sortere tidsmæssigt i forhold til deadlinen. Så den der er overskredet med er øverste og så falder de, men der er enkelte ordre som bryder sorteringen.
Grunden til at jeg kan se det lyn hurtigt, skyldes at på oversigten returnerer jeg en datokode (ugenr. - ugedagsnr.) for enten deadlinen eller udførslen. Først vises deadlinen og når opgaven er udført vises udførselsdatoen. Disse bliver også vist ved nogle farvekoder. Rød, gul og grøn alt efter for tæt på deadline ordren er eller blev udført.
Og problemet er at jeg kan se enkelte gule udførte ordre imellem de grønne, og alle gule skal ligge før de grønne, lige som de røde skal ligge før de gule. Det sidste ser dog ud til at virke.
Den første bliver vist i grøn, men nr 2 og 3 bliver vist med gult. Altså er det lavet under 4 dage før deadline, hvilket også kan ses med det første punkt, da der står 2. Den sidste er grøn, altså er den lavet i god tid, helt præcist 203 dage før.
Jeg har taget et screendump af udtrækket fra db, men kan først ligge det op når jeg kommer hjem.
Jeg var selv i går ved at ændre på nogle af IF-sætningerne, men det hjalp ikke meget og så kom "de tomme" pludselig op øverste også, så nej det virkede ikke. Håber du kan finde et eller andet.
Nu kunne jeg pludselig se, hvad det skyldes - håber jeg da.
Det er det første tal, på rækken, der sorteres efter, og af en eller anden grund, bliver det sorteret som en streng i stedet for som et nummer. Det er derfor 2 kommer mellem 198 og 203
Det er den anden if, som skal rettes til så:
IF((o5.r542a IS NULL OR o5.r542a = '0000-00-00'),o5.r530b, o5.r530b - o5.r542a) ASC
Bagefter skal den se således ud:
CAST(IF((o5.r542a IS NULL OR o5.r542a = '0000-00-00'),o5.r530b, o5.r530b - o5.r542a) AS SIGNED) ASC
Yes, nu har jeg gjort så den eneste sortering jeg har er din CAST, og så ser det ud til at virke, næsten. Der er lige nogle enkelte 0000-00-00, som kommer ind imellem reelt udfyldte datoer.
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.