使用JOIN和WHERE IN子句进行SQL查询

时间:2014-01-24 23:40:12

标签: sql sql-server-2008 join

更新:最初,我在订单项表中有订单日期并意识到这是一个错误并将其移至订单表。还更新了我的示例查询。遗憾

我正在尝试编写一个查询来加载订单项订单日期在特定日期之后的所有订单,同时加载查询第一部分返回的同一产品的所有其他订单。也许一个例子可以帮助

CREATE TABLE DemandOrder 
(OrderId INT, OrderDate date, Customer VARCHAR(25))
CREATE TABLE LineItem 
(OrderId INT, LineItemId INT, ProductId VARCHAR(10))

INSERT INTO DemandOrder VALUES(1, '01/23/2014', 'ABC');
INSERT INTO DemandOrder VALUES(2, '01/24/2014', 'DEF');
INSERT INTO DemandOrder VALUES(3, '01/24/2014', 'XYZ');
INSERT INTO DemandOrder VALUES(4, '01/23/2014', 'ABC');

INSERT INTO LineItem VALUES(1, 1, 'A');
INSERT INTO LineItem VALUES(1, 2, 'C');
INSERT INTO LineItem VALUES(2, 1, 'B');
INSERT INTO LineItem VALUES(3, 1, 'A');
INSERT INTO LineItem VALUES(4, 1, 'C');

在上面的示例中,我需要查询订单日期在01/24或之后的所有订单以及可能具有查询第一部分返回的所有其他订单。结果应该是订单1,2和& 3

这是更新的sql代码(使用下面帖子中的ErikE建议)

SELECT
 DISTINCT O.*
 FROM
 dbo.[DemandOrder] O
 INNER JOIN dbo.LineItem LI
  ON O.OrderID = LI.OrderID
 WHERE
 EXISTS (
  SELECT *
  FROM
     dbo.DemandOrder O2 INNER JOIN
     dbo.LineItem L2 ON O2.OrderId = L2.OrderId
  WHERE
     O2.OrderDate >= '01/24/2014'
     AND LI.ProductID = L2.ProductID -- not clear if correct
);

感谢您的帮助和建议

6 个答案:

答案 0 :(得分:1)

您也可以使用窗口功能执行此操作:

select o.*
from (Select o.*,
             max(li.OrderDate) over (partition by li.product) as maxProductOrderDate
      from Order o INNER JOIN
           LineItem li
           ON o.OrderId = li.OrderId
     ) o
where o.maxProductOrderDate >= '2014-01-24';

在外部查询中,您实际上可能需要select distinct,以防止一个订单在给定日期之后发运多个产品时出现重复。

至于您的查询,您可以简化它,因为您不需要子查询中的order表,除非您需要它用于过滤目的:

SELECT o.*
FROM Order o INNER JOIN
     LineItem li
     ON o.OrderId = li.OrderId
WHERE li.Product IN (SELECT li.Product
                     FROM LineItem li
                     WHERE li.OrderDate >= '2014-01-24'
                    );

您可能希望在外部查询中使用select distinct o.*,以避免在订单包含两个或更多符合条件的产品时出现重复。

答案 1 :(得分:1)

您也可以使用窗口功能执行此操作:

select o.*
from (Select o.*,
             max(li.OrderDate) over (partition by li.product) as maxOrderDate
      from Order o INNER JOIN
           LineItem li
           ON o.OrderId = li.OrderId
     ) o
where o.maxOrderDate >= '2014-01-24';

在外部查询中,您实际上可能需要select distinct,以防止一个订单在给定日期之后发运多个产品时出现重复。

至于您的查询,您可以简化它。不需要order表:

SELECT o.*
FROM Order o INNER JOIN
     LineItem li
     ON o.OrderId = li.OrderId
WHERE li.Product IN (SELECT li.Product
                     FROM LineItem li and li.OrderDate >= '2014-01-24'
                    );

答案 2 :(得分:1)

要获得每个订单包含1行的结果集(意味着您对订单项数据不感兴趣,只需订单摘要),这样的事情应该是这样的:

