Sql server 2008 在链接表中查找相关行

Sql server 2008 在链接表中查找相关行,sql-server-2008,relational-database,Sql Server 2008,Relational Database,我的问题领域是广告,为此,我有一个数据库,其中包含一个名为广告的表。广告可以有方面,即准分类描述性术语。因此,有一个FACET表定义FACET,还有一个faceterm表包含每个FACET的值。ADVERTFACETTERMASSIGNMENT是一个链接表,说明哪些方面的术语值分配给哪个广告 所以,你可能有一个汽车广告,其中本田的Make方面有价值,苏塞克斯的位置方面有价值。因此,如果广告客户是广告客户{PK=14},Honda是刻面术语{PK=1},Sussex是刻面术语{PK=2},那么您希

我的问题领域是广告,为此,我有一个数据库,其中包含一个名为广告的表。广告可以有方面,即准分类描述性术语。因此,有一个FACET表定义FACET,还有一个faceterm表包含每个FACET的值。ADVERTFACETTERMASSIGNMENT是一个链接表,说明哪些方面的术语值分配给哪个广告

所以,你可能有一个汽车广告,其中本田的Make方面有价值,苏塞克斯的位置方面有价值。因此,如果广告客户是广告客户{PK=14},Honda是刻面术语{PK=1},Sussex是刻面术语{PK=2},那么您希望在广告客户FacetTermAssignment{AdvertId,FacetTermId}:14,1和14,2中找到行

考虑到这一安排,我如何着手寻找所有其他在苏塞克斯郡为洪达斯做的广告?换句话说,我如何在AdvertFaceTermAssignment中找到一组行,这些行与给定广告的该表中的行相匹配,但不是该广告中的行

我正在使用SQLServer2008。我尝试过使用IN子句,但这会返回部分匹配,即除Sussex之外的所有Hondas和Sussex中不属于Hondas的所有汽车等


为了重申我的要求,我需要从AdvertFaceTermAssignment中找到所有行,其中这些行至少包含与另一个给定广告相同的方面术语ID。它是否有更多的方面术语并不重要,前提是它至少有与所选的、比较的、广告完全相同的方面术语。

Ok,其中广告FaceTermAssignment为{AdvertId,FaceTermId} 对于两个学期的搜索

select fta1.AdvertID 
from ADVERTFACETTERMASSIGNMENT fta1
join ADVERTFACETTERMASSIGNMENT fta2 on fta1.AdvertID = fta2.AdvertID
where fta1.FacetTermId = @searchFacet1 and fta2.FacetTermID = @searchFacet2
and fta1.AdvertID <> @searchAdvertId

顺便说一句,我在威斯康星州苏塞克斯发布了这篇文章,这基本上是一个EAV-实体、属性、价值模型,具有固定的价值选择

WITH FLATTENED AS (
    SELECT a.ADVERT_ID, ft.FACETTERM_ID
    FROM ADVERT a
    INNER JOIN ADVERTFACETTERMASSIGNMENT afta
        ON afto.ADVERT_ID = a.ADVERT_ID
    INNER JOIN FACETTERM ft
        ON ft.FACETTERM_ID = afta.FACETTERM_ID
    INNER JOIN FACET f
        ON f.FACET_ID = ft.FACET_ID
)
SELECT rhs.ADVERT_ID, COUNT(*)
FROM FLATTENED lhs
INNER JOIN FLATTENED rhs
    ON lhs.ADVERT_ID = @SOME_ID
    AND rhs.ADVERT_ID <> lhs.ADVERT_ID
    AND rhs.FACETTERM_ID = lhs.FACETTERM_ID
GROUP BY rhs.ADVERT_ID
HAVING COUNT(*) = (SELECT COUNT(*) FROM FLATTENED WHERE ADVERT_ID = @SOME_ID)

这里的技术是,任何两个广告之间的内部连接中匹配的面数必须等于左侧对象广告的面数。

一种方法可以是在facettermid上将广告FacetTermAssignment表内部连接到自身, 并根据广告ID进行分组,以计算广告之间匹配面的数量

