/ Forside / Teknologi / Udvikling / SQL / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
SQL
#NavnPoint
pmbruun 1704
niller 962
fehaar 730
Interkril.. 701
ellebye 510
pawel 510
rpje 405
pete 350
gibson 320
10  smorch 260
Join med m-m tabel
Fra : Jeppe Vesterbæk


Dato : 26-10-04 19:05

Hej

Sidder og roder med et problem, som jeg kun kan finde en lidt grim løsning
til. Håber I kan hjælpe mig til en pænere løsning. Jeg har følgende
entiteter:
PERSON ----0..M-------------0..M----GRUPPE

dvs. der er en m-m relation mellem "person" og "gruppe". "Person" beskriver
en person med navn, adresse, tlf etc. "Gruppe" beskriver en bestemt gruppe
med navn ect. Een person kan altså være relateret til mange grupper, og een
gruppe kan være relateret til mange personer.

M-m relationen resulterer jo i tre tabeller: "person", "p_gr_r" og "gruppe"
hvor den "p_gr_r" er m-m relations-tabellen

Jeg kan lave søgninger ud fra alle felter i "person", f.eks.
SELECT * FROM person WHERE navn='jens'

Jeg kan lave søgninger hvor jeg kræver relation til een gruppe (her med
gID=3):
SELECT p.* FROM
person p LEFT JOIN p_gr_r pg ON p.pID = pg.pID
WHERE pg.gID =3

Men hvad så hvis jeg kræver, at personen skal have relation til både gruppe
3 og gruppe 4? Min løsning lige nu:
SELECT p.* FROM
(person p LEFT JOIN p_gr_r pg ON p.pID = pg.pID)
LEFT JOIN p_gr_r pg2 ON p.oID = pg2.pID
WHERE pg.gID =3 AND pg2.gID=4

Det virker, men det er lidt bøvlet .. især fordi jeg kommer til at lave
søgninger med relationer til over 10 grupper. Der må være en rigtigre måde
at gøre dette på.

På forhånd tak for hjælpen
/Jeppe



 
 
Jeppe Vesterbæk (26-10-2004)
Kommentar
Fra : Jeppe Vesterbæk


Dato : 26-10-04 19:20

Nåja, bruger MySQL 4 ...



Peter Brodersen (26-10-2004)
Kommentar
Fra : Peter Brodersen


Dato : 26-10-04 21:53

On Tue, 26 Oct 2004 20:04:34 +0200, "Jeppe Vesterbæk"
<jhve02_fjerndette_@control.auc.dk> wrote:

>Men hvad så hvis jeg kræver, at personen skal have relation til både gruppe
>3 og gruppe 4? Min løsning lige nu:
>SELECT p.* FROM
>(person p LEFT JOIN p_gr_r pg ON p.pID = pg.pID)
>LEFT JOIN p_gr_r pg2 ON p.oID = pg2.pID
>WHERE pg.gID =3 AND pg2.gID=4
>
>Det virker, men det er lidt bøvlet .. især fordi jeg kommer til at lave
>søgninger med relationer til over 10 grupper. Der må være en rigtigre måde
>at gøre dette på.

Muligvis kan tråden begyndende med dette indlæg hjælpe dig:
<news:cjiiqm$rko$1@katie.ellegaard.dk>

Eller via Google:
http://groups.google.com/groups?hl=da&lr=&c2coff=1&threadm=cjqag9%247ru%241%40katie.ellegaard.dk&rnum=2&prev=/groups%3Fq%3Dauthor:Brodersen%2Bgroup:dk.edb.database%26hl%3Dda%26lr%3D%26c2coff%3D1%26selm%3Dcjqag9%25247ru%25241%2540katie.ellegaard.dk%26rnum%3D2

Mit forslag:
SELECT p.*, COUNT(*) AS antal
FROM person p
INNER JOIN p_gr_r pg ON p.pID = pg.pID
WHERE pg.gID IN (3,4)
GROUP BY p.pID
HAVING antal = 2;

HAVING-antallet skal justeres efter antallet af grupper, personen skal
være med i. Så hvis personen skal tilhøre tre grupper - 2,4 og 5 - så
ser queryen således ud:

SELECT p.*, COUNT(*) AS antal
FROM person p
INNER JOIN p_gr_r pg ON p.pID = pg.pID
WHERE pg.gID IN (2,4,5)
GROUP BY p.pID
HAVING antal = 3;


I øvrigt, idet du alligevel bruger WHERE på pg og pg2 i dit eksempel,
er der ingen grund til at LEFT JOIN'e fremfor INNER JOIN'e.

(det er måske på sin plads at bemærke, at det ikke er yndigt at hive
felter ud, man ikke aggregerer på - i dette tilfælde ville jeg dog
gøre det uden at blinke, idet der er tale om præcis samme række, der
går igen flere gange, og der bruges MySQL)

--
- Peter Brodersen

Ugens sprogtip: pc (og ikke PC)

