28. april 2005 - 10:23Der er
64 kommentarer og 1 løsning
Sortering af MySQL output med "tomme" datoer sidst
Ja, jeg har oprettet dette spørgsmål før, og troede også jeg havde fået det løst, men nu kan jeg se at det ikke virker alligevel. Om det er fordi jeg har slettet noget eller hvorfor ved jeg ikke, men jeg bliver derfor nødtil at oprette spørgsmålet igen.
Jeg har et output fra MySQL, bl.a. med datooplysninger om ordre/tilbud, det er dog ikke alle disse som har en "rigtig" dato, den kan også være NULL eller 0000-00-00. Jeg skal så have dette output sorteret så dem med "rigtige" datoer kommer først i stigende orden, og derefter alle de "forkerte" datoer.
Jeg har nu selv fået det til at gøre det lidt, gad vide hvad forskellen er i forhold til det jeg ikke kunne få til at virke, for jeg synes ikke lige der nogle. Nå men koden:
Mit problem er nu, at jeg gerne skulle have den gjort specifik, så alt efter om der fra brugeren side bliver sorteret på dato, projektleder e.l. så skal den sortere på samme måde på den valgte og ikke kun ud fra datoen.
$query = "SELECT o.id as id, o.ordre as ordre, o.rev as rev, YEAR(o5.r533c) as levaar, WEEKOFYEAR(o5.r533c) as levuge, o0.r1 as projektleder, o0.r9 as kunde, o0.r18 as bygherre, o5.r541, o5.r541a, o5.r542, o5.r546, o5.r543, o5.r547, o5.r544, o5.r548, o5.r552, WEEKOFYEAR(o5.r555) AS tegnuge, YEAR(o5.r555) AS tegnaar, o5.r572 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 $search ORDER BY $sort, o.id ASC
$sort er så det som brugeren vælger, eller standard første gang de kommer ind på siden, og det fungere perfekt.
Det jeg skal have tilføjet er en funktionalitet, som gøre at tomme felter sorteres sidst, hvilket jeg så har fået løst ud.
MEN, det skal der jo være... ;-)
jeg skal have sorteret den i flere niveauer. F.eks. vælger brugeren at sortere efter projektleder, er der tilfældigvis en record, som ingen projektleder har, skal den lægges sidst, derudover skal den i næste niveau sortere efter dato, og igen er der datofelter som er tomme skal de også komme sidst, inden for denne projektleder.
Hvis det er til at forstå, jeg tror lige jeg vil prøve at illustrere det.
Jeg er nået dertil, hvor den sortere enten på projektleder eller dato, alt efter valget, og ligger de tomme sidst. Nu skal jeg bare lige have fundet ud af at kombinere sorteringen ved projektleder. Jeg gør det på denne måde, men kan det ikke gøres smartere, da jeg egentlig vil få en 5-6 if-sætninger, kun til at tjekke sorteringen på.
SELECT o.id as id, o.ordre as ordre, o.rev as rev, YEAR(o5.r533c) as levaar, WEEKOFYEAR(o5.r533c) as levuge, o0.r1 as projektleder, o0.r9 as kunde, o0.r18 as bygherre, o5.r541, o5.r541a, o5.r542, o5.r546, o5.r543, UNIX_TIMESTAMP(o5.r543) as unix, o5.r547, o5.r544, o5.r548, o5.r552, WEEKOFYEAR(o5.r555) AS tegnuge, YEAR(o5.r555) AS tegnaar, o5.r572 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 $search ORDER BY IF(unix = 0,1,0),$sort, o.id ASC
hov, jeg havde lige lavet en lille fejl, som var skyld i at intet blev vist. Den sorterer sådan set godt nok, men kun på felt nr. 534. Så det skal vel ændres til projektleder, levuge og levaar som kombineres, og til sidste ordreid
Jo, der er mange, næsten alle sammen, men af relevens nok kun r553c, men jeg henter henholdvis årstallet og ugenummeret ud af datoen, for brugeren vil have det vist på den måde. Det er også den som er på "screendumpet" eks. 7-05 -> uge 7 i år 2005
bl.a.? Det er de felter som kan indeholde NULL eller 0000-00-00 vi skal lave til unix og så sortere via: IF((o5.r533c = 0 || o5.r533c IS NULL),1,0),$sort, o.id ASC
Ja, jeg ved ikke helt om det virker, nok fordi jeg får lavet noget rod i php-koden, som hiver data ud. Jeg poster lige min kode indtil videre, hvor jeg pt. ikke for returneret noget som helst. Der er en masse udkommenteret kode, som er fra den jeg via php prøvede at ændre sorteringen.
Jeg vil meget gerne hjælpe, men ville meget gerne se dine data live, hvis det er muligt! Du kan evt prøve at fange mig på MSN: jakobdo (-at-) hotmail (-dot-) com
Ja, hvis jeg på en eller anden måde kunne se hvordan du har dine data gemt i dag! Det er svært at se ud fra din sql, som er meget større end hvad jeg plejer at rode med! :o)
Selve data, kan/må jeg ikke vise dig, men opbygningen kan jeg da prøve at forklare. Det skal dog siges, at det ikke er mig som har opbygget db'en i tidernes morgen, og derfor heller ikke har det direkte fra "opfinderens" mund, hvorfor han har valgt at gøre på denne måde, men kun hvad jeg sådan har kunnet gætte mig til.
Men selve datastrukturen, er sådan set spredt over er 7 tabeller, i dette tilfælde ordre og ordre0-5, men det er også sådan for et tilbud. Ordre holder styr på id kontra ordrenr, oprettelsesdato, status og lignede ting. Ordre0 - 5 indeholder så data fra alle felter på ordren. Alle felter er nummeret, hvilket sikkert også har skabt tabelopbygningen, da alle 0-100 ligger i ordre0, alle 101-200 i ordre1 osv...
Det er også derfor jeg joiner, for at få samlet de oplysninger i et resultat, som jeg nu en gang skal bruge.
$search i queryen er en parameter, hvis brugeren vil søge efter f.eks. en bestemt oprettelsesdato, $sort er så sorteringen, som brugeren kan vælge ved at klikke på nogle kolonneoverskrifter, og det er altså så her, de godt vil have, at ordre som har en tom dato (bl.a. kunne det være den ikke være udfyldt endnu) bliver sorteret til sidst. Det fik vi sådan set også til at virker, MEN, for det skal der jo være ;-), de vil gerne have, at hvis de vælger at sortere på f.eks. projektleder, så skal der inden for hver projektleder soreteres efter dato og igen med de tomme til sidst.
Selvfølgelig kan jeg sortere på datofelter, men så kommer de tomme jo først. Den som du nævner, bliver efter query via dit script ændret, så de tomme kommer til sidst. Det virker altså bare ikke helt når jeg gerne vil sortere f.eks. på projektleder.
SELECT o.id as id, o.ordre as ordre, o.rev as rev, YEAR(o5.r533c) as levaar, WEEKOFYEAR(o5.r533c) as levuge, o0.r1 as projektleder, o0.r9 as kunde, o0.r18 as bygherre, o5.r541, o5.r541a, o5.r542, o5.r546, o5.r543, UNIX_TIMESTAMP(o5.r543) as unix, o5.r547, o5.r544, o5.r548, o5.r552, WEEKOFYEAR(o5.r555) AS tegnuge, YEAR(o5.r555) AS tegnaar, o5.r572, o5.r573, o5.r574, o5.r575 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 ORDER BY $sort, IF((o5.r533c = 0 || o5.r533c IS NULL || o5.r555 = 0 || o5.r555 IS NULL),1,0), o.id ASC
Men hov, kan det være fordi jeg stadig i scriptet splittet det andre på dato. Det må jeg lige tjekke ud.
Ahhh, jeg har nogle enkelte andre felter som også kan være tomme, så de skal nok også have den på, men jeg lader lige spørgsmålet stå åbent, da der faktisk er mange steder jeg skal have tilpasset til denne sortering. Så der kommer nok nogle problemer af en eller naden form.
De skulle sådan set kunne være begge dele. NULL når der endnu ikke er skrevet til dem, og eventuelt en tom streng også. Men jeg har prøvet med begge muligheder, og synes ikke rigtigt den fanger dem.
Jeg har nu fået løst problemet med bygherre, men det er ikke en god løsning, så hvis du har en anden og bedre, så kom endelig med det.
Mit problem var, at jeg på et link via onClick, sætte sorteringen. Og det jeg gerne ville have, var at den så sådanne ud: onClick="return setSort('IF((o0.r18 = "")1,0)');"
Jeg kan godt escape "", så siden kan loades under problemer, men så forstår queryen, den ikke for pludselig, står der \"\" i den, og det er den ikke glad for.
Min løsning nu er, at jeg sætter sorteringen lig bygherre, og så i script når siden loadesm tjekke på om setSort er lig bygherre. er den det laver jeg querydelen som jeg vil have den, og det virker.
Jeg forstår ikke helt dit spørgsmål her til sidst. Mener du en måde at lave forskellige sorts?
Hvis ja, så kunne du evt bruge:
switch($_POST['sort']) { case "bygherre": $sort = "IF((o0.r18 = ''),1,0), IF((o5.r533c = 0 || o5.r533c IS NULL),1,0), o.id ASC"; break; case "dato": $sort = "IF((o5.r533c = 0 || o5.r533c IS NULL || o5.r555 = 0 || o5.r555 IS NULL),1,0), o.id ASC"; break; default: $sort "et eller andet som bare er standard";
Du skal forestille dig kolonneoverskrifterne i links, som sætter sorteringen. Klikker brugeren på "bygherre", så skal query-output sorteres, så først kommer de ordre som har en bygherre, derefter dem som ikke har. Er bygherren ens (lige meget om den er udfyldt eller tom), skal den efterfølgende sortere på en leveringsdato.
Det har jeg løst, men kunne godt tænke mig en løsning, som lignede originalkoden mere. Oprindelig bliver $_POST['sort'] ved onClick sat lig med de forskellige $sort varibler.
Men jeg er løbet på endnu et problem, det mærkelige er at når jeg går videre, til næste kolonne, hvor datamuligherne er 1, 0 og NULL, så kan jeg odt få den til at sortere 1'erne først, men den vil sgu ikke sortere på datoen, selvom koden er ens...?
Hvis jeg skralder queryen til kun at vise id, r542 og r533c, så virker det som om der er en sortering efter id, som overrider den anden IF-sætning, kan det passe, det burde da ikke ske?
Hmm, jeg ser nu at bygherre heller ikke virker optimalt. Godt nok deles sorteringen op i 2. Dem med en bygherre og dem uden, men dem med en bygherre, må eventuelt gerne blive sorteret alfabetisk først, med i det mindste skal den sortere dem på leveringsdato og ikke ordre.id, som den ellers gør.
Jeg har ikke forsøgt med breaks, kun if-sætninger. Men de fanger godt nok, det er selve $sort der ikke kører som den skal, så jeg tror ikke break vil gøre nogen sønderlig forskel, men jeg vil da prøve på mandag.
Breaks, gør ikke noget ved selve din søgning. Den ændre bare måden at stille det op på! (og så er det pænere end if, elseif osv...) Men jeg tror snart jeg giver op hvordan dine sql'er skal laves! Jeg er slet ikke med på hvordan din database struktur er! Jeg tror desværre jeg giver op, men jeg håber du har fået lidt ideer du kan bruge til en brugbar løsning.
Hvis det bare selve strukturen du er i tvivl om, så er faktisk ikke så mærkelig, og så lidt alligevel. Langt de fleste felter er som udgangspunkt "Tinytext". Grunden hertil må stå hen i det uvisse, men kan måske skyldes, at den første udvikler ikke havde fået en ordentlig info. om data som skulle gemmes.
Nå men jeg tager kun de felter som skal bruges i forespørgelsen, da det ville bliver for uoverskueligt andet.
Struktur: Ordre ----- felt - datatype - nulværdi - standardværdi id - mediumint(8) - nej - ordre - do - nej - 0 rev - smallint(5) - nej - 0
ordre0: tilbudsnummer - mediumint(8) - ja - NULL r9 - tinytext - ja - NULL r1 - tinytext - ja - NULL r18 - tinytext - ja - NULL
ordre5: r533c - date - nej - 0000-00-00 r534 - tinytext - ja - NULL r534a - tinytext - nej r541 - tinytext - ja - NULL r541a - tinytext - ja - NULL r542 - tinytext - ja - NULL r543 - tinytext - ja - NULL r544 - tinytext - ja - NULL r546 - tinytext - ja - NULL r547 - tinytext - ja - NULL r548 - tinytext - ja - NULL r552 - tinytext - ja - NULL r555 - tinytext - ja - NULL r572 - tinytext - ja - NULL r573 - tinytext - ja - NULL r574 - tinytext - ja - NULL r575 - tinytext - ja - NULL
Håber det kan hjælpe lidt, og så komemr jeg lige med et indlæg over hvilke felter, som jeg gerne vil have sortere specielt.
Standard: Når brugeren lige kommer ind på siden, skal der sorteres efter r533c, så den førstkommende dato står øverst, og eventuelle ordre med datoer med 0000-00-00 står sidst. Er der ordre med samme dato, skal de sorteres stigende efter id.
Ordrenr: Ja, den er ikek det store problem, skal kun sortere på ordreid, og der er ingen tomme.
Leveringstid: Lige som standard.
Projektleder: Skal sortere på r1, som faktisk er deres id-nummer, igen ordre uden projektleder til sidst. Når flere ordre, har samme projektleder, skal der sorteres efter standard, altså først r533 og så id.
Kunde: Sortering på r9, igen med tomme til sidst, efterfølgende standard.
Bygherre: Sortering på r18, igen med tomme til sidst, efterfølgende standard.
Resten vil næsten køre over samme princip.
Ordrebekræftelse sendt: Sortering på r572, igen med tomme til sidst, efterfølgende standard.
Special stål bestilt: Sortering på r541, først records med JA, så NEJ, og til sidst tomme. Efterfølgende igen standard.
Klar til statik: Sortering på r542, igen med tomme til sidst, efterfølgende standard.
Statik regnet: Sortering på r546, igen med tomme til sidst, efterfølgende standard.
Klar til optegnelse: Sortering på r543, igen med tomme til sidst, efterfølgende standard.
Sendt til godkendelse: Sortering på r547, igen med tomme til sidst, efterfølgende standard.
Godkendt af kunde: Sortering på r544, igen med tomme til sidst, efterfølgende standard.
Ordrebekræftelse retur: Sortering på r548, igen med tomme til sidst, efterfølgende standard.
Kreditvurdering OK: Sortering på r552, igen med tomme til sidst, efterfølgende standard.
Leveringsuge på tegn.sæt: Sortering på r555, igen med tomme til sidst, efterfølgende standard.
Intern statik / produktionstegning / produktion: Denne bliver måske noget voldsom, da den samlet 3 felter i én kolonne. Statik er felt r373, produktionstegning er r374 og produktion er r375, og de skal sorteres på følgende måde: ------------- | S | T | P | ------------- | x | x | x | ------------- | | x | x | ------------- | x | x | | ------------- | x | | x | ------------- | | | x | ------------- | | x | | ------------- | x | | | ------------- | | | | ------------- x er dem som indeholder data.
Igen efterfølgende, når der er ordre, som er ens, skal de sorteres som standard, hvis det er muligt.
Hov, jeg lavede lige nogle fejl. Først "Special stål", der skal tjekkes på både felt r541 og r541a,
er r541 = 1 og r541a = 0, er der bestilt stål. Er det modsat er der ikke bestilt stål. Er ingen af dem udfyldt, ja, så har brugeren endnu ikke fortaget valget.
Den anden fejl er ved de 3 interne felter. Der skrev jeg r3xx, men det skulle have været r5xx.
Hov havde slet ikke set du havde lagt et indlæg, jeg tester den lige.
Intern er også lidt tricky, da der er 3 felter, som bliver vist samlet. Der er der bestemt, at når alle 3 er sat skal de sorteres øverste, dernæst når 2 er sat, og til sidst kun 1 er sat.
Jeg testede lige med bygherre, og godt nok måtte jeg ændre IF((o0.r18 = '' || o0.r18 IS NULL) ,1,0), ASC til IF((o0.r18 = '' || o0.r18 IS NULL) ,1,0), o0.r18 ASC for ikke at få en sql-fejl, men så kommer alle bygherrene alfabetisk, og med de tomme til sidst. Fjernede jeg ASC i din, bliver de ikke sorteret alfabetisk.
Jeg løber lige igennem og se om det virker for den andre også, plus de lidt mere specielle sorteringer.
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.