【问题标题】:Inner Joining two tables based on all "Key/Value" Pairs matching exactly基于完全匹​​配的所有“键/值”对内部连接两个表
【发布时间】:2010-03-02 23:17:05
【问题描述】:

假设我有两个表 - Person 和 Clothes,并且这两个表都有关联的 Key/Value 表,这些表存储有关 Person 和 Clothing 项目的属性。

Person to Attributes 的联合版本可能如下所示:

 PersonID | AttributeKey | AttributeValue
    1          'Age'          '20'
    1          'Size'         'Large'
    2          'Age'          '20'

服装到属性的联合版本可能如下所示:

 ClothingID | AttributeKey | AttributeValue
    99          'Age'          '20'
    99          'Color'        'Blue'
    60          'Age'          '20'

给定一件特定的衣服,我想找到与所有属性对完全匹配的 Person 条目。例如,给定 ClothingID 60 我只想获取 PersonID 2,即使 PersonID 1 确实有匹配的 AGE 但它有额外的属性。而且基本上相反的效果是一样的。

鉴于 Clothing 99,我预计没有结果,因为没有 Person 条目具有 Color 属性。

一个 INNER JOIN 显然给了我与人的特定属性相匹配的服装属性。但我只想返回所有可能匹配确实匹配的行,如果有额外的,则丢弃其他行。 OUTER JOIN 将为匹配的值提供 NULL 值,但如果 1 行有 NULLS,我如何检测并丢弃所有 Person 行?

【问题讨论】:

  • 如果您重组表以便将属性存储在它们自己的字段中,那么查询数据会变得容易得多。例如。人员(PersonID、年龄、尺寸、姓名等)和衣服(ClothingID、年龄、颜色、类型、描述等)

标签: sql-server database tsql join


【解决方案1】:
SELECT  *
FROM    persons p
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    (
                SELECT  key, value
                FROM    clothing_attributes
                WHERE   clothing_id = 99
                ) ca
        FULL JOIN
                (
                SELECT  key, value
                FROM    person_attributes
                WHERE   person_id = p.id
                ) pa
        ON      ca.key = pa.key
                AND ca.value = pa.value
        WHERE   ca.key IS NULL OR pa.key IS NULL
        )

【讨论】:

  • 服装可能被允许有person表中没有的附加属性
  • @Andomar:问题是:“鉴于 Clothing 99,我预计没有结果,因为没有 Person 条目具有 Color 属性”
【解决方案2】:

您可以使用子查询来验证是否满足所有要求。对于 PersonID 和 ClothingID 的每个组合,inner join 应该有一个 count(*),它等于 person 表中的条件数。

查询示例:

select p.PersonID, c.ClothingID
from @person p
inner join @clothing c
    on p.AttributeKey = c.AttributeKey
    and p.AttributeValue = c.AttributeValue
group by p.PersonID, c.ClothingID
having count(*) = (
    select count(*) 
    from @person p2 
    where p.PersonID = p2.PersonID
)

输出:

PersonID   ClothingID
2          60
2          99

用于测试查询的数据:

declare @person table (PersonID int, AttributeKey varchar(30),
    AttributeValue varchar(30))
declare @clothing table (ClothingID int, AttributeKey varchar(30),
    AttributeValue varchar(30))

insert into @person select 1, 'Age', '20'
insert into @person select 1, 'Size', 'Large'
insert into @person select 2, 'Age', '20'

insert into @clothing select 99, 'Age', '20'
insert into @clothing select 99, 'Color', 'Blue'
insert into @clothing select 60, 'Age', '20'

【讨论】:

  • 这个子查询的性能开销是多少?
【解决方案3】:

类似这样的:

SELECT p.*,c.* People p INNER JOIN Cloths c ON (P.key=c.key AND p.value=c.value) WHERE c.id=99

【讨论】:

  • 我不相信这给了我想要的东西。 INNER JOIN 会给我 Person 和 Clothes 之间的匹配项。如果任何一方有更多或更少的属性,那么那些将不在结果集中,而匹配的将在结果集中。除非双方的所有属性都匹配,否则我不想要任何行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-07
  • 2018-11-05
  • 1970-01-01
  • 2017-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多