claesdamlund (27-10-2004)
Kommentar
Fra : claesdamlund


Dato : 27-10-04 20:39

Hej Peter

Man kan da ikke bruge kolonne-aliaser i Having?

Claes Damlund

--
Leveret af:
http://www.kandu.dk/
"Vejen til en hurtig løsning"


Peter Brodersen (27-10-2004)
Kommentar
Fra : Peter Brodersen


Dato : 27-10-04 21:08

On Wed, 27 Oct 2004 19:39:27 GMT, "claesdamlund"
<claesdamlund.news@kandu.dk> wrote:

>Man kan da ikke bruge kolonne-aliaser i Having?

MySQL har ingen problemer med det, men det er selvfølgelig mere
generisk at bruge COUNT(*) i stedet for mit antal-alias. Ved brug af
aliaset er det dog måske lettere at forstå meningen ud af teksten.

MySQL 4.0 understøtter dog ikke subselects, derfor den løsning - men
dobbelt not exsists er selvfølgelig finere. Her er det nok også
passende at smide det link på banen, som Troels gav mig for et par
uger siden: http://www.dbazine.com/celko1.html

--
- Peter Brodersen

Ugens sprogtip: pc (og ikke PC)

Jeppe Vesterbæk (29-10-2004)
Kommentar
Fra : Jeppe Vesterbæk


Dato : 29-10-04 20:40

Hej Peter

Tak for dit svar. Undskyld jeg ikke har svaret før nu .. der har været
lidt travlt om ørerne på mig.

> Mit forslag:
> SELECT p.*, COUNT(*) AS antal
> FROM person p
> INNER JOIN p_gr_r pg ON p.pID = pg.pID
> WHERE pg.gID IN (3,4)
> GROUP BY p.pID
> HAVING antal = 2;

Ok, smart. Jeg forstår princippet / hvad der sker. Hvad jeg dog ikke
helt kan gennemskue er hvordan jeg så kan udtrykke:
(gID=3 AND gID=4 AND gID=5) OR (gID=4 AND gID=8)

Altså, enten skal en person være medlem af gruppe 3,4 og 5 eller gruppe
4 og 8. Problemet er jo, at COUNT(*) (antal) jo enten skal sættes til 2
eller 3.

/Jeppe

Jeppe Vesterbæk (31-10-2004)
Kommentar
Fra : Jeppe Vesterbæk


Dato : 31-10-04 15:16

Hej hej

> Ok, smart. Jeg forstår princippet / hvad der sker. Hvad jeg dog ikke
> helt kan gennemskue er hvordan jeg så kan udtrykke:
> (gID=3 AND gID=4 AND gID=5) OR (gID=4 AND gID=8)

Jeg fik selv løst problemet ved at opgradere til Mysql 4.1.7 (stable nu)
som tillader subselects Herefter brugte jeg claes'løsningsforslag
(dobbelt negering). Svaret på ovenstående spørgsmål ser derfor således ud:

select *
from person p
where
not exists(
select *
from gruppe g
where
      
      (
      gid in(3,4,5)
      )
      
         and not exists(
select *
from p_gr_r pg
where p.pid = pg.pid and
g.gid = pg.gid)
)
or
not exists(
select *
from gruppe g
where
      
      (
      gid in(4,8)
      )
      
         and not exists(
select *
from p_gr_r pg
where p.pid = pg.pid and
g.gid = pg.gid)
);

Tak for hjælpen begge to.
/Jeppe

claesdamlund (27-10-2004)
Kommentar
Fra : claesdamlund


Dato : 27-10-04 20:37

Hej Jeppe

Det du efterlyser er det man kalder en Divide-sætning (i
mængdelære-teorien) også kaldet for en "dobbelt Not Exists".

Peters løsning er rigtig, forudsat fremmednøglerne i din relationstabel
(p_gr_r) udgør en sammensat unik nøgle. Desuden kan den performe dårligt
medmindre der er de rigtige indekser. Den sætning du skal bruge ser
sådan ud:

select *
from person p
where not exists(
select *
from gruppe g
where gid in(3,4) and not exists(
select *
from p_gr_r pg
where p.pid = pg.pid and
g.gid = pg.gid))

Den er simpel og effektiv og det eneste du behøver at skifte ud er
værdierne i In-operatoren, som i øvrigt kan være et vilkårligt antal og
som også kan genereres med en sub-select.

Claes Damlund

--
Leveret af:
http://www.kandu.dk/
"Vejen til en hurtig løsning"


Jeppe Vesterbæk (29-10-2004)
Kommentar
Fra : Jeppe Vesterbæk


Dato : 29-10-04 20:42

Hej Claes

Tak for svaret. Jeg tror desværre ikke jeg kan bruge din løsning da
mySQL (ver. 4) ikke understøtter subselects.

/Jeppe

Søg
Reklame
Statistik
Spørgsmål : 177558
Tips : 31968
Nyheder : 719565
Indlæg : 6408925
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste