SQL-запрос, который дает отличные результаты, которые соответствуют нескольким столбцам - PullRequest
4 голосов
/ 29 июля 2009

Извините, я не могу предоставить более подходящее название для своей проблемы, так как я довольно новичок в SQL. Я ищу строку запроса SQL, которая решает приведенную ниже проблему.

Предположим, что следующая таблица:

DOCUMENT_ID |     TAG
----------------------------
   1        |   tag1
   1        |   tag2
   1        |   tag3
   2        |   tag2
   3        |   tag1
   3        |   tag2
   4        |   tag1
   5        |   tag3

Теперь я хочу выбрать все отдельные идентификаторы документов, которые содержат один или несколько тегов (но они должны содержать все указанные теги). Например: Выберите все document_id с tag1 и tag2 вернет 1 и 3 (но не 4, например, так как у него нет tag2).

Какой лучший способ сделать это?

С уважением, Kai

Ответы [ 4 ]

14 голосов
/ 30 июля 2009
SELECT document_id
FROM table
WHERE tag = 'tag1' OR tag = 'tag2'
GROUP BY document_id
HAVING COUNT(DISTINCT tag) = 2

Edit:

Обновлено из-за отсутствия ограничений ...

7 голосов
/ 30 июля 2009

Предполагается, что DocumentID и Tag являются первичным ключом.

Редактировать : изменено предложение HAVING для подсчета тегов DISTINCT. Таким образом, не имеет значения, что является первичным ключом.

Данные испытаний

-- 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

Запрос

-- Return Results
SELECT DocumentID FROM #table
WHERE Tag IN ('tag1','tag2')
GROUP BY DocumentID
HAVING COUNT(DISTINCT Tag) = 2

Результаты

DocumentID
----------
1
3
1 голос
/ 30 июля 2009
select DOCUMENT_ID
      TAG in ("tag1", "tag2", ... "tagN")
   group by DOCUMENT_ID
   having count(*) > N and 

Настройте N и список тегов, если необходимо.

0 голосов
/ 30 июля 2009
Select distinct document_id 
from {TABLE} 
where tag in ('tag1','tag2')
group by id 
having count(tag) >=2 

Способ создания списка тегов в предложении where зависит от структуры вашего приложения. Если вы динамически генерируете запрос как часть своего кода, вы можете просто сконструировать запрос как большую динамически генерируемую строку.

Мы всегда использовали хранимые процедуры для запроса данных. В этом случае мы передаем список тегов в виде XML-документа. - такая процедура может выглядеть примерно так, где входной аргумент будет

<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

ИЛИ

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

END

...