|
| mysql - join og gruppering Fra : Martin |
Dato : 21-04-08 18:53 |
|
Flg. tabeller er oprettet og indeholder data til emneregister af sange:
tabel 1:
id, emne
tabel 2:
id, underemne, pid
tabel 3:
nr, titel, emne, underemne mfl.
Der er flg. relationer:
tabel1.id=tabel2.pid
tabel3.emne=tabel1.id
tabel3.underemne=tabel2.id
Jeg vil gerne lave et udtræk der giver flg. resultat, der grupperer emme,
underemner med de tilhørende titler.
Emne
- underemne
- titel
fx.
emne 1
- underemne 1
- titel 1
- titel 2
- underemne 2
- titel 3
- titel 4
- titel 5
emne 2
- underemne 2
- titel 6
- titel 7
- underemne 3
- titel 8
- titel 9
- titel 10
De må da kunne lade sig gøre, men jeg er løbet surt i det - forslag modtages
med stor tak.
Martin
| |
Kristian Damm Jensen (21-04-2008)
| Kommentar Fra : Kristian Damm Jensen |
Dato : 21-04-08 19:51 |
|
Martin wrote:
> Flg. tabeller er oprettet og indeholder data til emneregister af
> sange:
> tabel 1:
> id, emne
>
> tabel 2:
> id, underemne, pid
>
> tabel 3:
> nr, titel, emne, underemne mfl.
Du angiver ikke nogen nøgler.
Jeg antager:
tabel1: id
tabel2: id
tabel3: nr
Heraf følger, at samme titel kan forekomme på flere numre, og derfor at
samme titel kan være knyttet sammen med såvel flere emner, som flere
underemner.
>
> Der er flg. relationer:
> tabel1.id=tabel2.pid
> tabel3.emne=tabel1.id
> tabel3.underemne=tabel2.id
Du angiver ikke hvordan relationerne ser ud.
Jeg antager
> tabel1.id=tabel2.pid
Én til mange
> tabel3.emne=tabel1.id
Mange til én
> tabel3.underemne=tabel2.id
Mange til én
Den sidste kunne være én til én, men hvorfor skulle der da være en særskilt
tabel. Derfor denne antagelse.
> Jeg vil gerne lave et udtræk der giver flg. resultat, der grupperer
> emme, underemner med de tilhørende titler.
> Emne
> - underemne
> - titel
Det ser ud til, at der aldrig kan forekomme et emne i dit udtræk uden både
et underemne og en titel. Hvis det ikke er korrekt, skal alle joins i
nedenstående laves om til left outer join.
Tabel1 og tabel2 er i virkeligheden overflødige til dette formål, eftersom
alle værdierne også ligger i tabel3, nemlig som emne og underemne.
Select e.emne
, ue.emne
, ue.titel
from tabel3 e
join tabel3 ue
on e.underemne = ue.emne
join tabel3 t
on ue.nr= t.nr
<snip>
> De må da kunne lade sig gøre, men jeg er løbet surt i det - forslag
> modtages med stor tak.
At join'e en tabel med sig selv er altid et stort spring, når man skal lære
sql.
--
Venlig hilsen /Best regards
Kristian Damm Jensen
| |
Martin (21-04-2008)
| Kommentar Fra : Martin |
Dato : 21-04-08 21:48 |
|
Kristian wrote:
<snip>
Tabel1 og tabel2 er i virkeligheden overflødige til dette formål, eftersom
alle værdierne også ligger i tabel3, nemlig som emne og underemne.
Select e.emne
, ue.emne
, ue.titel
from tabel3 e
join tabel3 ue
on e.underemne = ue.emne
join tabel3 t
on ue.nr= t.nr
<snip>
Så har jeg ikke forklaret det rigtigt. I tabel 3 ligger bare et tal i
felterne emne og underemne, der så referer til tabellerne emne og underemne.
Emne er entydig
Der kan være flere underemner pr emne
Der kan være flere titler pr. underemne
Martin
| |
Kristian Damm Jensen (22-04-2008)
| Kommentar Fra : Kristian Damm Jensen |
Dato : 22-04-08 06:24 |
|
Martin wrote:
> Kristian wrote:
> <snip>
> Tabel1 og tabel2 er i virkeligheden overflødige til dette formål,
> eftersom alle værdierne også ligger i tabel3, nemlig som emne og
> underemne.
> Select e.emne
> , ue.emne
> , ue.titel
> from tabel3 e
> join tabel3 ue
> on e.underemne = ue.emne
> join tabel3 t
> on ue.nr= t.nr
> <snip>
Har du prøvet mit forslag? Giver det noget i den rigtige retning?
>
> Så har jeg ikke forklaret det rigtigt. I tabel 3 ligger bare et tal i
> felterne emne og underemne, der så referer til tabellerne emne og
> underemne.
Ja. Så vidt er jeg med. id, pid, emne og underemne er alle numeriske nøgler.
> Emne er entydig
> Der kan være flere underemner pr emne
> Der kan være flere titler pr. underemne
Klart.
Hvis du ikke mener, at jeg har forstået problemstillingen, må du uddybe det.
Du kan fx poste den præcise SQL der opretter dine tabeller (specielt
erklæringen af primærnøgler og fremmednøgler er interessant), samt nogle
konkrete dataeksempler med angivelse af, hvordan du forventer output ser ud.
Spørgsmål:
- Kan et underemne høre til under flere emner, eller er opdelingen i
underemner entydig?
- Kan en titel høre til under flere underemner, eller er kategoriseringen
entydig?
- Findes der kun de tre niveauer - emne, underemne, titel - eller kan et
underemne og underopdeles?
--
Venlig hilsen /Best regards
Kristian Damm Jensen
| |
Martin (22-04-2008)
| Kommentar Fra : Martin |
Dato : 22-04-08 17:48 |
|
>> Kristian wrote:
>> <snip>
>
> Har du prøvet mit forslag? Giver det noget i den rigtige retning?
> Ja, men også kun nogenlunde - der bliver fx ikke listet navnet på emner
> kun tal og underemner mangler også.
>>
>
> Du kan fx poste den præcise SQL der opretter dine tabeller (specielt
> erklæringen af primærnøgler og fremmednøgler er interessant), samt nogle
> konkrete dataeksempler med angivelse af, hvordan du forventer output ser
> ud.
>
CREATE TABLE `emne` (
`id` int(11) NOT NULL auto_increment,
`emne` tinytext NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;
CREATE TABLE `underemne` (
`id` int(11) NOT NULL auto_increment,
`underemne` tinytext NOT NULL,
`pid` varchar(2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=19 ;
CREATE TABLE `sang` (
`nr` int(11) NOT NULL auto_increment,
`titel` tinytext NOT NULL,
`emne` varchar(10) NOT NULL,
`underemne` varchar(10) NOT NULL,
PRIMARY KEY (`nr`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
Jeg ved ikke helt med en - mange relation - måske får du svaret ved min
fremstilling nedenunder.
Måske er feltet underemne i tabellen sang ikke nødvendig?
> Spørgsmål:
> - Kan et underemne høre til under flere emner, eller er opdelingen i
> underemner entydig?
Det sidste - et underemne kan kun høre til et og kun et bestemt emne
> - Kan en titel høre til under flere underemner, eller er kategoriseringen
> entydig?
Det sidste - en titel kan kun høre til et og kun et underemne eller hvis der
ikke er noget underemne høre det direkte til emnet. (ex emne 1 og 4)
> - Findes der kun de tre niveauer - emne, underemne, titel - eller kan et
> underemne og underopdeles?
Det første - der er kun 3 niveauer, men på nogle emner er der ingen
underemner kun titler og dermed kun 2 niveauer.
>
Output ønskes sådan
emne 1
- titel 1.1
- titel 1.2
emne 2
- underemne 2.1
- titel 2.1.1
- titel 2.1.2
- underemne 2.2
- titel 2.2.1
- titel 2.2.2
- titel 2.2.3
emne 3
- underemne 3.1
- titel 3.1.1
- titel 3.1.2
- underemne 3.2
- titel 3.2.1
- titel 3.2.2
- titel 3.2.3
- underemne 3.3
- titel 3.3.1
emne 4
-titel 4.1
-titel 4.2
Her er der ingen underemner på emne 1 og 4
ex. på tabellerne i eksemplet ovenover
emne:
id emne
1 emne 1
2 emne 2
3 emme 3
osv
underemne (fremmednøglen pid relaterer til emne.id)
id underemne pid
1 underemne2.1 2
2 underemne2.2 2
3 underemne3.1 3
4 underemne3.2 3
5 underemne3.3 3
osv
sang (fremmednøglen underemne relaterer til underemne.id og (fremmednøglen
emne relaterer til emne.id)) - måske denne sidste ikke er nødvendig ??
nr titel emne underemne
1 titel1.1 1 blank
2 titel1.2 1 blank
3 titel2.1.1 2 1
4 titel2.1.2 2 1
5 titel2.2.1 3 2
6 titel2.2.2 3 2
7 titel2.2.2 3 2
8 titel3.1.1 3 3
9 titel3.1.2 3 3
10 titel3.2.1 3 4
11 titel3.2.2 3 4
12 titel3.2.3 3 4
13 titel3.3.1 3 5
14 titel4.1 3 blank
15 titel4.2 3 blank
osv
Det var en længere smørre - er dig meget taknemmlig hvis du finder en
løsning.
Martin
| |
Michael Zedeler (23-04-2008)
| Kommentar Fra : Michael Zedeler |
Dato : 23-04-08 09:24 |
|
Martin wrote:
>>> Kristian wrote:
>>> <snip>
>> Har du prøvet mit forslag? Giver det noget i den rigtige retning?
>> Ja, men også kun nogenlunde - der bliver fx ikke listet navnet på emner
>> kun tal og underemner mangler også.
>> Du kan fx poste den præcise SQL der opretter dine tabeller (specielt
>> erklæringen af primærnøgler og fremmednøgler er interessant), samt nogle
>> konkrete dataeksempler med angivelse af, hvordan du forventer output ser
>> ud.
>>
>
> CREATE TABLE `emne` (
> `id` int(11) NOT NULL auto_increment,
> `emne` tinytext NOT NULL,
> PRIMARY KEY (`id`)
> ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;
>
> CREATE TABLE `underemne` (
> `id` int(11) NOT NULL auto_increment,
> `underemne` tinytext NOT NULL,
> `pid` varchar(2) NOT NULL,
Av for dælen da. Det går vist ikke. Bruger du ikke pid som fremmednøgle?
> PRIMARY KEY (`id`)
> ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=19 ;
>
> CREATE TABLE `sang` (
> `nr` int(11) NOT NULL auto_increment,
> `titel` tinytext NOT NULL,
> `emne` varchar(10) NOT NULL,
> `underemne` varchar(10) NOT NULL,
Disse to bruger du også som fremmednøgler, men datatypen er ikke den
samme som i det felt, der henvises til. Det er altså en dårlig ide.
Desuden bør du fortælle mysql hvilke referentielle constraints der er
(altså hvilke felter, der refererer til hvad).
> PRIMARY KEY (`nr`)
> ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
>
> Jeg ved ikke helt med en - mange relation - måske får du svaret ved min
> fremstilling nedenunder.
>
> Måske er feltet underemne i tabellen sang ikke nødvendig?
>
>> Spørgsmål:
>> - Kan et underemne høre til under flere emner, eller er opdelingen i
>> underemner entydig?
> Det sidste - et underemne kan kun høre til et og kun et bestemt emne
>
>> - Kan en titel høre til under flere underemner, eller er kategoriseringen
>> entydig?
> Det sidste - en titel kan kun høre til et og kun et underemne eller hvis der
> ikke er noget underemne høre det direkte til emnet. (ex emne 1 og 4)
>
>> - Findes der kun de tre niveauer - emne, underemne, titel - eller kan et
>> underemne og underopdeles?
> Det første - der er kun 3 niveauer, men på nogle emner er der ingen
> underemner kun titler og dermed kun 2 niveauer.
Så er din tabelstruktur vel rimelig nok, men du skal altså rydde op i
datatyperne og få sat referentielle constraints på. Konsekvensen er at
en sang kan referere til både et emne og et underemne. Der bør du nok
indsætte en regel om at præcis eet af disse felter altid skal være NULL.
Mvh. Michael.
| |
Kristian Damm Jensen (23-04-2008)
| Kommentar Fra : Kristian Damm Jensen |
Dato : 23-04-08 07:05 |
|
Martin wrote:
>>> Kristian wrote:
>>> <snip>
>>
>> Har du prøvet mit forslag? Giver det noget i den rigtige retning?
>> Ja, men også kun nogenlunde - der bliver fx ikke listet navnet på
>> emner kun tal og underemner mangler også.
>>>
>>
>> Du kan fx poste den præcise SQL der opretter dine tabeller (specielt
>> erklæringen af primærnøgler og fremmednøgler er interessant), samt
>> nogle konkrete dataeksempler med angivelse af, hvordan du forventer
>> output ser ud.
>>
>
> CREATE TABLE `emne` (
> `id` int(11) NOT NULL auto_increment,
> `emne` tinytext NOT NULL,
> PRIMARY KEY (`id`)
> ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;
>
> CREATE TABLE `underemne` (
> `id` int(11) NOT NULL auto_increment,
> `underemne` tinytext NOT NULL,
> `pid` varchar(2) NOT NULL,
> PRIMARY KEY (`id`)
> ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=19 ;
>
> CREATE TABLE `sang` (
> `nr` int(11) NOT NULL auto_increment,
> `titel` tinytext NOT NULL,
> `emne` varchar(10) NOT NULL,
> `underemne` varchar(10) NOT NULL,
> PRIMARY KEY (`nr`)
> ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
Dine type-erklæringer er i kaos.
emne.id er int(11), men underemne.pid er varchar(2), selvom den så vidt jeg
forstår refererer til emne.id
sang.emne og sang.underemne er begge varchar(10), men refererer til hhv
emne.id (int(11)) og underemne.id (int(11)).
Du har desuden en grum redundans i din struktur, idet der er to måder at
finde emne for en sang: Direkte opslag i sang og ved at at finde
underemne.pid ud fra sang.underemne.
<snip>
> Måske er feltet underemne i tabellen sang ikke nødvendig?
Du har fat i noget. Problemet her er, at der kan forekomme sange, der ikke
har noget underemne. HVIS en sang har underemne, har du ikke brug for emne.
HVIS den IKKE har underemne, _skal_ du bruge emne.
Jeg ville løse det ved kun at have emne, og så tilføje et typefelt, der
fortæller hvilken tabel, sang.emne refererer til. Det er ikke kønt (det kan
fx ikke erklæres som fremmednøgle på den måde), men det undgår i det mindste
redundansen.
<snip>
> Output ønskes sådan
> emne 1
> - titel 1.1
> - titel 1.2
> emne 2
> - underemne 2.1
> - titel 2.1.1
> - titel 2.1.2
> - underemne 2.2
> - titel 2.2.1
> - titel 2.2.2
> - titel 2.2.3
> emne 3
> - underemne 3.1
> - titel 3.1.1
> - titel 3.1.2
> - underemne 3.2
> - titel 3.2.1
> - titel 3.2.2
> - titel 3.2.3
> - underemne 3.3
> - titel 3.3.1
> emne 4
> -titel 4.1
> -titel 4.2
Du kan ikke få MySQL til at levere output i form af en træstruktur. Den må
du selv skabe. SQL leverer altid rækker.
Hvad du kan få, er fx
emne 1 - NULL - titel 1.1
emne 1 - NULL - titel 1.2
emne 2 - underemne 2.1 - titel 2.1.1
emne 2 - underemne 2.1 - titel 2.1.2
emne 2 - underemne 2.2 - titel 2.2.1
emne 2 - underemne 2.2 - titel 2.2.2
emne 2 - underemne 2.2 - titel 2.2.3
emne 3 - underemne 3.1 - titel 3.1.1
emne 3 - underemne 3.1 - titel 3.1.2
emne 3 - underemne 3.2 - titel 3.2.1
emne 3 - underemne 3.2 - titel 3.2.2
emne 3 - underemne 3.2 - titel 3.2.3
emne 3 - underemne 3.3 - titel 3.3.1
emne 4 - NULL -titel 4.1
emne 4 - NULL -titel 4.2
Og det er i virkeligheden relativt nemt:
select emne, underemne, titel
from sang
order by emne, underemne
Det giver så godt nok kun id'erne fremfor teksten for emne og underemne. men
så tilføjer vi bare:
select e.emne, u.underemne, titel
from sang s
join emne e on s.emne = e.id
join underemne u on s.underemne = u.id
order by e.emne, u.underemne
Bemærk dog, at du her får problemer med at sammenligne varchar(10) med
int(11), hvis du ikke har ændret din databasestruktur. Så kommer du til at
tilføje noget konverteringssnavs.
Denne version tager så ikke højde for at sang.underemne kan være NULL, så vi
retter lige til:
select e.emne, u.underemne, titel
from sang s
join emne e on s.emne = e.id
left join underemne u on s.underemne = u.id
order by e.emne, u.underemne
--
Venlig hilsen /Best regards
Kristian Damm Jensen
| |
Martin (27-04-2008)
| Kommentar Fra : Martin |
Dato : 27-04-08 09:37 |
|
Hej Kristian
Tak for nedenstående - respekt for din SQL viden - det virker fint med den
sidste select sætning - så tak herfra.
Martin
>>>> Kristian wrote:
>>>> <snip>
>>>
> Dine type-erklæringer er i kaos.
> emne.id er int(11), men underemne.pid er varchar(2), selvom den så vidt
> jeg forstår refererer til emne.id
> sang.emne og sang.underemne er begge varchar(10), men refererer til hhv
> emne.id (int(11)) og underemne.id (int(11)).
>
> Du har desuden en grum redundans i din struktur, idet der er to måder at
> finde emne for en sang: Direkte opslag i sang og ved at at finde
> underemne.pid ud fra sang.underemne.
>
> <snip>
>
>> Måske er feltet underemne i tabellen sang ikke nødvendig?
>
> Du har fat i noget. Problemet her er, at der kan forekomme sange, der ikke
> har noget underemne. HVIS en sang har underemne, har du ikke brug for
> emne. HVIS den IKKE har underemne, _skal_ du bruge emne.
>
> Jeg ville løse det ved kun at have emne, og så tilføje et typefelt, der
> fortæller hvilken tabel, sang.emne refererer til. Det er ikke kønt (det
> kan fx ikke erklæres som fremmednøgle på den måde), men det undgår i det
> mindste redundansen.
>
> <snip>
>
>
> Du kan ikke få MySQL til at levere output i form af en træstruktur. Den må
> du selv skabe. SQL leverer altid rækker.
>
> Hvad du kan få, er fx
>
> emne 1 - NULL - titel 1.1
> emne 1 - NULL - titel 1.2
> emne 2 - underemne 2.1 - titel 2.1.1
> emne 2 - underemne 2.1 - titel 2.1.2
> emne 2 - underemne 2.2 - titel 2.2.1
> emne 2 - underemne 2.2 - titel 2.2.2
> emne 2 - underemne 2.2 - titel 2.2.3
> emne 3 - underemne 3.1 - titel 3.1.1
> emne 3 - underemne 3.1 - titel 3.1.2
> emne 3 - underemne 3.2 - titel 3.2.1
> emne 3 - underemne 3.2 - titel 3.2.2
> emne 3 - underemne 3.2 - titel 3.2.3
> emne 3 - underemne 3.3 - titel 3.3.1
> emne 4 - NULL -titel 4.1
> emne 4 - NULL -titel 4.2
>
> Og det er i virkeligheden relativt nemt:
>
> select emne, underemne, titel
> from sang
> order by emne, underemne
>
> Det giver så godt nok kun id'erne fremfor teksten for emne og underemne.
> men så tilføjer vi bare:
>
> select e.emne, u.underemne, titel
> from sang s
> join emne e on s.emne = e.id
> join underemne u on s.underemne = u.id
> order by e.emne, u.underemne
>
> Bemærk dog, at du her får problemer med at sammenligne varchar(10) med
> int(11), hvis du ikke har ændret din databasestruktur. Så kommer du til at
> tilføje noget konverteringssnavs.
>
> Denne version tager så ikke højde for at sang.underemne kan være NULL, så
> vi retter lige til:
>
> select e.emne, u.underemne, titel
> from sang s
> join emne e on s.emne = e.id
> left join underemne u on s.underemne = u.id
> order by e.emne, u.underemne
>
>
> --
> Venlig hilsen /Best regards
> Kristian Damm Jensen
>
| |
|
|