2012-09-24 10 views
15

Wie kann man nur die gewünschten Elemente in der IN-Liste auswählen? zum BeispielSo wählen Sie Artikel übereinstimmen Nur in der Liste in SQL-Server

select * from pagetags where TagID in (1,2,4) 

Jetzt möchte ich alle Seiten, die ihnen (1,2,4), nicht nur alle von ihnen, aber alle von ihnen zugewiesen alle oben genannten 3-IDs hat?

Gibt es einen Weg? jeder andere Betreiber? Ich habe bereits versucht = Any und = All aber kein Glück.

Antwort

22

Der Begriff für diese Art von Problem ist relational division. Eine Möglichkeit unten.

SELECT PageID 
FROM pagetags 
WHERE TagID IN (1, 2, 4) 
GROUP BY PageID 
HAVING Count(DISTINCT TagID) = 3 
+0

ok, ich hätte mein ursprüngliches Schema schreiben sollen, denn das ist schwieriger als das obige Beispiel :) Aber du hast mich dort gerettet, danke eine Tonne. – Ali

0

Sie so etwas wie dies versuchen könnte:

SELECT id, Tag FROM (
SELECT id, Tag, COUNT(*) OVER(partition by id) as cnt 
FROM pagetags 
WHERE Tag in(1,2,4) 
GROUP BY id, tag 
) a WHERE a.cnt = 3 
0

Die gewählte Antwort von Martin Smith

SELECT PageID 
FROM pagetags 
WHERE TagID IN (1, 2, 4) 
GROUP BY PageID 
HAVING Count(DISTINCT TagID) = 3 

korrekt ist, aber wenn die Geschwindigkeit ein Problem dann versuchen, diese ist.

Ich habe eine große Tabelle, die die gleiche Sache macht und 10x bessere Leistung mit dem folgenden bekam.
0,2 Sekunden im Vergleich zu 2,0 Sekunden für die Abfrage, die 272 aus einer Tabelle mit 3 Millionen Zeilen zurückgibt.
Auch getestet auf einer größeren Tabelle mit 5 Tags und gleich 10x aber jetzt 0,5 gegenüber 5,0.
Index ist PageID, TagID mit Millionen von PageID und Hunderte von TagID.
Häufiges Szenario, in dem viele Objekte mit mehrwertigen Eigenschaften gekennzeichnet sind.

SELECT distinct(p1.PageID) 
    FROM pagetags p1 
    JOIN pagetags p2 
     ON p2.PageID = p1.PageID 
     AND p2.TagID = 2 
    JOIN pagetags p3 
     ON p3.PageID = p1.PageID 
     AND p3.TagID = 4 
    WHERE p1.PageID = 1 
ORDER BY p1.PageID 

oder

SELECT distinct(PageID) 
    FROM pagetags 
    WHERE TagID = 1 
    INTERSECT 
    SELECT distinct(PageID) 
    FROM pagetags 
    WHERE TagID = 2 
    INTERSECT 
    SELECT distinct(PageID) 
    FROM pagetags 
    WHERE TagID = 4 
ORDER BY PageID 

Ziehe die zuletzt als mit über 5 schließt sich der Abfrage-Optimierer oft einige schlechte Entscheidungen treffen.
Und damit haben Sie die Gruppe nicht aufgebraucht, wenn Sie es für eine andere Aggregation benötigen.

+0

Es hängt von den verfügbaren Indizes und der Anzahl der Tags im System ab. Grundsätzlich das gleiche wie beim Vergleich von ['PIVOT' gegen' JOIN'] (http://stackoverflow.com/questions/7448453/sql-server-pivot-vs-multiple-join/7449213#7449213). Wenn die Anzahl der Variablen, die betrachtet werden sollen, variabel ist, ist dies nicht sehr erweiterbar, außer wenn die Abfrage über dynamisches SQL generiert wird. –

+0

@MartinSmith In meinem Fall ist der Index PageID TagID. Weniger als 1000 TagID, aber Millionen von PageID. Wird von einem Programm verwendet. Also ich nehme gerne die 10x Performance. – Paparazzi

0
SELECT distinct(PageID) 
FROM pagetags 
WHERE TagID IN (1,2,4) 
and PageID in 
(select distinct(PageID) from pagetags group by PageID having count(TagID)=3) 
group by PageID 
+3

Einige Erklärung könnte helfen! –

Verwandte Themen