SQL:如何同时获取匹配和不匹配记录

Posted

技术标签:

【中文标题】SQL:如何同时获取匹配和不匹配记录【英文标题】:SQL: How to get both match and non-match records 【发布时间】:2019-02-13 12:38:16 【问题描述】:

我有一个包含以下字段的表格。

    订单编号 物品编号

我的表有以下条目。

我想比较两个 OrderId 并获得一个结果,以了解两个 Order 中存在哪些 ItemId,哪些不存在。

我需要的结果如下。

ItemId: 200 存在于两个订单中。

ItemId: 201 存在于 100 中,而不存在于 101 中

ItemId: 202 和 203 存在于 101 中,而不存在于 100 中。

我不确定这是否可以通过 SQL 完成。

任何帮助将不胜感激。提前致谢。

用于测试的 SQL 脚本:

Create table #Orders(OrderId INT, ItemId INT) Insert into #Orders Select 100, 200 Insert into #Orders Select 100, 201 Insert into #Orders Select 101, 200 Insert into #Orders Select 101, 202 Insert into #Orders Select 101, 203

【问题讨论】:

“我不确定这是否可以通过 SQL 完成” - 几乎所有你想做的事情都可以在 SQL 中完成^^ 总是两个订单吗?您想比较两个订单的所有组合吗? 是的。我想比较两个订单。 请通过编辑而非 cmets 进行澄清。请对minimal reproducible example 采取行动并点击谷歌搜索“stackexchange 作业”并展示你能做什么。请使用文本而不是图像/链接作为文本——包括表格和 ERD。仅使用图像来增加文本或提供无法通过文本提供的内容。 【参考方案1】:

您需要先发送CROSS JOIN,然后发送LEFT JOIN 以检查可用性。

当您有多个订单和商品时,您想要的输出不是最好的检查,以下输出应该足够好:

;WITH AllOrders AS
(
    SELECT DISTINCT O.OrderID FROM #Orders AS O
),
AllItems AS
(
    SELECT DISTINCT O.ItemId FROM #Orders AS O
)
SELECT
    OrderId = O.OrderId,
    ItemId = I.ItemId,
    IsItemInOrder = CASE WHEN A.OrderId IS NOT NULL THEN 1 ELSE 0 END
FROM
    AllOrders AS O
    CROSS JOIN AllItems AS I
    LEFT JOIN #Orders AS A ON
        O.OrderId = A.OrderId AND
        I.ItemId = A.ItemId
ORDER BY
    O.OrderId,
    I.ItemId

结果:

OrderId ItemId  IsItemInOrder
100     200     1
100     201     1
100     202     0
100     203     0
101     200     1
101     201     0
101     202     1
101     203     1

【讨论】:

太棒了,有帮助。非常感谢。【参考方案2】:

一种方式...

DECLARE @O1 INT = 100, @O2 INT = 101;

SELECT FirstOrderID = @O1, 
       SecondOrderId = @O2, 
       FirstOrderItemId = MAX(CASE WHEN OrderId =@O1 THEN ItemId END), 
       SecondOrderItemId = MAX(CASE WHEN OrderId =@O2 THEN ItemId END)
FROM  #Orders 
WHERE OrderId IN (@O1, @O2)
GROUP BY ItemId 

【讨论】:

太棒了,按预期工作。非常感谢。【参考方案3】:

如果你只想要两个订单,你可以这样做:

select coalesce(oi1.orderid, 100), coalesce(oi2.orderid, 101), oi1.itemid, oi2.itemid
from (select oi.*
      from orderitems oi
      where oi.orderid = 100
     ) oi1 full join
     (select oi.*
      from orderitems oi
      where oi.orderid = 101
     ) oi2
     on oi2.orderid <> oi1.orderid and
        oi2.itemid = oi1.itemid;

Here 是一个 dbfiddle。

这回答了您提出的问题。如果您想将此推广到更多订单,请提出另一个问题。这并不像您想象的那么容易概括。

【讨论】:

【参考方案4】:

为什么不使用CROSS JOIN

SELECT DISTINCT t.Orderid, tt.ItemID
FROM table t CROSS JOIN
     (SELECT DISTINCT ItemId FROM table t1) t1 LEFT OUTER JOIN
     table tt
     ON tt.Orderid = t.Orderid AND t1.Itemid = tt.ItemId;

如果您比较一个或多个 orderid,您将需要更动态的方法来获得您想要的结果。因此,CROSS JOIN 在这种情况下有助于查找不匹配的 itemid。

【讨论】:

谢谢,没用。【参考方案5】:

正如您所写:“我想比较两个 OrderId,并得到一个结果,以了解两个 Order 中存在哪些 ItemId,哪些不存在。” p>

只需使用INNER JOIN- 结果集将包含两个订单中的所有 ItemID:

      SELECT A.ItemID
        FROM dbo.yourtable A
  INNER JOIN dbo.yourtable B
          ON A.ItemID        = B.ItemID
         AND B.OrderID       = 101
       WHERE A.OrderID       = 100

【讨论】:

谢谢,没用。

以上是关于SQL:如何同时获取匹配和不匹配记录的主要内容,如果未能解决你的问题,请参考以下文章

如何编写oracle SQL查询以特定顺序获取匹配和不匹配的行对(基于键列)

比较两个文件并包括匹配和不匹配记录

如何使用 Exists 语句以及主表上的条件获取匹配记录

在同一个sql连接中获取2个不同的记录行

SQL 获取具有与特定值匹配的最新关联的记录

SQL获取第一个匹配的行