Query SQL che fornisce risultati distinti che corrispondono a più colonne
Domanda
Siamo spiacenti, non potrei fornire un titolo migliore per il mio problema poiché sono abbastanza nuovo in SQL. Sto cercando una stringa di query SQL che risolva il problema seguente.
Supponiamo che la seguente tabella:
DOCUMENT_ID | TAG ---------------------------- 1 | tag1 1 | tag2 1 | tag3 2 | tag2 3 | tag1 3 | tag2 4 | tag1 5 | tag3
Ora voglio selezionare tutti gli ID documento distinti che contengono uno o più tag (ma devono fornire tutti i tag specificati). Per esempio: Seleziona tutti i document_id con tag1 e tag2 restituirà 1 e 3 (ma non 4 ad esempio perché non ha tag2).
Quale sarebbe il modo migliore per farlo?
Saluti, Kai
Soluzione
SELECT document_id
FROM table
WHERE tag = 'tag1' OR tag = 'tag2'
GROUP BY document_id
HAVING COUNT(DISTINCT tag) = 2
Modifica:
Aggiornato per mancanza di vincoli ...
Altri suggerimenti
Ciò presuppone che DocumentID e Tag siano la chiave primaria.
Modifica : modificata la clausola HAVING per contare i tag DISTINCT. In questo modo non importa quale sia la chiave primaria.
Dati di prova
-- Populate Test Data
CREATE TABLE #table (
DocumentID varchar(8) NOT NULL,
Tag varchar(8) NOT NULL
)
INSERT INTO #table VALUES ('1','tag1')
INSERT INTO #table VALUES ('1','tag2')
INSERT INTO #table VALUES ('1','tag3')
INSERT INTO #table VALUES ('2','tag2')
INSERT INTO #table VALUES ('3','tag1')
INSERT INTO #table VALUES ('3','tag2')
INSERT INTO #table VALUES ('4','tag1')
INSERT INTO #table VALUES ('5','tag3')
INSERT INTO #table VALUES ('3','tag2') -- Edit: test duplicate tags
Query
-- Return Results
SELECT DocumentID FROM #table
WHERE Tag IN ('tag1','tag2')
GROUP BY DocumentID
HAVING COUNT(DISTINCT Tag) = 2
Risultati
DocumentID
----------
1
3
select DOCUMENT_ID
TAG in ("tag1", "tag2", ... "tagN")
group by DOCUMENT_ID
having count(*) > N and
Regola N e l'elenco dei tag secondo necessità.
Select distinct document_id
from {TABLE}
where tag in ('tag1','tag2')
group by id
having count(tag) >=2
La modalità di generazione dell'elenco di tag nella clausola where dipende dalla struttura dell'applicazione. Se stai generando dinamicamente la query come parte del tuo codice, potresti semplicemente costruire la query come una grande stringa generata dinamicamente.
Abbiamo sempre usato le procedure memorizzate per interrogare i dati. In tal caso, passiamo nell'elenco dei tag come documento XML. - una procedura del genere potrebbe assomigliare a una di queste in cui l'argomento di input sarebbe
<tags>
<tag>tag1</tag>
<tag>tag2</tag>
</tags>
CREATE PROCEDURE [dbo].[GetDocumentIdsByTag]
@tagList xml
AS
BEGIN
declare @tagCount int
select @tagCount = count(distinct *) from @tagList.nodes('tags/tag') R(tags)
SELECT DISTINCT documentid
FROM {TABLE}
JOIN @tagList.nodes('tags/tag') R(tags) ON {TABLE}.tag = tags.value('.','varchar(20)')
group by id
having count(distict tag) >= @tagCount
END
OPPURE
CREATE PROCEDURE [dbo].[GetDocumentIdsByTag]
@tagList xml
AS
BEGIN
declare @tagCount int
select @tagCount = count(*) from @tagList.nodes('tags/tag') R(tags)
SELECT DISTINCT documentid
FROM {TABLE}
WHERE tag in
(
SELECT tags.value('.','varchar(20)')
FROM @tagList.nodes('tags/tag') R(tags)
}
group by id
having count( distinct tag) >= @tagCount
END
FINE