16. december 2005 - 15:51Der er
12 kommentarer og 2 løsninger
Fejl i JOIN med GROUP BY
Hej,
Jeg har problemer med denne forespørgsel. Efter min mening skulle det være underordnet om der bliver brugt INNER JOIN eller LEFT JOIN, da der altid vil være et felt i [Testing_1] jf der ingen kriterier for denne tabel er. Men INNER JOIN giver færre resultater end LEFT JOIN - er der nogen tyrk-fejl eller grundlæggende fejltrin i denne forespørgsel?
SELECT MIN([testing_1].[testing started]) AS [Testing started], FROM ([testing] LEFT JOIN [testing] AS [testing_1] ON ( TRIM([testing].[Product]) = TRIM([testing_1].[Product]) AND TRIM([testing].[Type]) = TRIM([testing_1].[Type]) AND TRIM([testing].[TOM TR name]) = TRIM([testing_1].[TOM TR name]) AND IIF(TRIM(UCASE([testing].[Test platform]))='REPORT','Report','Testing') = IIF(TRIM(UCASE([testing_1].[Test platform]))='REPORT','Report','Testing') AND TRIM(UCASE([testing].[round])) = TRIM(UCASE([testing_1].[round])))) WHERE TRIM(UCASE([testing].[Status])) NOT IN ('DONE','CLOSED','CANCELLED') GROUP BY TRIM([testing].[Product]), TRIM([testing].[Type]), TRIM([testing].[TOM TR name]), IIF(TRIM(UCASE([testing].[Test platform]))='REPORT','Report','Testing'), TRIM(UCASE([testing].[round])),
Hvis det skulle gøre nogen forskel er her hele forespørgslen.
SELECT TRIM([testing].[Product]) AS [Product], TRIM([testing].[Type]) AS [Type], TRIM([testing].[TOM TR name]) AS [TOM TR name], TRIM(UCASE([testing].[round])) AS [Round], IIF(TRIM(UCASE([testing].[Test platform]))='REPORT','Report','Testing') AS [Test platform], MAX([testing].[Test request description]) AS [Test request description], MAX([testing].[TCC Target date]) AS [TCC Target date], MIN([testing].[TCC Target date]) AS [TCC Target date min], MAX([testing].[PP demand date]) AS [PP demand date], SUM([testing].[remaining]) AS [Remaining], COUNT(*) AS [Number of test platforms], MIN([testing_1].[testing started]) AS [Testing started], [comment].[date] AS [comment_date], TRIM([comment].[user] & ' - ' & UCASE([testing].[test platform])) AS [comment_user], TRIM([comment].[comment]) AS [comment] FROM ([testing] LEFT JOIN [testing] AS [testing_1] ON ( TRIM([testing].[Product]) = TRIM([testing_1].[Product]) AND TRIM([testing].[Type]) = TRIM([testing_1].[Type]) AND TRIM([testing].[TOM TR name]) = TRIM([testing_1].[TOM TR name]) AND IIF(TRIM(UCASE([testing].[Test platform]))='REPORT','Report','Testing') = IIF(TRIM(UCASE([testing_1].[Test platform]))='REPORT','Report','Testing') AND TRIM(UCASE([testing].[round])) = TRIM(UCASE([testing_1].[round])))) LEFT JOIN [comment] ON [Comment].[referid] = [testing].[id] WHERE TRIM(UCASE([testing].[Status])) NOT IN ('DONE','CLOSED','CANCELLED') GROUP BY TRIM([testing].[Product]), TRIM([testing].[Type]), TRIM([testing].[TOM TR name]), IIF(TRIM(UCASE([testing].[Test platform]))='REPORT','Report','Testing'), TRIM(UCASE([testing].[round])), [comment].[date], TRIM([comment].[user] & ' - ' & UCASE([testing].[test platform])), TRIM([comment].[comment]) ORDER BY TRIM([testing].[Product]), TRIM([testing].[Type]), TRIM([testing].[TOM TR name]), IIF(TRIM(UCASE([testing].[Test platform]))='REPORT','Report','Testing'), TRIM(UCASE([testing].[round])), [comment].[date] DESC
I lang tid har samarbejdsbranchen fokuseret på at forbedre enhedsfunktioner – bedre kameraer, klarere lyd og smartere software. Men den virkelige forvandling handler ikke om funktioner.
Slettet bruger
16. december 2005 - 16:02#1
Jeg fjerner lige de kommer, jeg ikke fik fjernet, da jeg forenklede forespørgslen.
SELECT MIN([testing_1].[testing started]) AS [Testing started] FROM ([testing] LEFT JOIN [testing] AS [testing_1] ON ( TRIM([testing].[Product]) = TRIM([testing_1].[Product]) AND TRIM([testing].[Type]) = TRIM([testing_1].[Type]) AND TRIM([testing].[TOM TR name]) = TRIM([testing_1].[TOM TR name]) AND IIF(TRIM(UCASE([testing].[Test platform]))='REPORT','Report','Testing') = IIF(TRIM(UCASE([testing_1].[Test platform]))='REPORT','Report','Testing') AND TRIM(UCASE([testing].[round])) = TRIM(UCASE([testing_1].[round])))) WHERE TRIM(UCASE([testing].[Status])) NOT IN ('DONE','CLOSED','CANCELLED') GROUP BY TRIM([testing].[Product]), TRIM([testing].[Type]), TRIM([testing].[TOM TR name]), IIF(TRIM(UCASE([testing].[Test platform]))='REPORT','Report','Testing'), TRIM(UCASE([testing].[round]))
Hvis du får to forskellige resultater og det eneste du ændrer er en left join til en inner join, så er det fordi at du har null values i din venstre tabel i en af de kolonner som du joiner på (Product, type, TOM TR name osv). Men ellers kan jeg ikke forstå hvorfor du joiner på alle de kolonner. Har du ikke en nøgle du kan joine på? Eller består nøglen af alle de kolonner?
Jeg tror du har en null værdi i et eller flere af de felter du joiner på. Selv om der jo vil være null i begge rows, da det er den samme tabel du joiner sammen, vil en inner join alligevel ignorere dem, da der ikke kan joines på en null-værdi. Derimod vil en LEFT JOIN medtage en sådan row.
Prøv evt. at teste på null, og omdanne den til en blank i stedet (med en IIF) i dine ON conditioner.
Synes godt om
Slettet bruger
16. december 2005 - 16:49#4
skal jeg så lave ([testing].[felt] = [testing_1].[felt] OR (ISNULL([testing].[felt]) AND ISNULL([testing_1].[felt]))) på alle 5 felter?
Jeg skal have den højeste [testing started] i hver GROUP (og dette værdi skal findes uden kriteriet) og nøglen er derfor de 5 kolonner.
Jeg tænkte mere på at omdanne evt. null værdier til en slags dummy-værdi før du joiner (null indikerer jo, at feltet intet indeholder). På den måde kan du "snyde" din inner join.
Noget lignende:
LEFT JOIN [testing] AS [testing_1] ON ( TRIM(IIF([testing].[Product] IS NULL, ' ', [testing].[Product])) = TRIM(IIF([testing_1].[Product] IS NULL, ' ', [testing_1].[Product])) AND TRIM(IIF([testing].[Type] IS NULL, ' ', [testing].[Type])) = TRIM(IIF([testing_1].[Type] IS NULL, ' ', [testing_1].[Type])) AND TRIM(IIF([testing].[TOM TR name] IS NULL, ' ', [testing].[TOM TR name])) = TRIM(IIF([testing_1].[TOM TR name] IS NULL, ' ', [testing_1].[TOM TR name])) AND IIF(TRIM(UCASE(IIF([testing].[Test platform] IS NULL, ' ', [testing].[Test platform])))='REPORT','Report','Testing') = IIF(TRIM(UCASE(IIF([testing_1].[Test platform] IS NULL, ' ', [testing_1].[Test platform])))='REPORT','Report','Testing') AND TRIM(UCASE(IIF([testing].[round] IS NULL, ' ', [testing].[round]))) = TRIM(UCASE(IIF([testing_1].[round] IS NULL, ' ', [testing_1].[round]))))
Jeg har som jeg foreslog erstattet null med en blank. Hvis feltet er numerisk, bør det erstattes med en dummy numerisk værdi i stedet.
Jeg vil tro, at du efter denne ændring vil opdage, at der ikke længere er forskel på en inner join og en left outer join.
Synes godt om
Slettet bruger
16. december 2005 - 17:22#6
Hvad med at lave en forespørgsel først med brug af:
--> spg: Tja, i bund og grund er det vel det samme. Men du har da ret. Man kan lave en sådan grundlæggende forespørgsel, hvor man omdanner felters evt. null-værdier til en dummy-værdi, som dog helst skal være unik i forhold til feltets øvrige værdier. Herefter kan man bruge denne forespørgsel som udgangspunkt for sin join.
Du har brugt funktionen nz, hvor jeg har brugt iif til at teste for null. Jeg tilstår, at nz nok er mere elegant, men jeg bruger den sjældent...
Hvis spørgeren skulle ønske at bruge en sådan to-trins-raket, vil det desuden være oplagt også at indlægge alle de øvrige konverteringer i trin 1 (TRIM, UCASE osv). Det ville gøre den efterfølgende forespørgsel noget nemmere.
Synes godt om
Slettet bruger
16. december 2005 - 18:16#8
Great,
Problemer var egentlig ikke at JOINsne ikke var ens. Men LEFT JOIN udelader også RIGHT table values hvis LEFT table er NULL (har jeg kunnet erfare fra denne tråd - ret mig hvis jeg tager fejl). Jeg skulle bruge alle JOINs, og det får jeg nu..
Hmm... Nej, jeg forstår heller ikke rigtigt den kommentar, med mindre der med RIGHT TABLE menes den tabel, som angives på højre side af en LEFT JOIN.
Sagen er jo, at man ikke kan bruge en null værdi til at joine rows i to tabeller. Null anses altså ikke for at være lig med null i en sammenligning. Det kan lyde forkert, men på den anden side, så angiver null jo, at der ikke er nogen værdi. Det ville jo også være forkert at sige at intet = intet. Hvordan kan man sammenligne noget som ikke er der? Det er forøvrigt en regel som ikke kun gælder i SQL, men i alle programmeringssprog som understøtter begrebet null.
Men godt du fik løst dit problem, og hvis du fik klaret begreberne lidt, så endnu bedre...
Synes godt om
Slettet bruger
18. december 2005 - 00:19#12
Jeg kendte nu godt de forskellige JOIN typer, men var ikke klar over at man ikke i en JOIN kan JOINe Null values (var det jeg uden succes forsøgte at forklare i min tidligere kommentar :c)).
Til kjulius. Du har ret i, at null ikke må være i join kriterierne. Null != null. Men i en left outer join, tages ALLE rækker med fra venstre tabel. Venstre tabel er den tabel som nævnes først.
SELECT * FROM VenstreTabel LEFT OUTER JOIN HojreTabel ON VenstreTabel.Id = HojreTabel.Id.
--> imago-dei: Ja, det er jeg klar over. Det er beklageligt, hvis jeg ikke har formået at lade det skinne igennem! ;-) Må vist hellere få mig tilmeldt det skrivekursus, jeg har overvejet...
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.