23. juli 2003 - 22:44Der er
74 kommentarer og 1 løsning
SQl sortering af resultat part2
Jeg havde i et tidligere spm, spurgt omkring at få sorteret et resultat fra mssql serveren, se evt.: http://www.eksperten.dk/spm/378404 , var desværre lidt for hurtig på aftrækkeren med at acceptere
Jeg har et forum, hvor at der vises indlæg ala "snitz forum", mit problem er at jeg skal have indlæg der er besvaret til at ligge øverst. Oprindelige indlæg har reference = 0, mens besvarelser har reference = (id på oprindeligt indlæg). Mit problem er at det skal sorteres efter id fra alle indlæg (for at besvarede indlæg ryger øverst), men kun de indlæg der har reference = 0 skal vises.
Et forsøg på at opnå det har jeg lavet en ekstra tabel der indeholder alle id´er og jeg prøver så at bruge den til sortering, men det kan jeg ikke helt få den til.
Min sql er: Select * From topic as a LEFT JOIN topicsort as b ON b.idsort=a.id WHERE a.forumid ='" & Request.Querystring("fid") & "' AND a.reference = 0 AND b.idsort <> 0 Order by b.id4 DESC
topic er den tabel der indeholder alle indlæggene (og besvarelser), mens topicsort indeholder id fra alle indlæg
select * from ( select topic1.*, count(topic2) from topic topic1, topic topic2 where topic1.id += topic2.idsort group by topic1.*) order by count(topic2)
Sætningen virker med stor sandsynlighed ikke, men prøv. Muligvis skal += være =+.
Du behøver ingen ekstra tabeller - bare et korrekt SQL-statement. Jeg skal lige forstå dig ret. Du har en tabel med tråde, og du har en tabel med besvarelser, der referer til den pågældende tråds id, ik'?
Niks, det hele ligger i samme tabel, jeg tænkte at det ikke ville gøre nogen forskel umiddelbart, men det kan da godt være jeg tager fejl. Mit layout for tabellen der indeholder tråde er:
id - auto, identity forumid - til reference af hvilket forum posten tilhører reference - er 0 hvis nyt emne, er (id til oprindelig post), hvis besvarelse dato klokken navn overskrift tekst
Den anden tabel jeg lavede (topicsort), var kun som et forsøg på at løse mit problem
Det som er mit hoved brud er at jeg siger jeg kun vil have de poster der indeholder reference = , men jeg vil godt have sorteret efter alle poster der er i tebellen ligemeget hvad reference er, og det er jo lidt modsigende. En helt grundlæggende udgave af select ville være:
Select * FROM topic WHERE forumid ='" & Request.Querystring("fid") & "' AND reference = 0 ORDER by id DESC;
Men dette gør jo at den kun sortere efter de poster der har reference = 0
Nu er det ikke for at lyde hellig, men det er meget dårlig databasestruktur at blande de forskellige kategorier sammen på den måde. Hvis du har mod på at redesigne det, så gør det således:
Tabel (Spm) =========== - SpmID - Dato - Overskrift - Tekst - BrugerID
Tabel (Svar) ============ - SvarID - Dato - Tekst - BrugerID - SpmID
Her refererer "SpmID" i tabellen "Svar" til "SpmID" i tabellen "Spm".
Ikke NULL, men 0. Feltet er reference, og det fungere på den måde at hvis feltet har værdien 0 så er det et nyt indlæg. Har feltet en værdi over 0 f.eks. 1, så er det en besvarelse. Den værdi feltet har når det er en besvarelse svarer til id på det indlæg som man har besvaret.
Måske er det nemmere hvis jeg liger viser min insertkoder:
Netro: Jeg er altid oplagt på at gøre det bedre, og det der gør alligevel ikke den helt store forskel. Men hvordan får jeg den så til at sortere på den rigtige måde efter id´er? Så skal den vel på en eller anden måde sammenligne de 2 tabeller....
SELECT * FROM ( SELECT topic1.*, count(topic2.*) AS topic_count FROM topic topic1 LEFT JOIN topic topic2 ON topic1.id = topic2.reference GROUP BY topic1.*) ORDER BY topic_count DESC
darkstar -> Du kan da ikke ved dine fulde fem påstå, at det er god databasestruktur at sammenblande data på den måde. Angiver du også en kundes fulde navn i en enkelt kolonne? Havde du tænkt dig, at feltet overskrift kun skulle udfyldes, når den pågældende post er et spørgsmål?
korger+netro>>> Netros forslag er en rigtig dårlig idé.
Hvis der er tale om indlæg, hvor data stort set er de samme, er det oplagt at hælde dem i den samme tabel. Det eneste som jeg vil opfordre dig til er at bruge NULL i stedet for 0 når det gælder nye indlæg. Det andet er noget skidt.
netro>>> Du har skrevet to tabeller som er identiske, pånær en overskrift og en reference. Ja. jeg ville med glæde anbringe det hele i en tabel.
1) Fordi at folk nogle gange gerne vil kunne sætte en overskrift på deres svar. Som f.eks. i Computerworlds forum. 2) Fordi at din struktur kræver noget særlig kode som skal tage hensyn til at den træstruktur som man skal behandle har et særligt 1. niveau som ligegr i en anden tabel. 3) Fordi at man - i særlige tilfælde - måske gerne vil kunne hægte et indlæg som startede i toppen på en eksisterende tråd.
Specielt nummer 2 er en killer. Anbringer man data i to forskellige tabeller vokser den kode som skal behandle dem med 100% (+/-).
Netro jeg prøvede din kode, og må indrømme jeg forstår den ikke helt... Men jeg fik denne fejl: Microsoft OLE DB Provider for ODBC Drivers (0x80040E14) [Microsoft][ODBC SQL Server Driver][SQL Server]Line 1: Incorrect syntax near '*'. /forum/topics.asp, line 130
Linie 130 er: Set rs = objConn.Execute(strSQL) Men det er jo den den altid brokker sig over ved sql fejl
netro>>> Lad os antage at du har en eller anden drønsmart måde at gøre det på, som er meget nemmere end hvis det hele ligger i en tabel.
Så kan jeg bevise at jeg kan gøre det ligeså smart med blot een tabel ved at lave to views som indeholder nøjagtig de samme data som der ellers ville være i dine tabeller. Views kan indskrives direkte i SQL-sætninger og hvis de er trivielle - hvilket de er, koster de ikke ekstra i performance.
View 1: select SpmID, Dato, Overskrift, Tekst, BrugerID from topic
View 2: select SvarID, Dato, Tekst, BrugerID, SpmID from topic
Hvis du stadigvæk ikke er overbevist, så skriv den SQL-forespørgsel til dine to tabeller, som du mener jeg ikke kan lave ligesågodt med een tabel.
SELECT * FROM ( SELECT topic1.*, count(topic2.*) AS topic_count FROM topic topic1 LEFT JOIN topic topic2 ON topic1.id = topic2.reference GROUP BY topic1.*) ORDER BY topic_count DESC
Det er topic1.* der giver fejlen. Du skal indsætte alle topic1's felter, altså
...det er faktisk ved GROUP BY at jeg tror at det går galt. Den først forekomst burde virke, men skift hellere begge to ud - så er det mere konsistent.
netro>>> som jeg skrev: "Hvis du stadigvæk ikke er overbevist, så skriv den SQL-forespørgsel til dine to tabeller, som du mener jeg ikke kan lave ligesågodt med een tabel.".
Microsoft OLE DB Provider for ODBC Drivers (0x80040E14) [Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near the keyword 'ORDER'.
Og koden er nu:
SELECT * FROM (SELECT topic1.id, topic1.forumid, topic1.reference, topic1.dato, topic1.klokken, topic1.navn, topic1.overskrift, topic1.tekst, count(topic2.id) AS topic_count FROM topic topic1 LEFT JOIN topic topic2 ON topic1.id = topic2.reference GROUP BY topic1.id, topic1.forumid, topic1.reference, topic1.dato, topic1.klokken, topic1.navn, topic1.overskrift, topic1.tekst) ORDER BY topic_count DESC
Microsoft OLE DB Provider for ODBC Drivers (0x80040E14) [Microsoft][ODBC SQL Server Driver][SQL Server]The text, ntext, and image data types cannot be used in a GROUP BY clause.
Kolonnen "tekst" er af typen ntext (For at kunne få plads til lange indlæg)
Ja, den smuttede, men du kan formentlig tænke dig til det sidste. Nu vil jeg sige tak for diskusionen og lade være med at spamme krogers spørgsmål yderligere. Vi bliver alligevel aldrig enige om dette.
netro>>> jeg kan ikke tænke mig til "det sidste". Faktisk aner jeg ikke hvad du skriver om. Jeg kan *bevise* at du ikke kan noget som jeg ikke kan. Derfor er det lidt svært at "tænke sig til det sidste".
Jeg prøver. Nu har jeg også fået en del at arbejde ud fra. Jeg siger mange tak for hjælpen, du får pointene får den store hjælp det er jeg virkelig glad for.
En hver forespørgsel du måtte finde på, kan omskrives ved at bruge følgende regler:
1. Omskriv feltnavnene så de passer ("SpmID" bliver til "id" hvis det er Spm-tabellen der refereres til og så videre). 2. Omskriv "Spm" til "topic Spm". 3. Hægt følgende betingelser på: "Spm.reference = 0" og "Svar.reference <> 0".
Jeg glemte punkt tre i mine eksempler igår, men de er lige til at hægte på.
...så din sætning fra igår bliver til
Select s.id From topic s Left Join topic v On s.id = v.reference Where v.BrugerID = 123 and s.reference = 0 and v.reference <> 0 Group By s.id;
Jeg venter stadigvæk på den SQL-sætning som du påstår der findes, som man ikke kan formulere med een tabel.
For at fortsætte ud af arrogancesporet: jeg har arbejdet med SQL siden 1995 og fik 13 i skriftlig eksamen i databaser på Universitetet.
"Jeg venter stadigvæk på den SQL-sætning som du påstår der findes, som man ikke kan formulere med een tabel."
Inden du selvforelsker dig helt, så prøv lige at læse tråden én gang til og vis mig stedet, hvor jeg påstår ovenstående.
Det oprindelige spørgsmål er, om det er godt eller dårligt databasedesign at hælde det hele ned i samme tabel. Jeg mener stadig, det er bedre at opdele data, som jeg illustrerede. Men du plaprer løs og forsøger at overbevise mig om, du kan gøre det samme som mig med én tabel. Og hvor vil du hen med det? Jeg synes, det ville være mere relevant, hvis du kunne overbevise mig om, at din løsning er så meget bedre, at du kan tillade dig at betegne min som direkte "dårlig". Du må gerne citere fra dine før omtalte bøger, hvis du lyster.
Jvf. tabellerne fra 24/07-2003 00:03:15), laver jeg et udtræk af de spm., hvor en bruger deltager med en join:
Select s.SpmID From Spm s Left Join Svar v On s.SpmID = v.SpmID Where v.BrugerID = 123 Group By s.SpmID;
Jeg har ikke så meget at trække i land. Jeg kunne blot godt tænke mig at se, hvordan du laver det tilsvarende udtræk med brug af én SQL-sætning i en database, der ikke understøtter subselects og views.
...og hvad angår om det er godt eller dårligt databasedesign iøvrigt, mener jeg ikke at det er en diskussion vi kan tage her. Jeg mener at een tabel er det rigtige, men for min skyld skal du være velkommen til at putte hvert spørgsmål i en separat tabel.
Du kan eventuelt tage et kig på mine argumenter imod dit design og starte med at svare på dem.
Havde ikke set det svar - men ja, det var det, jeg ville vide. Generelt synes jeg, man bør undgå for mange tomme felter. Derudover synes jeg rent designmæssigt, det er pænere at adskille data. Hvis svarene også kræver en overskrift, er problemet ikke væsentligt. Men lad os sige, at brugeren der opretter spørgsmålet også skulle angive navn, adresse og e-mail. Ville du så stadig hælde det ned i samme tabel, hvor alle svar-felterne efterlades tomme i disse kolonner?
netro>>> Jamen så går jeg ud fra at du er overbevist nu.
Hvad angår databasedesign så er det jo en afvejning af "renhed" og brugervenlighed overfor programmøren. Et enkelt felt som man blot undlader at bruge synes jeg bestemt ikke er grund nok til at dele ind i to tabeller. Konsekvensen er jo at man skal skrive en pæn bunke kode som tager højde for den nye tabel, som man har lavet. I dette tilfælde er det specielt grelt fordi at den ene tabel vil tjene til at holde øverste niveau i en skov, hvor de næste niveauer ligger i en separat tabel. Det kommer til at give noget temmeligt grim kode.
Desuden er to tabeller der ligner hinanden så meget altså også tegn på dårligt databasedesign.
Hvis der var nogle data som dem du beskriver (det er bare ikke noget godt eksempel i denne kontekst, da der jo er et BrugerID, som man må antage bruges til det samme), så er jeg enig med dig - det ville ikke blive pænt. Til gengæld er det altså heller ikke pænt at putte navn, adresse og email på de enkelte indlæg - med mindre at brugerne af systemet har en særlig interesse i at vide præcis hvilken mailadresse den enkelte spørgsmål-stiller havde da han stillede spørgsmålet.... :-|
Så til din kommentar om godt eller dårligt design ville jeg nok sige at det pæneste ville være at lave en tabel til brugere og en tabel til spørgsmål/svar - ligesom kroger har gjort det nu.
Hvis det ikek var email, navn og adresse, men måske nogle oplysninger som havde noget direkte med spørgsmålet at gøre, f. eks. hvornår det skulle besvares, hvilken kategori det tilhørte og den slags, så ville jeg begynde at overveje at hælde dem i en separat tabel.
Jeg havde faktisk ikke overvejet muligheden med at joine tabellen med sig selv, så ja - det er indlysende, at det giver de samme muligheder for udtræk. Det var et lidt dårligt eksempel, jeg kom med. For selvfølgelig vil man hælde brugerrelaterede oplysninger i tabellen med brugere. Et bedre eksempel ville f.eks. være kategori og relevans for spørgsmålet. Men jeg kunne dog stadig godt tænke mig at se uddrag fra de bøger, du hentyder til, da denne form for design så vidt jeg husker ikke er i overensstemmelse med de fire normaliseringstrin. Jeg har arbjedet med SQL og databaser i 5 år og er altid blevet "opdraget" til at opdele data på en så logisk og overskuelig struktur som muligt. Derfor interessere det mig, hvis du kan fremvise noget konkret dokumentation for dine egen udsagn. Ikke at det nødvendigvis vil ændre min opfattelse og personlige overbevisning, men det vil give mig lidt tankestof.
Lige for at strække den darkstar vil jeg høre om du kan hjælpe mig med en sidste ting, du kan evt få nogle xtra point hvis det er. Jeg har nu nået så langt at den nu sortere efter dem der har flest besvarelser, og det er jo ikke helt korrekt. Og når man laver et nyt indlæg ryger det helt nederst, og det er jo absolut heller ikke meningen. Efter jeg har været begravet i diverse bøger og artikler har jeg stadig ikke fået kringelt den, mit problem er nok at jeg ikke helt forstår koden, så hvis du evt. kunne forklare lidt om hvad der sker, kunne jeg selv arbejde videre med den selv.
Den kode jeg er endt med indtil videre er:
SELECT topic1.id, topic1.forumid, topic1.reference, topic1.dato, topic1.klokken, topic1.navn, topic1.overskrift, count(topic2.id) AS topic_count FROM musik_topic topic1 LEFT JOIN musik_topic topic2 ON topic1.id = topic2.reference WHERE topic1.forumid ='" & Request.Querystring("fid") & "' AND topic1.reference = 0 GROUP BY topic1.id, topic1.forumid, topic1.reference, topic1.dato, topic1.klokken, topic1.navn, topic1.overskrift ORDER BY topic_count DESC;
Det er specielt GROUP BY og din LEFT JOIN jeg ikke helt forstår.
Jeg fik selv klaret den, dog på en anden måde. Hvis det ellers interressere kan jeg lige hvise hvad jeg har gjort.
Jeg oprettede et xtra felt i tabellen der hedder sortering.
Når der oprettes et nyt indlæg smides indlæggets id i feltet sortering. Når der laves en besvarelse opdatere den det originale indlægs sortering med besvarelsens id. Og ved visnig er det "order by sortering desc"
Så simpelt, og alligevel skulle det tage 400 år før jeg kom i tanke om det
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.