根据行的分组搜索行

时间:2018-02-16 14:27:16

标签: sql-server tsql sql-server-2016

前言,我不确定这个问题是否有意义。

问题陈述

我有一个看起来像这样的表:

+----------------+-----------+
| ProductGroupID | ProductID |
+----------------+-----------+
|              1 |         1 |
|              1 |         2 |
|              2 |         3 |
|              2 |         4 |
|              3 |         1 |
|              3 |         2 |
|              4 |         1 |
|              4 |         2 |
|              4 |         3 |
+----------------+-----------+

我要做的是查找包含ProductGroupID 1和2的所有ProductID

期望输出

+----------------+
| ProductGroupID |
+----------------+
|              1 |
|              3 |
|              4 |
+----------------+

我的尝试

下面是我创建的一个天真的脚本,但我认为它可以大大改进。

SELECT DISTINCT ProductGroupID
FROM
    (SELECT ProductGroupID FROM tbl WHERE ProductID = 1 ) t1 
INNER JOIN
    (SELECT ProductGroupID FROM tbl WHERE ProductID = 2 ) t2
ON t1.ProductGroupID = t2.ProductGroupID

出于某种原因,我的直觉告诉我CROSS APPLY在这种情况下可能有用,但我似乎无法解释这个问题。

任何帮助将不胜感激。

附录

如果您可以生成一个显示ProductGroupID的脚本,其中只显示1和3,并且忽略4,因为它在集合中有一个额外的项目。

1 个答案:

答案 0 :(得分:3)

如何使用HAVING

WITH VTE AS(
    SELECT *
    FROM (VALUES (1,1),
                 (1,2),
                 (2,3),
                 (2,4),
                 (3,1),
                 (3,2),
                 (4,1),
                 (4,2),
                 (4,3)) V(ProductGroupID, ProductID))
SELECT ProductGroupID
FROM VTE
GROUP BY ProductGroupID
HAVING COUNT(CASE ProductID WHEN 1 THEN 1 END) >0
   AND COUNT(CASE ProductID WHEN 2 THEN 1 END) >0;

如果你想忽略ProductIDGroup 4,那么:

WITH VTE AS(
    SELECT *
    FROM (VALUES (1,1),
                 (1,2),
                 (2,3),
                 (2,4),
                 (3,1),
                 (3,2),
                 (4,1),
                 (4,2),
                 (4,3)) V(ProductGroupID, ProductID))
SELECT ProductGroupID
FROM VTE
GROUP BY ProductGroupID
HAVING COUNT(CASE ProductID WHEN 1 THEN 1 END) >0
   AND COUNT(CASE ProductID WHEN 2 THEN 1 END) >0
   AND COUNT(CASE WHEN ProductID NOT IN (1,2) THEN 1 END) = 0;