Avatar billede jannick281090 Nybegynder
08. marts 2012 - 11:29 Der er 11 kommentarer og
3 løsninger

Indviklet select query jeg ikke kan løse selv

Hej Eksperten.dk

Sidder med en SELECT Query jeg ikke selv kan løse.

Min database struktur:
---------------------------------
| gruppe_id | bruger_id |
---------------------------------
|          1        |          1        |
|          1        |          2        |
|          2        |          1        |
|          2        |          2        |
|          2        |          3        |
|          3        |          1        |
|          3        |          2        |
|          3        |          3        |
|          3        |          4        |
---------------------------------

Det jeg gerne vil er at selecte de rækker hvor f.eks. bruger_id 1 og 2 er med i, men hvor der kun er de to medlemmer, altså skal den ikke returnere grupperne 2 og 3, men kun gruppe 1.

På forhånd tak :)
08. marts 2012 - 12:18 #1
Jeg lavede for test en tabel jannick med dine data, og så strikkede jeg denne query sammen der gav resultatet

gruppe_id bruger_id
        1                  2
        1                  2

SELECT gruppe_id, bruger_id FROM jannick WHERE bruger_id IN (1, 2) AND gruppe_id IN(SELECT gruppe_id FROM(SELECT gruppe_id, COUNT(*) count FROM jannick GROUP BY gruppe_id HAVING count=2) AS a);
Avatar billede kloge Nybegynder
08. marts 2012 - 12:54 #2
select distinct gid, max(bid)  from tab
group by gid
having count(*) = 2 and max(bid) in (1,2)
Avatar billede jannick281090 Nybegynder
08. marts 2012 - 19:20 #3
Ingen af jeres queries virkede efter hensigten på den fulde tabel :(

Hvis jeg f.eks. tilføjer nogle nye grupper til eksemplet, så tabellen ser således her ud:
---------------------------------
| gruppe_id | bruger_id |
---------------------------------
|          1        |          1        |
|          1        |          2        |
|          2        |          1        |
|          2        |          2        |
|          2        |          3        |
|          3        |          1        |
|          3        |          2        |
|          3        |          3        |
|          3        |          4        |
|          4        |          1        |
|          4        |          2        |
|          4        |          3        |
|          4        |          4        |
|          4        |          5        |
|          5        |          2        |
|          5        |          3        |
---------------------------------

Vil din query, Christian, returnere:
---------------------------------
| gruppe_id | bruger_id |
---------------------------------
|          1        |          1        |
|          1        |          2        |
|          5        |          2        |
---------------------------------

Hvor det ønskede resultat ville være: (Gerne bare gruppere efter gruppe_id, så den bare returnerer gruppe_id = 1)
---------------------------------
| gruppe_id | bruger_id |
---------------------------------
|          1        |          1        |
|          1        |          2        |
---------------------------------

Din query, kloge, var derimod lidt mere præcis, men returnerede desværre også uhensigtsmæssige rækker hvis jeg f.eks. ændrede querien til at skulle finde gruppen hvor bruger_id 2 og 3 er med i:

SELECT DISTINCT gruppe_id, MAX(bruger_id) FROM table
GROUP BY gruppe_id
HAVING COUNT(*) = 2 AND MAX(bruger_id) IN (2,3)

Til denne query returnerede den:
---------------------------------
| gruppe_id | max(bruger_id) |
---------------------------------
|          1        |          2        |
|          5        |          3        |
---------------------------------

Hvor det ønskede resultat selvfølgelig ville være at den kun returnerede gruppe 5.
Avatar billede arne_v Ekspert
09. marts 2012 - 03:16 #4
Forslag:

SELECT t1.gruppe_id,t1.bruger_id
FROM (t t1 JOIN t t2 ON t2.gruppe_id=t1.gruppe_id)
    LEFT JOIN t t3 ON t3.gruppe_id=t1.gruppe_id AND t3.bruger_id<>t1.bruger_id AND t3.bruger_id<>t2.bruger_id
WHERE t3.bruger_id IS NULL AND t1.bruger_id IN (1,2) AND t2.bruger_id IN (1,2);

SELECT t1.gruppe_id,t1.bruger_id
FROM (t t1 JOIN t t2 ON t2.gruppe_id=t1.gruppe_id)
    LEFT JOIN t t3 ON t3.gruppe_id=t1.gruppe_id AND t3.bruger_id<>t1.bruger_id AND t3.bruger_id<>t2.bruger_id
WHERE t3.bruger_id IS NULL AND t1.bruger_id IN (2,3) AND t2.bruger_id IN (2,3);
Avatar billede jannick281090 Nybegynder
09. marts 2012 - 04:47 #5
Har bikset en løsning sammen:

SELECT DISTINCT group_id
FROM groups
GROUP BY group_id
HAVING
    COUNT(*) = " . $num_users . " AND
    MIN(user_id) = " . $lowest . " AND
    MAX(user_id) = " . $highest . " AND
    SUM(user_id) = " . $sum . " AND
    VARIANCE(user_id) = " . $variance . ";

Hvor jeg giver min PHP funktion et array af user_id's, og ud fra det array udregner count, min, max, sum og variance.

Hvis i har bedre forslag, gerne med henblik på bedre performance, må i gerne komme med dem.
09. marts 2012 - 08:18 #6
Ja, jeg indser problemet - min query giver resultater hvor der er præcist to rækker med en gruppe id og i disse tilfælde de rækker hvor bruger id er 1 eller 2.  Ved nærlæsning af spørgsmålet ser jeg, at du kun vil have de rækker med hvor de eneste brugere i en gruppe er 1 og 2.

Men eftersom du nu har en egen løsning (og til lykke med det) skal jeg ikke bakse videre med min.  Jeg afventer så at spørgsmålet lukkes (sandsynligvis med point til dig selv.)
Avatar billede arne_v Ekspert
09. marts 2012 - 14:45 #7
jannick>

Har du proevet mit forslag?
Avatar billede jannick281090 Nybegynder
09. marts 2012 - 18:44 #8
Christian ->

Tak for forsøget, og det var da heller ikke forgæves, da din samt kloge's forslag bidrog til min egen query så i får lov at dele de 200 point, evt. også med arne, men afventer lige hans respons på nedenstående.

Arne ->

Nej, desværre, eftersom jeg fik bikset min egen løsning sammen inden du postede dit forslag, men da du jo bruger IN to gange tænker jeg at det vel ikke kan være bedre, performance mæssigt, end min egen løsning?
Avatar billede arne_v Ekspert
09. marts 2012 - 18:49 #9
Tja.

Proev og kig paa data og overvej om hvorvidt der er hurtigst at lave en IN (n1,n2) eller at udregne SUM og VARIANCE.
Avatar billede jannick281090 Nybegynder
09. marts 2012 - 19:04 #10
I mit tilfælde handler det mere om performance, end hvorvidt det er hurtigt at kode, og din query ville jo blive en del længere hvis nu jeg f.eks. vil finde gruppe_id ud fra eks. 6 bruger_id's.
Avatar billede arne_v Ekspert
09. marts 2012 - 19:18 #11
Med 2 vaerdier vil jeg da tro at min er betydeligt hurtigere.

Men query forudsaetter at det er 2 vaerdier - SQL skal aendres for fler vaerdier.
Avatar billede jannick281090 Nybegynder
09. marts 2012 - 19:40 #12
Alligevel, tak for hjælpen alle 3, og smid et svar arne, så får du lov at dele de 200 points med de 2 andre.

Så kan jeg altid lege lidt med dit forslag når jeg får tid til at teste performance med de forskellige queries.
Avatar billede arne_v Ekspert
11. marts 2012 - 20:14 #13
svar
Avatar billede arne_v Ekspert
12. marts 2012 - 03:37 #14
Jeg har lige testet paa min PC med 1 million raekker og index paa begge felter.

Test paa moment tager ca. 400 gange saa lang tid som brug af join.
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