然后,您可以将其与第一个广告中的面总数进行比较,如果匹配的数量 是相同的,那么它至少具有与所选比较器完全相同的方面项

在SQLServer2008中,您可以使用CTE来简化这一过程。像这样:

;WITH m AS
    (SELECT advertid,candidateid,COUNT(*) as matchingfacets FROM (
        SELECT a.advertid,b.advertid as candidateid FROM advertfacettermassignment a 
        INNER JOIN advertfacettermassignment b ON a.facettermid=b.facettermid) sub
    GROUP BY advertid,candidateid)
,t AS
    (SELECT advertid,COUNT(*) as TotalFacets FROM advertfacettermassignment GROUP BY advertid)
SELECT 
    totalfacets.advertid,
    matchingfacets.candidateid,
    t.totalfacets,
    m.matchingFacets
FROM m INNER JOIN t
ON m.advertid=t.advertid
WHERE matchingfacets=totalfacets

请显示模式、示例数据和所需结果。我觉得我回到了高中,试图从我最不喜欢的老师那里破译一个神秘的单词问题。一般的解决方案是+1,但是使用flatten而不是仅仅使用AFTA有什么意义呢?扁平化不只是AFTA的一个经过验证的副本,还需要额外的连接表的开销吗?@Mr.Mindor没有真正的原因,我只是将所有内容连接起来,这样如果需要的话就不必重复了,因为这是集合的自连接。我认为在现实生活中,这样的观点已经存在于EAV系统中。非常感谢。这显然是可行的,我已经在我的数据库中进行了测试,并且得到了正确的结果,但是作为一个非SQL开发人员,我不明白为什么它可以工作。你能把它拼出来吗?@user1439973如果你继续,把一些数据放到一个SQLFIDLE示例中,我将一步一步地向你展示它是如何工作的。基本上,这是一个自我连接,以显示所有其他广告匹配。当按其他广告分组时,每个其他广告都有该广告与对象广告的匹配计数。如果给定广告的匹配计数与对象广告的总计数匹配,则它必须是完美或严格的超集匹配。
 AdvertId matches nonMatches
 4        2       0
 7        2       0
 9        2       1
 5        2       1
 10       1       0
 6        1       1
 2        1       1
 3        1       1
WITH FLATTENED AS (
    SELECT a.ADVERT_ID, ft.FACETTERM_ID
    FROM ADVERT a
    INNER JOIN ADVERTFACETTERMASSIGNMENT afta
        ON afto.ADVERT_ID = a.ADVERT_ID
    INNER JOIN FACETTERM ft
        ON ft.FACETTERM_ID = afta.FACETTERM_ID
    INNER JOIN FACET f
        ON f.FACET_ID = ft.FACET_ID
)
SELECT rhs.ADVERT_ID, COUNT(*)
FROM FLATTENED lhs
INNER JOIN FLATTENED rhs
    ON lhs.ADVERT_ID = @SOME_ID
    AND rhs.ADVERT_ID <> lhs.ADVERT_ID
    AND rhs.FACETTERM_ID = lhs.FACETTERM_ID
GROUP BY rhs.ADVERT_ID
HAVING COUNT(*) = (SELECT COUNT(*) FROM FLATTENED WHERE ADVERT_ID = @SOME_ID)
;WITH m AS
    (SELECT advertid,candidateid,COUNT(*) as matchingfacets FROM (
        SELECT a.advertid,b.advertid as candidateid FROM advertfacettermassignment a 
        INNER JOIN advertfacettermassignment b ON a.facettermid=b.facettermid) sub
    GROUP BY advertid,candidateid)
,t AS
    (SELECT advertid,COUNT(*) as TotalFacets FROM advertfacettermassignment GROUP BY advertid)
SELECT 
    totalfacets.advertid,
    matchingfacets.candidateid,
    t.totalfacets,
    m.matchingFacets
FROM m INNER JOIN t
ON m.advertid=t.advertid
WHERE matchingfacets=totalfacets