20. september 2005 - 08:41Der er
24 kommentarer og 2 løsninger
Problemer med flere joins i en query
Jeg skal hinte noget data fra 3 tabeller, men jeg kan ikke helt gennemskue hvordan jeg skal lave queryen.
Jeg kan godt få en join til at virke med 2 tabeller, så det er sikkert ikke så meget anderledes med 3 tabeller. Men jeg kan i hvertfald ikke få det til at virke :)
Jeg har lavet følgende query: SELECT cc_vagter.*, medarbejdere.*, bemaerkninger.* FROM cc_vagter LEFT JOIN bemaerkninger ON (cc_vagter.dato = bemaerkninger.dato AND cc_vagter.init = bemaerkninger.init) LEFT JOIN medarbejdere ON medarbejdere.init = cc_vagter.init WHERE cc_vagter.dato >= #9/20/2005# AND cc_vagter.init='tho'
For at gøre det enkelt, vil jeg bare hente alle data fra tabellerne cc_vagter, medarbejdere og bemaerkninger.
Det du siger er, at du vil have alt fra cc_vagter, og dernæst alt fra bemaerkninger som relaterer til cc_vagter. Du kræver at både dato og init skal stemme overens.
Undersøg først om denne del at queryen giver hvad du forventede:
SELECT cc_vagter.*, bemaerkninger.* FROM cc_vagter LEFT JOIN bemaerkninger ON (cc_vagter.dato = bemaerkninger.dato AND cc_vagter.init = bemaerkninger.init) WHERE cc_vagter.dato >= #9/20/2005# AND cc_vagter.init='tho'
Derefter JOIN'er du med medarbejdere, hvor du vil have alt som relaterer til cc_vagter idet init skal stemme overens.
Det jeg spekulerer på er om du har overvejet det med dato. Hvis klokkeslættet ikke stemmer overens ned tl millisekunder, så kommer der ikke noget med fra bemaerkninger.
Hvis der kan knyttes et antal bemærkninger til en post i cc_vagter, så ville den korrekte måde at joine på være at du bruger primærnøglen fra cc_vagter, og noterer den i en kolonne i bemærkninger. Er det init der er primærnøglen?
Det du får nu skulle gerne være ALLE poster fra cc_vagter, så er problemet at der ikke kommer "nok" med fra de andre to tabeller?
Desuden vil posterne fra cc_vagter godt kunne komme flere gange, hvis der er flere bemaerkninger eller flere medarbejdere der matcher. Sådan vil det være, og sådan skal det være.
jeg sidder lige og finder ud af at jeg har dummet mig lidt. Den query jeg skrev har jeg brugt på en anden side, og kan slet ikke bruges på den forside jeg skal bruge :)
Det script jeg laver, skal vise dagens vagter for nogle personer.
Jeg bruger pt. denne query til at finde hvilke personer som har vagt i dag.
SELECT cc_vagter.init AS c_init, medarbejdere.* FROM cc_vagter LEFT JOIN medarbejdere ON (cc_vagter.init = medarbejdere.init AND trin = 1 AND dato = #"&dato&"#)
Det virker fint.
I tabellen Bemaerkninger ligger de bemærkninger som folk evt. har skrevet hvis de har byttet vagt osv. Bemaerkninger har følgende felter: init, dato, bemaerkning.
Det er meningen at den query, skal kunne hente en eventuel bemærkning for alle personerne der har vagt i dag. Der er kun 1 bemærkning pr. person pr. dag
Jeg håber at jeg har forklaret mig bedre end i morges. For der var jeg da helt galt på den :)
Der er kun 1 bemærkning pr. person pr. dag, siger du, men bemærkningen er knyttet til cc_vagter. Og der kan åbenbart være flere personer på hver vagt, så der er da noget galt.
Men anyhow, er dit problem løst, eller hvad består det i nu?
init | navn .... __________________ tho | Thomas ..... mpe | Mads ..... tin | Tina .....
[bemaerkninger] dato | init | bemaerkning ___________________________________ 20/09/2005 | tho | håber det virker
På forsiden skal alle vagter for d. 20 vises. I stedet for initialer, skal hele navnet stå. Hvis der er nogen bemærkninger for den person for den dag, skal det også vises
Jeg håber at jeg har forklaret mig godt nok, så du kan hjælpe mig med at lave den sql sætning :)
Umiddelbart Left Joiner du forkert i forhold til det du ønsker. Prøv med:
SELECT cc_vagter.*, medarbejdere.*, bemaerkninger.* FROM Medarbejdere LEFT JOIN cc_vagter ON medarbejdere.init = cc_vagter.init LEFT JOIN bemaerkninger ON (cc_vagter.dato = bemaerkninger.dato AND cc_vagter.init = bemaerkninger.init) WHERE cc_vagter.dato >= #9/20/2005# AND cc_vagter.init='tho'
Så behøver du da ikke at Left Joine, så vidt jeg kan se:
SELECT cc_vagter.*, medarbejdere.*, bemaerkninger.* FROM Medarbejdere INNER JOIN cc_vagter ON medarbejdere.init = cc_vagter.init INNER JOIN bemaerkninger ON (cc_vagter.dato = bemaerkninger.dato AND cc_vagter.init = bemaerkninger.init) WHERE cc_vagter.dato >= #9/20/2005# AND cc_vagter.init='tho'
Der står: Der er fundet en syntaks fejl fordi der mangler en operator . i forespørgelsesudtrykket "medarbejdere.init = cc_vagter.init INNER JOIN bemaerkninger ON (cc_vagter.dato = bemaerkninger.dato".
Måske er det fordi Access har en underlig SQL-syntaks, så prøv:
SELECT cc_vagter.*, medarbejdere.*, bemaerkninger.* FROM (cc_vagter INNER JOIN bemaerkninger ON cc_vagter.dato = bemaerkninger.dato AND cc_vagter.init = bemaerkninger.init) INNER JOIN medarbejdere ON medarbejdere.init = cc_vagter.init WHERE cc_vagter.dato >= #9/20/2005# AND cc_vagter.init='tho';
SELECT cc_vagter.*, medarbejdere.*, bemaerkninger.* FROM (cc_vagter LEFT JOIN bemaerkninger ON cc_vagter.dato = bemaerkninger.dato AND cc_vagter.init = bemaerkninger.init) INNER JOIN medarbejdere ON medarbejdere.init = cc_vagter.init WHERE cc_vagter.dato >= #9/20/2005# AND cc_vagter.init='tho';
Du skal joine medarbejdere med cc_vagter, og vi er enige om at vi kun vil se personer der har vagter, derfor kan det være INNER.
Derefter skal bemaerkninger joines, og da der ikke altid er bemaerkninger skal det være LEFT OUTER:
SELECT cc_vagter.*, medarbejdere.*, bemaerkninger.* FROM medarbejdere INNER JOIN cc_vagter ON medarbejdere.init = cc_vagter.init LEFT JOIN bemaerkninger ON (cc_vagter.dato = bemaerkninger.dato AND cc_vagter.init = bemaerkninger.init) WHERE cc_vagter.dato >= #9/20/2005# AND cc_vagter.init='tho';
jeg er lige prøvet claes' access venlige sætning i Access, og det virker sgu. Jeg kan bare ikke få det til at virke i scriptet. Den siger "Elementet kan ikke findes i den samling, der svarer til det anmodede navn eller ordenstal."
Men det er nok en fejl i mit script.. Det kigger jeg på senere, bare sql'en virker.
Mange tak for hjælpen begge to. Jeg havde ikke regnet den query ud selv.
Når du i scriptet henviser til et felt med fx. (hvis det er ASP):
Response.Write(Rec("feltnavn"))
- så skal der jo være et felt der hedder "feltnavn", og der må kun være ét der hedder sådan.
Det jeg vil råde dig til er at droppe at bruge *. Det er en dårlig vane af mange grunde, bl.a. fordi du belaster serveren med at hente en masse felter du ikke har brug for. Gør i stedet dette:
SELECT cc_vagter.felt1 AS vagter_felt1, cc_vagter.felt2 AS vagter_felt2, medarbejdere.felt1 AS vagter_felt1 ...
Altså, nævn alle de felter du faktisk får brug for, og sørg for at de alle har unikke navne, evt. ved at bruge AS til at tildele dem et alias.
Hvis dette hjælper vil jeg gerne have nogle af pointene, ellers giver du dem bare til claesdamlund
Jo simplere jo bedre er rigtigt nok, man skal bare huske at det skal være simpelt for serveren, ikke for programmøren. En server har ingen problemer medat læse en SQL sætning der fylder tre A4-ark, men det har vi. Den kommer derimod på ekstra arbejde hvis den skal tage stilling til en masse *'er.
Den eneste form for dovenskab der er ok, er dovenskab på serverens vegne. Men det er du jo åbenbart helt med på :o)
Idanielsen har ret - forespørgsler skal være så præcise som muligt. Du kan dog forsvare * hvis dine underliggende tabeller jævnligt ændrer design, dvs. får fjernet eller tilføjet felter. Så kan * unødvendiggøre omskrivning af dine SQL sætninger.
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.