【问题标题】:SQL Server: Comparing Concatenated Columns for Equality of Unordered SetSQL Server:比较连接列的无序集相等性
【发布时间】:2016-11-05 14:47:55
【问题描述】:

我有两个表,其中包含一个 ID 列(将表匹配在一起)和连接列,其中连接值的顺序是任意的。我想比较两列是否包含完全相同的项目(以任何顺序),如果不包含则输出 ID。

例子:

表 1

PersonID    Products
1           Apple|Pear|Orange
2           Flour|Apple|Butter
3           Apple
4           Banana|Cashews
5           Juice|Crackers|Banana|Cashews
6           Cashews

表 2

PersonID    Products
1           Orange|Apple|Pear
2           Flour|Apple|Butter
3           Apple|Banana
4           Banana
5           Crackers|Juice|Banana|Cashews
6           Pear|Crackers

我想获取表 1 和表 2 之间产品不是相同集合(任何顺序)的所有 personids。所以在这种情况下是: 第 3 个人(额外产品)、第 4 个人(缺失产品)和第 6 个人(不同产品)。

我当前的查询错误地选择了第 1 个人和第 5 个人,因为他们的产品订购方式不同。

我目前的查询是这样的:

select t1.personid, t1.products as t1products, t2.products as t2products
from table1 t1 (nolock)
inner join table2 t2 (nolock) on t1.personid = t2.personid
where t1.products != t2.products

我也有预连接形式的数据,每个 personid 有多行(每个产品一个,然后分别在两个表中),如果这更有帮助 - 我还没有想出如何将它们连接到按字母顺序,所以解决这个问题的方法也可以解决这个问题。

编辑(澄清): 未连接的数据如下所示:

表 1

PersonID    Product
1           Apple
1           Pear
1           Orange
2           Flour
2           Apple
2           Butter
3           Apple

等等

表 2

PersonID    Product
1           Orange
1           Apple
1           Pear
2           Flour
2           Apple
2           Butter
3           Apple
3           Banana

等等

我使用 STUFF 按 PersonID 连接它们。

【问题讨论】:

  • 如果您要走这条路,有多少列产品需要按字母顺序排列?如果只有几列,这就像一些嵌套的 CASE 语句和 >< 运算符一样简单。
  • 产品的结构是多行,而不是列(因此 jobid 在多行上重复)。它们可以从 1 到 300 行,最常见的是每行大约 5-10 行

标签: sql sql-server set concatenation equality


【解决方案1】:

如果您以每行一个产品的形式提供它,那么您可以查询对面表中产品和 personid 都不匹配的所有结果。然后对另一个表执行相同的操作并将结果合并:

SELECT t1.personid, t1.product, '2' AS [Not Found In Table]
FROM table1 t1 
LEFT JOIN table2 t2 ON t1.personid = t2.personid AND t1.product = t2.product
WHERE t2.product IS NULL
UNION
SELECT t2.personid, t2.product,  '1' AS [Not Found In Table]
FROM table2 t2 
LEFT JOIN table1 t1 ON t2.personid = t1.personid AND t2.product = t1.product
WHERE t1.product IS NULL

您可以将其包装在一个选择中并CONCAT 结果为您提供一个很好的列表,其中列出了每个不匹配的人在哪个表中缺少的内容。

【讨论】:

  • 此解决方案确实考虑了产品的顺序。因此,具有完全相同产品但顺序不同的两个人 ID 将显示在结果集中/
  • 我同意 no lock comment bacon ,但我不知道他有什么理由在他的原始查询中包含它们。
  • @M.Ali,如果此查询针对连接的结果运行,它将考虑顺序,但正如答案所述,这旨在针对每行具有一个产品的表运行, 多行表示拥有多个相关产品的人。因为这些是分开的,所以不用担心顺序。
【解决方案2】:

我只是在完全连接时配对行。这样,如果出现pair,则表示产品匹配,如果不出现,则表示存在问题。 所以我希望这个简单的查询也能解决你的问题:

SELECT DISTINCT PersonID FROM (
    SELECT * FROM table1 
    UNION ALL 
    SELECT * FROM table2
) d 
GROUP BY PersonID, Products 
HAVING COUNT(*) != 2

【讨论】:

    【解决方案3】:

    测试数据

    Declare @t1 TABLE (PersonID INT, Products Varchar(200))
    INSERT INTO @t1 VALUES
    (1   ,'Apple|Pear|Orange'),
    (2   ,'Flour|Apple|Butter'),
    (3   ,'Apple'),
    (4   ,'Banana|Cashews'),
    (5   ,'Juice|Crackers|Banana|Cashews'),
    (6   ,'Cashews');
    
    Declare @t2 TABLE (PersonID INT, Products Varchar(200))
    INSERT INTO @t2 VALUES
    (1   ,'Orange|Apple|Pear'),
    (2   ,'Flour|Apple|Butter'),
    (3   ,'Apple|Banana'),
    (4   ,'Banana'),
    (5   ,'Crackers|Juice|Banana|Cashews'),
    (6   ,'Pear|Crackers');
    

    查询

    WITH Table1 AS (
    SELECT  PersonID
            ,Split.a.value('.', 'VARCHAR(100)') Products
    FROM   
        (SELECT PersonID
                ,Cast ('<X>' + Replace(Products, '|', '</X><X>') + '</X>' AS XML) AS Data
        FROM    @t1
        ) AS t CROSS APPLY Data.nodes ('/X') AS Split(a) 
    ), Table2 AS (
    SELECT  PersonID
            ,Split.a.value('.', 'VARCHAR(100)') Products
    FROM   
        (SELECT PersonID
                ,Cast ('<X>' + Replace(Products, '|', '</X><X>') + '</X>' AS XML) AS Data
        FROM    @t2
        ) AS t CROSS APPLY Data.nodes ('/X') AS Split(a) 
    )
    SELECT t1.PersonID 
    FROM Table1 t1
    WHERE NOT EXISTS (SELECT 1 
                      FROM Table2 t2
                      WHERE t1.PersonID = t2.PersonID 
                      AND t1.Products = t2.Products)
    UNION  
    SELECT t2.PersonID 
    FROM Table2 t2
    WHERE NOT EXISTS (SELECT 1 
                      FROM Table1 t1
                      WHERE t1.PersonID = t2.PersonID 
                      AND t1.Products = t2.Products)
    

    【讨论】:

    • 这就是我在阅读关于将数据分成行的部分之前的想象。我很高兴有人做了困难的版本:)
    猜你喜欢
    • 2012-12-26
    • 2010-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-06
    • 2015-09-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多