Avatar billede -StreetDK- Nybegynder
09. december 2011 - 14:20 Der 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 :)


// Street^
Avatar billede JensPeterSvensson Nybegynder
09. december 2011 - 14:24 #1
Hvad med:

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"
09. december 2011 - 14:53 #2
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.
Avatar billede -StreetDK- Nybegynder
09. december 2011 - 18:25 #3
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.


// Street^
Avatar billede JensPeterSvensson Nybegynder
09. december 2011 - 18:52 #4
Ja, hvad så med:

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"
Avatar billede -StreetDK- Nybegynder
09. december 2011 - 19:12 #5
Det virker, men den viser først Opgaver og dernæst EkstraOpgaver.
Meningen var at det hele skulle blandes sammen og sorteres.


// Street^
Avatar billede -StreetDK- Nybegynder
09. december 2011 - 19:14 #6
Ahhh...hvis man ændrer begge SELECT til 0 AS `origin`, så spiller det :)

Tusinde tak- smid et svar...


// Street^
Avatar billede JensPeterSvensson Nybegynder
09. december 2011 - 19:18 #7
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"
Avatar billede -StreetDK- Nybegynder
09. december 2011 - 19:28 #8
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"
Avatar billede JensPeterSvensson Nybegynder
09. december 2011 - 20:00 #9
Tre muligheder:

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
10. december 2011 - 09:05 #10
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.
Avatar billede -StreetDK- Nybegynder
12. december 2011 - 15:15 #11
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?

// Street^
12. december 2011 - 16:22 #12
-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.)
Avatar billede -StreetDK- Nybegynder
16. december 2011 - 05:33 #13
Beklager den sene reaktion Christian_Belgien, men ville lige give JensPeterSvensson mulighed for at gøre krav på nogle af pointene :)


// Street^
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
Computerworld tilbyder specialiserede kurser i database-management

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