sql >> Databasteknik >  >> RDS >> Mysql

fråga för en uppsättning i en relationsdatabas

Jag kommer inte kommentera om det finns ett bättre lämpat schema för att göra detta (det är fullt möjligt), utan för ett schema som har kolumner name och item , bör följande fråga fungera. (mysql-syntax)

SELECT k.name
FROM (SELECT DISTINCT name FROM sets) AS k
INNER JOIN sets i1 ON (k.name = i1.name AND i1.item = 1)
INNER JOIN sets i2 ON (k.name = i2.name AND i2.item = 3)
INNER JOIN sets i3 ON (k.name = i3.name AND i3.item = 5)
LEFT JOIN sets ix ON (k.name = ix.name AND ix.item NOT IN (1, 3, 5))
WHERE ix.name IS NULL;

Tanken är att vi har alla inställda nycklar i k , som vi sedan sammanfogar med set artikeldata i sets en gång för varje uppsättningsobjekt i uppsättningen vi söker efter, tre i det här fallet. Var och en av de tre inre kopplingarna med tabellalias i1 , i2 och i3 filtrera bort alla uppsättningsnamn som inte innehåller objektet som söktes efter med den kopplingen. Slutligen har vi en vänsterkoppling med sets med tabellalias ix , som tar in alla extra föremål i setet, det vill säga varje föremål vi inte letade efter. ix.name är NULL i fallet att inga extra föremål hittas, vilket är precis vad vi vill ha, alltså WHERE klausul. Frågan returnerar en rad som innehåller set-nyckeln om setet hittas, inga rader annars.

Redigera: Tanken bakom kollapsars svar verkar vara mycket bättre än mitt, så här är en lite kortare version av det med förklaring.

SELECT sets.name
FROM sets
LEFT JOIN (
    SELECT DISTINCT name
    FROM sets
    WHERE item NOT IN (1, 3, 5)
) s1
ON (sets.name = s1.name)
WHERE s1.name IS NULL
GROUP BY sets.name
HAVING COUNT(sets.item) = 3;

Tanken här är att underfrågan s1 väljer nycklarna för alla uppsättningar som innehåller andra objekt än de vi letar efter. Alltså, när vi lämnade gå med i sets med s1 , s1.name är NULL när setet bara innehåller föremål vi söker efter. Vi grupperar sedan efter uppsättningsnyckel och filtrerar bort alla uppsättningar som har fel antal föremål. Vi har då bara set som endast innehåller föremål vi söker efter och som har rätt längd. Eftersom uppsättningar bara kan innehålla ett föremål en gång, kan det bara finnas en uppsättning som uppfyller dessa kriterier, och det är den vi letar efter.

Redigera: Det gick precis upp för mig hur man gör detta utan undantag.

SELECT totals.name
FROM (
    SELECT name, COUNT(*) count
    FROM sets
    GROUP BY name
) totals
INNER JOIN (
    SELECT name, COUNT(*) count
    FROM sets
    WHERE item IN (1, 3, 5)
    GROUP BY name
) matches
ON (totals.name = matches.name)
WHERE totals.count = 3 AND matches.count = 3;

Den första underfrågan hittar det totala antalet objekt i varje uppsättning och den andra tar reda på antalet matchande objekt i varje uppsättning. När matches.count är 3, har uppsättningen alla artiklar vi letar efter, och om totals.count är också 3, setet har inga extra föremål.



  1. Varför kan jag inte infoga 10 siffror när min kolumn är INT(10)

  2. Infoga Python List (JSON eller annat) i MySQL-databasen

  3. Metadata om PL/SQL-posttyper på paketnivå

  4. Kombinera flera resultat i en underfråga till ett enda kommaseparerat värde