Avatar billede Springform Nybegynder
09. december 2010 - 15:16 Der er 24 kommentarer og
1 løsning

Hvordan løses dette SELECT

Jeg har lavet følgende tabel imellem en M:N (mange-til-mange) relation.


prop_attr
p_attr_id | prop_id | attr_id
------------------------------
1        | 1      | 1
2        | 1      | 3
3        | 2      | 1
4        | 2      | 3
5        | 2      | 4
6        | 3      | 3


Godt lad os så sige at jeg gerne vil ha alle de prop_id med attr_id == 1 OG 3.

Jeg vil gerne lave et select statement der kan klare den.
Avatar billede Springform Nybegynder
09. december 2010 - 15:17 #1
Det var så lige forkerte kategori
Avatar billede Slettet bruger
09. december 2010 - 15:24 #2
SELECT prop_id WHERE (attr_id = 1 OR 3)
Avatar billede Springform Nybegynder
09. december 2010 - 15:28 #3
Det skal være OG og ikke ELLER
Avatar billede michael_stim Ekspert
09. december 2010 - 15:32 #4
SELECT prop_id FROM prop_attr WHERE attr_id = 3 AND prop_id = 1
Avatar billede michael_stim Ekspert
09. december 2010 - 15:35 #5
Hov læste forkert. De kan vel kun have ét id pr række, så det må blive:

SELECT prop_id FROM prop_attr WHERE attr_id = 3 OR attr_id = 1
09. december 2010 - 15:35 #6
Jeg lavede for test en lille tabel Springform med dine data.  Denne query:

SELECT prop_id FROM Springform WHERE attr_id IN(1, 3);

gav mig dette resultat:

prop_id 
      1
      1
      2
      2
      3

hvilket stemmer med dataerne i tabellen.
Avatar billede Springform Nybegynder
09. december 2010 - 15:41 #7
Når du bruger IN er det lige som at bruge OR den skal altså bare indeholde en af dem. Men prop_id 3 attr_id 1, og dermed bør prop_id ikke være med når jeg skal bruge dem med attr_id == 1 OG attr_id == 3

Håber i forstår :P, min logik siger at det ikke kan lade sig gøre, men igen så kender jeg ikke alle finurlige WHERE statements, så havde håbet der var en der kunne.

Eller er det den forkerte måde at bryde en M:N relation?
Avatar billede hooh Nybegynder
09. december 2010 - 15:51 #8
Hvis det ikke er nogen af ovenstående svar, så er det lidt forvirrende hvad du ønsker.
Hvad ønsker du slutresultatet skal være efter din Select?
Avatar billede Springform Nybegynder
09. december 2010 - 15:59 #9
jeg syntes eller det er meget klart beskrevet :P. Men forsøger da gerne igen.

Min select skal give mig én prop_id for hver prop_id der opfylder kravene attr_id == 1 OG attr_id == 3

det vil sige at i ovenstående eksempel skal der udskrives prop_id 1 og prop_id 2 da de er de eneste der opfylder kravene.
Avatar billede michael_stim Ekspert
09. december 2010 - 16:09 #10
SELECT a.prop_id FROM prop_attr a WHERE a.attr_id = 3 AND a.attr_id= (SELECT b.prop_id FROM prop_attr b WHERE b.attr_id = 1 AND a.prop_id = b.prop_id)

Ikke testet, ikke set igennem og kan formodentlig skrives pænere med en JOIN, men noget á la det.
Avatar billede michael_stim Ekspert
09. december 2010 - 16:10 #11
Kan allerede se at den er forkert, men du forstår pointen?
Avatar billede Springform Nybegynder
09. december 2010 - 16:15 #12
Svare det egentlig ikke til at skrive
SELECT prop_id FROM prop_attr WHERE attr_id = 1 AND attr_id = 3
?

Jeg må prøve at se om ikke jeg kan gøre noget anderledes, for den er ved at hænge mig ud af halsen
Avatar billede repox Seniormester
09. december 2010 - 16:22 #13
#2 var inde på noget af det rigtige.
Forsøg dig med
SELECT DISTINCT prop_id WHERE (attr_id = 1 OR 3) 

eller brug IN som #6 også foreslår; men kombiner det igen med en DISTINCT
SELECT DISTINCT prop_id FROM Springform WHERE attr_id IN(1, 3);
Avatar billede Springform Nybegynder
09. december 2010 - 16:32 #14
Stadig en OR og det jeg skal bruge er en AND operator
Avatar billede majbom Novice
09. december 2010 - 16:45 #15
da prop_id er ÈT felt, kan du jo i sagens natur ikke få nogle rækker returneret, hvis du kun vil have rækker hvor prop_id er BÅDE 1 OG 3 - det giver jo ingen mening.