select o.*
from ( select distinct OrderId
       from dbo.LineItem t1
       where exists ( select *
                      from dbo.LineItem t2
                      where t2.Product = t1.Product
                        and t2.OrderDate >= @SomeLowerBoundDateTimeValue
                    )
     ) t
join dbo.Order o on o.OrderId  = t.OrderId

from子句中的第一项是派生表,其中包含与产品关联的订单ID集合,该产品是指定日期或之后的订单的一部分。完成后,剩下的就是琐事:只需加入订单表。

通常,为了提高性能,您希望使用[not] exists (...)的相关子查询优先于[not] in (...)的不相关子查询。

exists尽快短路; in没有,因为它必须构造子查询的整个结果集。

答案 3 :(得分:0)

首先我猜你的结果应该是OrderId:2和3因为OrderDate是01/24 ......

如果您想获得该结果,可以尝试这样做。

    Select o1.OrderId,o1.CustomerName,l1.OrderDate,l1.ProductId
    from Order o1 INNER JOIN
         LineItem l1
         ON o1.OrderId = l1.OrderId
    where l1.OrderDate >= '01/242014'

希望这有效并解决您的问题。

问候!!!

答案 4 :(得分:0)

我相信这将接近你正在寻找的东西。

所有订单中至少有一个productID与1/24/2014或更高版本的订单中的任何产品ID匹配。

SELECT
   O.*
FROM
   dbo.[Order] O
   INNER JOIN dbo.LineItem LI
      ON O.OrderID = LI.OrderID
WHERE
   EXISTS (
      SELECT *
      FROM
         dbo.LineItem L2
         INNER JOIN dbo.LineItem L3
            ON L2.ProductID = L3.ProductID
         INNER JOIN dbo.[Order] O2
            ON L3.OrderID = O2.OrderID
      WHERE
         O2.OrderDate >= '20140124'
         AND O.OrderID = L2.OrderID
   )
;

答案 5 :(得分:0)

我相信这就是你要找的东西。

以下是发生的事情:

  • JOIN LineItem liBase:根据MinDate规范
  • 从LineItem获取初始记录
  • JOIN LineItem liMatches:使用初始JOIN中收集的ProductID自行加入LineItem表
  • JOIN LineItem projection:使用从上一个JOIN中收集的OrderID,从LineItem表中获取记录(在另一个自我JOIN中)
  • SELECT projection.*:projection是我们追求的结果集。选择他们

以下是查询:

;WITH parms (
    MinDate
) AS (
    SELECT CONVERT(DATETIME, '01/24/2014')
)

SELECT projection.* 
FROM parms p 
JOIN LineItem liBase
    ON liBase.OrderDate >= p.MinDate
JOIN LineItem liMatches 
    ON liMatches.ProductId = liBase.ProductId
JOIN LineItem projection
    ON projection.OrderId = liMatches.OrderId
ORDER BY projection.OrderId
;

相同的查询,但生成数据(生成您在问题中提供的LineItem和Order数据集)。

;WITH parms (
    MinDate
) AS (
    SELECT CONVERT(DATETIME, '01/24/2014')
)

, LineItem ( 
      OrderId
    , LineItemID
    , OrderDate
    , ProductId 
) AS (
    SELECT 1, 1, CONVERT(DATETIME, '01/23/2014'), 'B' UNION 
    SELECT 4, 1, CONVERT(DATETIME, '01/23/2014'), 'C' UNION 
    SELECT 2, 1, CONVERT(DATETIME, '01/24/2014'), 'A' UNION 
    SELECT 3, 1, CONVERT(DATETIME, '01/24/2014'), 'B'
) 

, [Order] (
      OrderId
    , CustomerName
) AS (
    SELECT 1, 'ABC' UNION
    SELECT 2, 'XYZ' UNION
    SELECT 3, 'DEF'
)

SELECT projection.* 
FROM parms p 
JOIN LineItem liBase
    ON liBase.OrderDate >= p.MinDate
JOIN LineItem liMatches 
    ON liMatches.ProductId = liBase.ProductId
JOIN LineItem projection
    ON projection.OrderId = liMatches.OrderId
ORDER BY projection.OrderId
;