Avatar billede MrJ Praktikant
20. september 2005 - 08:41 Der 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.


Kan i se hvad jeg gør galt?
Mvh
Effer
Avatar billede ldanielsen Nybegynder
20. september 2005 - 09:10 #1
Du bruger LEFT JOIN i stedet for INNER JOIN

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?
Avatar billede ldanielsen Nybegynder
20. september 2005 - 09:12 #2
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.
Avatar billede MrJ Praktikant
20. september 2005 - 10:10 #3
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 :)
Avatar billede MrJ Praktikant
20. september 2005 - 10:11 #4
og mht. det du siger med at jeg kan få problemer med dato feltet, så bruger jeg kun selve datoen, og ikke klokkeslættet, så jeg har ingen problemer
Avatar billede ldanielsen Nybegynder
20. september 2005 - 10:18 #5
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?
Avatar billede MrJ Praktikant
20. september 2005 - 10:35 #6
Nej, jeg kan stadig ikke finde ud af at putte det ekstra (inner) join på :)

Altså:
Der kan være X personer på vagt, det står i cc_vagter. DATO og INIT er primær nøglen.

I tabellen Medarbejdere står navn osv om medarbejderen, her bruges INIT som primær nøgle.

I tabellen Bemaerkninger bruges DATO og INIT som primærnøgle.

Eks:
[cc_vagter]
dato | init | trin
____________________
20/09/2005 | tho | 1
20/09/2005 | mpe | 1
20/09/2005 | tin | 1

[medarbejdere]

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 :)
Avatar billede claesdamlund Nybegynder
20. september 2005 - 10:47 #7
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'
Avatar billede claesdamlund Nybegynder
20. september 2005 - 10:48 #8
Du vil vel have alle medarbejdere, samt evt. tilhørende vagter med evt. tilhørende bemærkninger?
Avatar billede MrJ Praktikant
20. september 2005 - 10:51 #9
claesdamlund>

Access siger at der er en syntaks fejl.
Jeg kan ikke lige se hvor, men igen, jeg ved ikke hvordan sætningen skal se ud med flere joins :)

Access kan godt finde ud af flere joins ikke?
Avatar billede MrJ Praktikant
20. september 2005 - 10:51 #10
claes>

Nej det er alle vagter for en bestemt dato, og så skal deres fulde navn udskrives og evt. bemærkninger
Avatar billede claesdamlund Nybegynder
20. september 2005 - 10:55 #11
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'
Avatar billede MrJ Praktikant
20. september 2005 - 11:00 #12
ok. Jeg havde læst mig frem til at jeg skulle bruge left... ved ikke helt hvad forskellen er :)

men din query virker stadig ikke (i Access i hvertfald)
Avatar billede claesdamlund Nybegynder
20. september 2005 - 11:10 #13
Virker den ikke??? Kommer den med en fejl, eller giver den bare ingen data?
Avatar billede MrJ Praktikant
20. september 2005 - 11:16 #14
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".
Avatar billede claesdamlund Nybegynder
20. september 2005 - 11:31 #15
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';
Avatar billede ldanielsen Nybegynder
20. september 2005 - 11:31 #16
Du er nødt til at LEFT JOIN'e til bemaerkninger, for der er ikke altid nogen bemærkninger
Avatar billede claesdamlund Nybegynder
20. september 2005 - 11:34 #17
Enig, så:

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';
Avatar billede ldanielsen Nybegynder
20. september 2005 - 11:49 #18
Nej nu roder det:

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';

Er det ikke sådan?
Avatar billede claesdamlund Nybegynder
20. september 2005 - 11:55 #19
Det er også det der står - bare med "Access syntaks"...
Avatar billede ldanielsen Nybegynder
20. september 2005 - 12:07 #20
Du har ret, sorry :o)
Avatar billede MrJ Praktikant
20. september 2005 - 12:17 #21
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.

læg nogle svar, så få i nogle velfortjente point
Avatar billede claesdamlund Nybegynder
20. september 2005 - 12:40 #22
Svar
Avatar billede ldanielsen Nybegynder
20. september 2005 - 12:51 #23
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
Avatar billede MrJ Praktikant
20. september 2005 - 13:03 #24
Jeg brugte kun .* for at gøre SQL sætningen kortere, jo simplere jo bedre, når jeg så har fået den til at virke, så optimerer jeg det.

I får begge point.
igen, tak for hjælpen
Avatar billede ldanielsen Nybegynder
20. september 2005 - 13:10 #25
Tak.

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)
Avatar billede claesdamlund Nybegynder
20. september 2005 - 13:21 #26
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.
Avatar billede Ny bruger Nybegynder

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.

Loading billede Opret Preview
Kategori
Dyk ned i databasernes verden på et af vores praksisnære Access-kurser

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester