2015-04-07 143 views
3

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

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

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

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

订单来了两个订单项目。 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子句

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

然而,这将返回所有订单写其中一个或多个ProductIDs是产品组的一部分。如果所有订单项都是产品组的一部分,我需要返回订单行。

所以基本上,我需要一个IN子句,如果IN子句中的所有值都与bvc_OrderItem中的行匹配,那么这个IN子句将被视为匹配。

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

如果我能更简单地写出来,我会写这样

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

,如果表中包含IDS 1,2,3,4的所有行;它应该返回成功。如果这些IN值中的任何一个缺失,它应该返回false并且不应该选择任何值。

你认为这是可能的吗?或者有一个解决方法来做到这一点?

+0

也许你应该改写你的病情为“订单,其中不存在任何行,不属于组X'? – Arvo

+1

这听起来像[关系部门](https://www.simple-talk.com/sql/t-sql-programming/divided-we-stand-the-sql-of-relational-division/) –

+0

我不'不明白你在找什么。有一个或多个项目组成的订单,每个项目都是一个存在于一个组中的产品。因此,您的声明“查找特定产品组中的所有订单...”没有任何意义。订单与产品组无关。对于由属于G组的产品P构成的订单,您是否想要查看仅由G组产品组成的所有其他订单?或者您是否希望看到包含G组的任何*产品的所有订单?你在找什么? – TommCatt

回答

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语言受关系代数的启发。 SELECT,JOIN,WHEREGROUP BY的构造直接涉及关系代数基本构造。 ALL IN的概念 - 尽管有时是有用的 - 可以使用更基本的构建块来表达。

+0

WHERE ProductID ALL IN ......它使用哪个SQL Server版本?我已经在2008年和2008年尝试过了,但对于他们来说这似乎并不是一个有效的选择。 –

+0

此外,使用计数分组(DISTINCT oi.Product)的事情,可能无法正常工作。由于产品组可能有100种产品,订单中可能有两种或四种产品。我们需要确保订单项目都是产品组的一部分。因此,如果两个或所有订单项都是产品组的一部分,我们会将其视为匹配项。如果它们中的任何一个不是该组的一部分,我们将其视为不匹配。谢谢 –

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 
+0

嗨,谢谢你的回复。但是,即使一个产品属于该组,也会返回true。我们需要它,如果所有产品属于该组。我测试了它,即使One ProductID属于产品组,它也会返回orderid。如果只有一个项目属于组,我们需要它不返回OrderID。但只有当所有订单商品(ProductIds)属于该组时。 –

+0

@SameersJaved,你说的不对。在我的数据中有2个产品的Order = 3(3,4)3是10组,4是15组。Order = 3不会返回我的查询。 –