【问题标题】:Joining parents in 2 tables on exact match of child row values在 2 个表中加入父级以完全匹配子行值
【发布时间】:2012-12-20 08:36:13
【问题描述】:

我有 2 个结构如下的表:

表 1(Tb1):

MasId Int, ItemId int, Quantity int
1          1           10
1          2           5
1          3           18
2          2           3
2          4           8

表 2 (Tb2):

MasId Int, ItemId int, Quantity int
10          1           10
10          2           5
10          3           18
6           2           3
6           4           8

我想将 Tb1 与 Tb2 与 ItemIdQuantity 列进行匹配。并得到以下查询:

Tb1.MasId   Tb2.MasId
1           10
2           6

Table1 和 Table2 包含大约 2000000 条记录。我使用SQL Server 2012

编辑 1

在 Tb1 和 Tb2 中存在如下记录:

Tb1:

MasId, ItemId, Quantity
3      15       10
3      16       2

Tb2:

MasId, ItemId, Quantity
20     15      10
20     18      5

Tb1.MasId 和 Tb2.MasId 不匹配。

【问题讨论】:

  • 注意:选择的答案在某些情况下会给出错误的数据。请查看我对此的评论和我的回答。

标签: sql-server sql-server-2008 sql-server-2008-r2 sql-server-2012


【解决方案1】:

以下查询available as a SqlFiddle 即使数据很复杂也能返回正确的结果:

SELECT
   Tb1MasId = A1.MasId,
   Tb2MasId = B1.MasId
FROM
   (
      SELECT
         MasID,
         Pattern = Checksum_Agg(Binary_Checksum(ItemId, Quantity))
      FROM dbo.Tb1
      GROUP BY MasId
   ) A1
   INNER JOIN (
      SELECT
         MasID,
         Pattern = Checksum_Agg(Binary_Checksum(ItemId, Quantity))
      FROM dbo.Tb2
      GROUP BY MasId
   ) B1
      ON A1.Pattern = B1.Pattern
      AND NOT EXISTS (
         SELECT * 
         FROM
            (
               SELECT A2.ItemID, A2.Quantity
               FROM dbo.Tb1 A2
               WHERE A1.MasID = A2.MasID
               UNION ALL
               SELECT B2.ItemID, B2.Quantity
               FROM dbo.Tb2 B2
               WHERE B1.MasId = B2.MasID
            ) X
         GROUP BY ItemID, Quantity
         HAVING Count(*) = 1
      );

页面上的其他答案使用my SqlFiddle 中的示例数据给出了不正确的结果。具体来说,将以下数据添加到Tb2 将破坏X.L.Ant's current query(由于未检测到8, 3, 18 不属于,这将显示错误匹配2, 8)。

INSERT dbo.Tb2
VALUES
   (7, 1, 10),
   (7, 2, 5),
   (7, 3, 17),
   (8, 3, 18),
   (8, 2, 3),
   (8, 4, 8);

【讨论】:

  • Tb1 和 Tb2 大约有 1000000 行。而且你的查询很慢。我可以有一个性能更好的查询吗?
  • 也许吧。让我想想。了解您的数据特征和索引是必不可少的。每个 MasId 有多少 itemid?平均有多少潜在的不匹配(匹配不属于完全匹配的行)?你的表的每一行有多少字节?是否有父 MasId 表或表?我可能擅长 Sql,但我不是魔术师,需要更多信息。两个表中有多少不同的 MasId?我的查询有多少输出行?
  • 更新:我在this SqlFiddle 为您准备了 2 个新版本。它们仍然是相同的基本方法,但有一些优化应该对 1,000,000 行产生巨大的差异。看来第二个查询可能是最好的,但我没有任何接近你的数据来测试。我仍然需要我的问题的答案,以便我可以设置一个与您的数据有些相似的合理测试用例。我对此有另一个想法,我想探索,但如果没有要测试的数据,这样做是毫无意义的。
  • 谢谢!运行需要多长时间?有机会获得一些真实的测试数据吗?
【解决方案2】:

你也可以像下面这样分组

SELECT Tb1.MasId, Tb2.MasId
       FROM Tb1 
          INNER JOIN Tb2 
             ON Tb1.ItemId = Tb2.ItemId
             AND Tb1.Quantity = Tb2.Quantity
 group by Tb1.MasId, Tb2.MasId

【讨论】:

  • 很遗憾,这不会提供正确的答案。
【解决方案3】:

试试:

SELECT Tb1.MasId AS MasId1, Tb2.MasId AS MasId2
FROM Tb1, Tb2, (SELECT MasId, COUNT(MasId) AS Cnt FROM Tb1 GROUP BY MasId) Cnt
WHERE Tb1.ItemId = Tb2.ItemId
  AND Tb1.Quantity = Tb2.Quantity
  AND Tb1.MasId = Cnt.MasId
GROUP BY Tb1.MasId, Tb2.MasId, Cnt.Cnt
HAVING COUNT(Tb1.MasId) = Cnt.Cnt

SQLFiddle

【讨论】:

  • 请参阅 Edit1。与您的查询无法正确匹配数据。
  • 好的,但是如果另一个表中不存在匹配项,您想如何处理 3,16,2 和 20,18,5 呢?您是否希望它们出现在您的结果中?
  • 我只想查看所有匹配的记录。
  • 所以我提到的查询有效。它只会显示两个表中 itemid 和数量相同的记录中的 masid,并排除不相同的记录。
  • 除非您希望每个 MasId 的所有行都匹配。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-07
  • 2023-01-15
相关资源
最近更新 更多