der er heller ikke nogle biler der har BÅDE diesel OG benzin motor (det er der måske nok et eller andet sted, men jeg håber du fik fat i pointen..)
Avatar billede Springform Nybegynder
09. december 2010 - 16:56 #16
Jamen det var også der den bristede for mig, prøver lige at være lidt mere specific så kan det være at jeg går galt i byen et sted

(forklaring: table(row))
jeg har en række boliger i en tabel property(prop_id), hvor bolig kan så have en række attributter som have, grill, pool osv. som findes i tabellen attributes(attr_id)

Det vil altså sige at vi har en M:N relation da en bolig kan have mange attributter og en attribut kan have mange boliger.

For at undgå denne M:N indsætter jeg en associeret tabel prop_attr(p_attr_id, prop_id, attr_id).

Så har vi istedet 2*1:N relationer

Nu vil jeg så gerne have fat i alle de boliger som har have og grill.


property
prop_id | price
----------------
1      | 12000
2      | 12000
3      | 12000
4      | 12000



attributes
attr_id | attribute
----------------
1      | pool
2      | have
3      | grill
4      | garage



prop_attr
prop_id | attr_id
----------------
1      | 1
1      | 3
2      | 3
3      | 1
3      | 3
3      | 4


Er der en bedre måde at løse dette problem?
Avatar billede Springform Nybegynder
09. december 2010 - 16:57 #17
Den sidste tabel skal ligne den i det oprindelige indlæg
Avatar billede erikjacobsen Ekspert
09. december 2010 - 17:08 #18
SELECT prop_id FROM prop_attr WHERE attr_id IN (1,3) GROUP BY prop_id HAVING count(*)=2
Avatar billede repox Seniormester
09. december 2010 - 17:10 #19
Som splazz også er inde på er det din logik der fejler - ikke kodens logik.
Ved at fastholde at det er den logiske AND operator du vil anvende, vil dit logiske resultat også være at du ingen resultater får - for dit integer felt kan ikke indeholde 1 OG 3 på samme tid, som faktisk er det du spørger på i gennemløbet af dine rækker.

Derfor må det være naturligt at det er OR operatøren der skal i brug - da du i sagens natur ikke kan få en række retur som ikke indeholder 1 ELLER 3.
Avatar billede intenz Novice
09. december 2010 - 17:19 #20
Der er typisk to muligheder, enten at joine tabellen med sig selv eller bruge COUNT og GROUP BY.

Joine med sig selv:

SELECT pa1.prop_id
FROM prop_attr pa1
JOIN prop_attr pa2 ON (pa1.prop_id = pa2.prop_id)
WHERE pa1.attr_id = 2
AND pa2.attr_id = 3

Den kan så udvides med flere hvis behovet er der. Kaldet skal så genereres 'dynamisk' med en løkke.

Eller GROUP BY metoden:

SELECT prop_id
FROM prop_attr
WHERE attr_id IN (2,3)
GROUP BY prop_id
HAVING COUNT(*) = 2

Læg mærke til den sidste linje, som gør at du kun får resultatet tilbage hvis der er fundet 2 (begge attributes er til stede).

Jeg vil tro performance er bedre med den første, men det kommer an på omstændighederne (hvor mange attributes der skal tjekkes ad gangen).
Avatar billede wster Nybegynder
09. december 2010 - 17:24 #21
Misforstår jeg problemet eller er det ikke bare at lave en self-join?

SELECT DISTINCT p1.prop_id FROM prop_attr p1, prop_attr p2 WHERE p1.prop_id = p2.prop_id AND p1.attr_id = 1 AND p2.attr_id = 3
Avatar billede Springform Nybegynder
09. december 2010 - 17:28 #22
Fantastisk!

erikjacobsen den fungerede præcis som den skulle!

intenz igen det var lige det der skulle til!
Avatar billede majbom Novice
09. december 2010 - 17:44 #23
på den måde - så fangede jeg den osse :)
Avatar billede Springform Nybegynder
09. december 2010 - 19:05 #24
Lige for at vende tilbage til performance så fandt jeg at ved 8 kriterier var group by metoden i gennemsnit dobbelt så hurtig (0,0004s mod 0.0008s) og ser ud til at den er stigende, ikke at der er den store forskel men lidt har også ret. Så det må være den jeg gør brug af :)...

Endnu engang tak for hjælpen
Avatar billede repox Seniormester
10. december 2010 - 12:20 #25
Jeg synes at GROUP BY metoden som intenz bidrog med gav en god og forståelig løsning, men jeg synes det er værd at pointere  at #2 og #6 ikke tog fejl i deres antagelser  om hvilken logik der skulle i brug...
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

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