SQL ALL IN子句

时间:2015-04-07 11:53:48

标签: sql sql-server sql-server-2008

我一直在寻找这个,但没有找到任何特别的东西。

是否可以使用一个像ALL IN一样的SQL查询?为了更好地解释,这是一个表结构。

Orders table
OrderItem table (having several columns, but mainly ProductID, OrderID)
ProductGroup table (several columns, but mainly GroupID and ProductID)

我想编写一个查询,它将选择属于特定ProductGroup的所有订单。所以,如果我有一个名为" XYZ" ID = 10。它有一个ProductID。说ProductID01

订单包含两个订单商品。 ProductID01和ProductID02。要查找特定产品组中的所有订单,我可以使用简单的SQL,如

SELECT bvc_OrderItem.ProductID, bvc_OrderItem.OrderID
From bvc_OrderItem
INNER JOIN bvc_Product_Group_Product with (nolock) ON bvc_OrderItem.ProductID = bvc_Product_Group_Product.ProductID 
WHERE bvc_Product_Group_Product.GroupID = 10

或者我可以使用IN Clause编写

SELECT bvc_OrderItem.ProductID, bvc_OrderItem.OrderID
From bvc_OrderItem
WHERE ProductID IN (
    SELECT ProductID FROM bvc_Product_Group_Product WHERE GroupID=10
)

但是,这将返回一个或多个ProductID属于产品组的所有订单。如果所有订单商品都是产品组的一部分,我需要返回订单行

所以基本上,我需要一个IN子句,如果IN子句中的所有值都与bvc_OrderItem中的行匹配,则认为是匹配的。

或者如果我们使用Join,那么只有当左侧的所有行在相应的右表中都有值时,才能成功加入。

如果我能更简单地写它,我会像这样写

Select ID FROM Table WHERE ID IN (1, 2, 3, 4)

如果表包含所有带有id 1,2,3,4的行;它应该回归成功。如果缺少任何这些IN值,它应该返回false并且不应该选择任何内容。

你认为有可能吗?或者有一种解决方法可以做到这一点?

2 个答案:

答案 0 :(得分:3)

您可以通过多种方式获取订单列表,例如:

SELECT oi.OrderID
FROM bvc_OrderItem oi JOIN
     bvc_Product_Group_Product pgp
     ON oi.ProductID = pgp.ProductId AND
        pgp.GroupID = 10
GROUP BY oi.OrderID
HAVING COUNT(DISTINCT oi.ProductID) = (SELECT COUNT(*)
                                       FROM bvc_Product_Group_Product
                                       WHERE GroupID = 10
                                      );

获取特定产品需要额外join。在大多数情况下,订单列表更有用。

ALL IN语法的问题在于它没有做你想做的事。您想要选择订单。语法:

SELECT bvc_OrderItem.ProductID, bvc_OrderItem.OrderID
From bvc_OrderItem
WHERE ProductID ALL IN (SELECT ProductID
                        FROM bvc_Product_Group_Product
                        WHERE GroupID = 10
                       )

这并未指定您打算将分组设为OrderId,而不是其他某个级别。

但更基本的是,SQL语言的灵感来自关系代数。 SELECTJOINWHEREGROUP BY的结构与关系代数基本结构直接相关。 ALL IN的概念 - 尽管有时很有用 - 可以使用更基本的构建块来表达。

答案 1 :(得分:0)

你可以通过这个棘手的声明来做到这一点:

DECLARE @Items TABLE
    (
      OrderID INT ,
      ProductID INT
    )
DECLARE @Groups TABLE
    (
      ProductID INT ,
      GroupID INT
    )

INSERT  INTO @Items
VALUES  ( 1, 1 ),
        ( 1, 2 ),
        ( 2, 1 ),
        ( 3, 3 ),
        ( 3, 4 )

INSERT  INTO @Groups
VALUES  ( 1, 10 ),
        ( 2, 10 ),
        ( 3, 10 ),
        ( 4, 15 )


SELECT  OrderID
FROM    @Items i
GROUP BY OrderID
HAVING  ( CASE WHEN 10 = ALL ( SELECT   gg.GroupID
                               FROM     @Items ii
                                        JOIN @Groups gg ON gg.ProductID = ii.ProductID
                               WHERE    ii.OrderID = i.OrderID ) THEN 1
               ELSE 0
          END ) = 1

输出:

OrderID
1
2

另外(这是更好的):

SELECT  OrderID
FROM    @Items i
        JOIN @Groups g ON g.ProductID = i.ProductID
GROUP BY OrderID
HAVING  MIN(g.GroupID) = 10
        AND MAX(g.GroupID) = 10