2011-06-09 129 views
3

我不确定如何提出这个问题。TSQL查询所有记录必须存在以返回记录

我的标签表:

TagId Tag 
----- ----- 
1  Fruit 
2  Meat 
3  Grain 

我有事件表:

EventId Event 
------- ----------- 
1   Eating Food 
2   Buying Food 

,我需要做的是带回只有那些与它相关联的所有选定的标签活动。

如果选择了三个标签,则只显示包含全部三个标签的事件。

例如:

映射表

EventId TagId 
------- ----- 
1   1 
1   3 
2   1 

如果我写这样的查询:

select * from MapTable where where tagId in (1,3) 

这将返回进食和购买食物。

但我需要做的是带回标签为1和3的事件。这意味着在这种情况下,我将返回的唯一事件就是“吃饭食物”,因为它同时包含所选标签。

我想知道这是否可以在TSQL中完成,或者如果我将不得不使用业务层将它翻译成对象返回到GUI。

谢谢。

回答

4

昨天有个非常类似的问题:Query for exact match of users in a conversation in SQL Server

基本上你可以这样做:

DECLARE @NumTags INT = 2 

SELECT EventID 
FROM EventTag 
GROUP BY EventID 
HAVING 
    Sum(CASE WHEN TagID IN (1, 3) THEN 1 ELSE 0 END) >= @NumTags 

所以这个会发现(这允许在那两个标签与任何其他标记一起存在的情况下)

+0

这会在事件ID具有重复标记的情况下潜在地返回误报 - 例如, (EventId,TagId)包含(1,1)和(1,1)。 – 2011-06-09 00:59:00

+0

我已经假设事件不会得到重复的标签。我不认为这是不合理的。我试图想到一个重复标签会有用的情况(考虑到问题中的信息) – Beno 2011-06-09 01:04:18

+0

标签不会重复,因为您在映射中对事件,标签组合具有唯一约束。这是一个有趣的解决方案。 – nitefrog 2011-06-09 01:10:56

0

你要内部连接两个表,如下

SELECT * FROM Events INNER JOIN MapTable ON MapTable.EventId=Events.EventID WHERE MapTable.TagID=1 AND MapTable.TagID=3

+0

这只适用于一个标签匹配,而不是两个。 – 2011-06-09 00:56:29

0

有可能是一个更好的方式来写,但这会给你你在找什么:

select * 
from event e 
where exists(select * from maptable where eventid = e.eventid and tagid = 1) and exists(select * from maptable where eventid = e.eventid and tagid = 3) 
+0

这是行不通的。他希望Events表中具有特定标签的项目。 – 2011-06-09 00:47:24

+0

@DBM,完全误解了它,认为他只想从映射表中选择,尽管我不知道为什么。已更新,可从事件表中选择 – 2011-06-09 00:51:06

+0

@Jimmie不起作用。它仍然带回只有一个选中的记录。我只是在TSQL中运行它。它不会带回具有所有选定标记的记录。 – nitefrog 2011-06-09 00:58:46

1

这里是当你不知道该标签的解决方案都存在标签的所有事件之前。

装入标签到一个表变量,并获得总数:

select @iCount = COUNT(*) from @Tags; 

然后写你的正常查询,这些结果撞到一个表变量:

insert into @EventTags(IsSet, EventId) 
    select distinct CASE WHEN TagID IN (select ID from @Tags) THEN 1 ELSE 0 END, 
      e.EventId 
     from Event_Tag e 
      inner join @Tags t on t.ID = e.TagId 

然后回去只有全部匹配标签的事件,不仅仅是选中的标签,而是所有您需要做的事情:

select * 
    from Event_Tag e 
    inner join @Tags t on t.ID = e.TagId 
     where e.EventId in 
       ( select EventId 
        from @EventTags 
         group by EventId 
          having count(EventId) = @iCount 
      ) 

仅返回所有标签关联的标签。

再次感谢大家的想法!非常感谢所有的反馈!

+0

当“标签”列表是动态的时,Beno的答案不起作用,即用户可以使用UI来选择它们,因为您无法在包含聚合或子查询的表达式上执行聚合函数。这就是说,你的代码稍微有些偏离,因为你还需要表变量@EventTags上的TagID,否则无论使用多少个标记,EventID都会有一个单独的记录。该更改修复了这个错误,并且按预期工作。 – 2015-08-10 22:34:33

相关问题