09. december 2011 - 14:20Der er
12 kommentarer og 1 løsning
Udtræk fra to tabeller i en enkelt SELECT
Først mine to tabeller:
Opgaver (ID, Deadline, Beskrivelse, Status); 1 | 2011-12-09 15:00:00 | Dette er en opgave | 1 2 | 2011-12-09 18:00:00 | Dette er en anden opgave | 0
EkstraOpgaver (ID, Deadline, Beskrivelse, Status); 1 | 2011-12-09 15:00:00 | Dette er en opgave | 0 2 | 2011-12-09 18:00:00 | Dette er en anden opgave | 1
Lige p.t. bruger jeg nedenstående, men kom til at tænke på, om det ikke kunne gøres lidt smartere? :)
my $Svar = "SELECT ID, Deadline, Beskrivelse FROM Opgaver WHERE Status = 0 ORDER BY Deadline ASC"
my ($OpgaverID, $OpgaverDeadline, $OpgaverBeskrivelse) = $Svar->fetchrow;
$Svar = "SELECT ID, Deadline, Beskrivelse FROM EkstraOpgaver WHERE Status = 0 ORDER BY Deadline ASC"
my ($EkstraOpgaverID, $EkstraOpgaverDeadline, $EkstraOpgaverBeskrivelse) = $Svar->fetchrow;
Spørgsmålet er således, hvordan jeg via en enkelt SELECT, får samme resultat, så koden bliver noget ala:
my $Svar = "SELECT ID, Deadline, Beskrivelse FROM Opgaver (AND meget gerne også EkstraOpgaver :)) WHERE Status = 0 ORDER BY Deadline ASC"
my ($ID, $Deadline, $Beskrivelse) = $Svar->fetchrow;
MySQL kan uden tvivl, min database-erfaring er bare ikke så stor. Btw. ovenstående AND virkede desværre ikke :)
my $Svar = "SELECT ID, Deadline, Beskrivelse FROM Opgaver WHERE Status = 0 ORDER BY Deadline ASC UNION SELECT ID, Deadline, Beskrivelse FROM EkstraOpgaver WHERE Status = 0 ORDER BY Deadline ASC"
Jeg er enig med JensPeterSvensson, UNION er løsningen i et sådant tilfælde. Men tillad mig at spørge, hvorfor du har en særskilt tabel for ekstra opgaver. Hvis du har to forskellige typer opgaver, normale og ekstra, kunne det være en forenkling at indsætte en ekstra kolonne i tabellen for type og indføre n for normal og e for ekstra:
Opgaver (ID, Deadline, Beskrivelse, Status, Type); 1 | 2011-12-09 15:00:00 | Dette er en opgave | 1 | n 2 | 2011-12-09 18:00:00 | Dette er en anden opgave | 0 | e
Så kunne du søge efter alle opgaver uanset type uden at skulle igang med en UNION forespørgsel.
JensPeterSvensson <- Får en "Incorrect usage of UNION and ORDER BY", når jeg kører ovenstående, men tror du er tæt på :)
Christian_Belgien <- Udmærket spørgsmål! :) Havde godt selv tænkt på at lave et felt mere, men da tabellen Opgaver bliver tømt fra tid til anden, er dette desværre ikke en mulighed.
my $Svar = "(SELECT ID, Deadline, Beskrivelse, 0 AS `origin` FROM Opgaver WHERE Status = 0 UNION SELECT ID, Deadline, Beskrivelse, 1 AS `origin` FROM EkstraOpgaver WHERE Status = 0) ORDER BY `origin`, Deadline ASC"
nå jeg indførte origin for at undgå sammenblandingen hvis sammenblanding ønskes kan du bare fjerne det:
my $Svar = "(SELECT ID, Deadline, Beskrivelse FROM Opgaver WHERE Status = 0 UNION SELECT ID, Deadline, Beskrivelse FROM EkstraOpgaver WHERE Status = 0) ORDER BY Deadline ASC"
Hvad så hvis jeg har sat prefix på tabelnavnene, da jeg har et par INNER JOINS? Du har sgu' været til stor hjælp, så du får lige hele kildekoden :)
"SELECT CHOK_Operatoer.ID, CHOK_Operatoer.Deadline, CHOK_Operatoer.Beskrivelse, CHOK_Operatoer.Udfoert, CHOK_Kategorier.KategoriNavn, CHOK_Brugere.Initialer, 0 AS Liste FROM CHOK_Operatoer INNER JOIN CHOK_Kategorier ON CHOK_Operatoer.Kategori = CHOK_Kategorier.Kategori INNER JOIN CHOK_Brugere ON CHOK_Operatoer.UdfoertInitialer = CHOK_Brugere.ID WHERE CHOK_Operatoer.Status = 0 UNION SELECT CHOK_EkstraOpgaver.ID, CHOK_EkstraOpgaver.Deadline, CHOK_EkstraOpgaver.Beskrivelse, CHOK_EkstraOpgaver.Udfoert, CHOK_Kategorier.KategoriNavn, CHOK_Brugere.Initialer, 0 AS Liste FROM CHOK_EkstraOpgaver INNER JOIN CHOK_Kategorier ON CHOK_EkstraOpgaver.Kategori = CHOK_Kategorier.Kategori INNER JOIN CHOK_Brugere ON CHOK_EkstraOpgaver.UdfoertInitialer = CHOK_Brugere.ID WHERE CHOK_EkstraOpgaver.Status = 0 AND CHOK_EkstraOpgaver.UdfoertInitialer != 0 ORDER BY Liste, Udfoert DESC"
1. Umiddelbar som jeg husker UNION burde den være helt lige glad. Kolonner i den endelige tabel svare til dem i den første select.
2. Ellers kan du sikker bare alias prefikser væk:
CHOK_Operatoer.ID AS ID EkstraOpgaver.ID AS ID
3. fjern prefikser og lave union før join, hvis det er lovligt, men det kommer til at se ufattelig grimt ud tror jeg.
SELECT uni.*, tabel1.felt, tabel2.felt FROM ( UNIONTABELLEN ) AS uni INNER JOIN tabel1 ON criteria1 INNER JOIN tabel2 ON criteria2 ORDER BY Deadline DESC
StretDK, mens vi venter på at spørgsmålet konkluderes og lukkes kan jeg ikke dy mig. Du siger, at du er nødt til at bruge to tabeller, fordi tabellen Opgaver (eller jævnfør #8 Operatoer) bliver tømt fra tid til anden. Hvem kontrollerer tømning af Operatoer? Kontrollerer du det selv eller sker det på en eller anden måde externt?
Hvis du selv kontrollerer det, så har du stadig muligheden for at placere Ekstra Opgaver i Operatoer tabellen og bruge et ekstra felt med type, for eksempel o eller e. Når du så fra tid til anden skal fjerne operatoer rækkerne men lade ekstra opgaver rækkerne blive siddende gør du det med "DELETE FROM Operatoer WHERE type = 'o'"
I så fald kunne du reducere forespørgselen i #8 til dette:
SELECT o.ID, o.Deadline, o.Beskrivelse, o.Udfoert, k.KategoriNavn, b.Initialer FROM CHOK_Operatoer o JOIN CHOK_Kategorier k ON o.Kategori = k.kategori JOIN CHOK_Brugere b ON o.UdfoertInitialer = b.ID WHERE o.status = 0
Det synes jeg selv gør det enklere og mere overskueligt.
Det er meget almindeligt, at folk designer deres databaser efter hvordan de skal bruge dataerne. Men det mere nyttige princip er at designe databasen efter dataernes struktur. Operatoerer og EkstraOpgaver synes at have præcis den samme struktur, skønt de har forskellige typer. De bør således, efter teorien om normalisering, placeres i den samme tabel med en kolonne der angiver typen. Hvis man designer databasen efter dataernes struktur, så vil man kunne gøre brug af dataerne, i princippet, på alverdens måder, også på måder man først kommer i tanker om bagefter. Hvis man designer databasen efter det man lige står og skal bruge, hvis man så senere kommer i tanker om andet man har brug for skal man som reget til at tviste tabellerne og finde på triks.
JensPeterSvensson <- Har lidt gode og dårlige nyheder. Har helt sikkert sat pris på din hjælp og lært en masse nye muligheder for MySQL-udtræk, så tak for det :)
Har dog, efter at have læst Christian_Belgien kommentar, ændret hele strukturen i databasen, så alle opgaver nu hentes fra en enkelt tabel. Må joh følge terorien om normalisering, når nu en sådan tilsyneladende eksisterer :)
Håber ikke, du føler du har spildt din tid, for har som sagt sat pris på det!
Hvordan skal vi gøre med point, så vi kan få lukket spørgsmålet?
-StreetDK-, JensPeterSvensson svarede på det spørgsmål du stillede, og du bad ham i # 6 om svar (som stadig er udestående.) Mine indlæg, som drejede sig om det jeg syntes du skulle have spurgt om, var så åbenbart til nytte, så jeg opretter et svar. Du kan uden problemer acceptere to svar. Så deler systemet automatisk pointene.
Du skal ikke følge en teori om normalisering bare fordi den består. Du skal følge teorien, hvis du mener det fører til resultater der er nyttige for dig. (Men det ser ud til at det i dette tilfælde vil være dig til nytte.)
Beklager den sene reaktion Christian_Belgien, men ville lige give JensPeterSvensson mulighed for at gøre krav på nogle af pointene :)
// Street^
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.