在SQL中指定最小连接点数

时间:2012-04-13 13:12:41

标签: sql sql-server sql-server-2008 tsql

我有这个加入表:

 CREATE TABLE [TagMap](
[intItemId] [bigint] NOT NULL,
[intTagId] [bigint] NOT NULL,
 CONSTRAINT [PK_TagMap_intItemId] PRIMARY KEY CLUSTERED 
 (
[intItemId] ASC,
[intTagId] ASC
 ))

我的sproc发现了与seedItemId相关联的标签,然后选择与这些标签关联的其他intItemIds,如下所示:

 declare @baseTags table    (intTagId bigint primary key clustered);

INSERT INTO @baseTags (intTagId)
SELECT TOP 20 t1.intTagId
FROM   TagMap t1
WHERE t1.intItemId = 776

 SELECT TOP 500 t1.intItemId
 FROM   TagMap t1
      JOIN @baseTags t2
       ON t1.intTagId = t2.intTagId
 GROUP  BY t1.intItemId
 ORDER  BY Count(*) DESC

我需要指的是在两个intItemIds之间指定最小数量的标记关联 - 比方说10 - 低于该值不返回值。换句话说,在TagMap表中可以找到两个intItemId共有的十个或更多intTagId,它很好,我们选择它 - 否则忽略它。

所以,例如给出这个数据:

 CREATE TABLE #TagMap(
 [intItemId] [bigint] NOT NULL,
 [intTagId] [bigint] NOT NULL,
 CONSTRAINT [PK_TagMap_intItemId] PRIMARY KEY CLUSTERED 
 (
 [intItemId] ASC,
 [intTagId] ASC
 ))

 insert into #TagMap
 (intItemId, intTagId)
 values 
 (1, 100),(1, 200),(1, 300),
 (2, 100),(2, 200),         (2, 500),(2, 600),
 (3, 100),                  (3, 500),(3, 600)

假设匹配阈值为2。

如果种子是intItemId 1,则只返回intItemId 2(它有两个匹配的标记ID:100和200,而intItemId 3有一个:100,低于阈值)。

如果种子是intItemId 2,则应返回intItemId 1和3(intItemId 1匹配标记Ids 100和200,而intItemId 3匹配标记Ids 500和600)。

如果种子是intItemId 3,则只返回intItemId 2(它有两个匹配的标记ID:500和600,而intItemId有一个:100,低于阈值)。

请问如何做到这一点?

干杯, 马特

2 个答案:

答案 0 :(得分:2)

SELECT
  [foreign].intItemID
FROM
  #TagMap    AS [primary]
INNER JOIN
  #TagMap    AS [foreign]
    ON [foreign].intTagID = [primary].intTagID
WHERE
  [primary].intItemID = 1
GROUP BY
  [foreign].intItemID
HAVING
  COUNT(distinct [foreign].intTagID) >= @threshold
然而,请注意,这种情况非常糟糕;因为JOIN搜索“ 任何 这些标记”,然后只能在HAVING子句中指定“has 所有 这些标签“。

根据我的经验,您可以进行小的优化,但我找到的最有价值的方法是将结果缓存到更标准的映射表中。必要时更新它们。 (标签数据的内容很少变化。)

答案 1 :(得分:1)

这似乎是这样做的(将@InterestItem改为1,2,3,它似乎产生了你要求的结果):

declare @InterestItem int
set @InterestItem = 1
declare @Threshold int
set @Threshold = 2

select
    tm2.intItemId,
    COUNT(*)
from
    #TagMap tm1
        inner join
    #TagMap tm2
        on
            tm1.intTagId = tm2.intTagId and
            tm2.intItemId <> tm1.intItemId
where
    tm1.intItemId = @InterestItem
group by
    tm2.intItemId
having
    COUNT(*) >= @Threshold

我目前在结果集中包含COUNT,但这不是必需的。