繁体   English   中英

SQL查询-查找另一个表的模式

[英]SQL-Query - finding pattern of another table

我有一张桌子有颜色:

COLORS

idColor   Name
-------   ------
   4      Yellow
   5      Green
   6      Red

我还有另一个数据表:

PRODUCTS

idProduct   idCategory   idColor
---------   ----------   -------
    1           1           4     
    2           1           5     
    3           1           6     
    4           2           10    
    5           2           11    
    6           2           12    
    7           3           4     
    8           3           5     
    9           3           8     
    10          4           4     
    11          4           5     
    12          4           6     
    13          5           4     
    14          6           4     
    15          6           5     

当第二个表中存在表Colors (4、5、6)的idColor值并且IdCategory具有3个具有相同idColor4, 5, 6元素时,我只想从Products返回行。

对于此示例,查询应返回:

IdCategory
----------
    1      
    4      

尝试这个:

SELECT idCategory
FROM PRODUCTS
GROUP BY idCategory
HAVING COUNT(*) = 3
AND COUNT(DISTINCT CASE WHEN idColor IN (4,5,6) THEN idColor END) = 3

这是一个演示供您尝试。

更新

如果要根据表`COLOR'的值动态过滤结果

SELECT idCategory
FROM PRODUCTS P
LEFT JOIN (SELECT idColor, COUNT(*) OVER() TotalColors
           FROM COLORS) C
     ON P.idColor = C.idColor
GROUP BY idCategory
HAVING COUNT(*) = MIN(C.TotalColors)
AND COUNT(DISTINCT C.idColor) = MIN(C.TotalColors)

这是一个摆弄这个例子的东西。

您可以使用聚合来确保它具有所有三种颜色,也可以确保它没有任何其他颜色。 像这样:

SELECT *
FROM
(
SELECT idCategory
  , SUM(CASE WHEN idColor IN (4, 5, 6) THEN 1 ELSE 0 END) AS GoodColors
  , SUM(CASE WHEN idColor NOT IN (4, 5, 6) THEN 1 ELSE 0 END) AS BadColors
FROM Products
GROUP BY idCategory
) t0
WHERE GoodColors = 3 AND BadColors = 0

注意,如果在每个idCategory中多次发现4、5、6,则必须采用其他技术。 但是从您的示例来看,情况并非如此。

我猜想您希望基于表中的数据执行此任务,而不是对值4、5和6进行硬编码(就像在给出的某些答案中一样)。 为此,在我的解决方案中,我创建了一个dbo.ColorSets表,您可以根据需要填充许多不同的颜色集,然后运行查询并查看与这些颜色集匹配的所有产品类别。 我之所以不只是使用dbo.Color表,是因为它看起来像是查找表,并带有颜色名称,因此,选择特定的颜色而不是正确的颜色似乎并不是一个正确的选择完整列表。

与仅使用聚合的其他查询方法相比,我使用了一种即使在海量数据上也能保持良好性能的技术。 无论使用哪种方法,此任务几乎总是需要扫描整个Products表,因为如果没有比较所有行,就无法比较所有行。 但是JOIN位于可索引列上,仅适用于极有可能成为正确匹配项的候选人,因此所需的工作量大大减少了。

这是ColorSets表的外观:

CREATE TABLE dbo.ColorSets (
   idSet int NOT NULL,
   idColor int NOT NULL,
   CONSTRAINT PK_ColorSet PRIMARY KEY CLUSTERED (idSet, idColor)
);

INSERT dbo.ColorSets
VALUES
   (1, 4), 
   (1, 5),
   (1, 6), -- your color set: yellow, green, and red
   (2, 4),
   (2, 5),
   (2, 8)  -- an additional color set: yellow, green, and purple
;

和查询( 请参见在SqlFiddle中的工作 ):

WITH Sets AS (
   SELECT
      idSet,
      Grp = Checksum_Agg(idColor)
   FROM
      dbo.ColorSets
   GROUP BY
      idSet
), Categories AS (
   SELECT
      idCategory,
      Grp = Checksum_Agg(idColor)
   FROM
      dbo.Products
   GROUP BY
      idCategory
)
SELECT
   S.idSet,
   C.idCategory
FROM
   Sets S
   INNER JOIN Categories C
      ON S.Grp = C.Grp
WHERE
   NOT EXISTS (
      SELECT *
      FROM
         (
            SELECT *
            FROM dbo.ColorSets CS
            WHERE CS.idSet = S.idSet
         ) CS
         FULL JOIN (
            SELECT *
            FROM dbo.Products P
            WHERE P.idCategory = C.idCategory
         ) P
            ON CS.idColor = P.idColor 
      WHERE
          CS.idColor IS NULL
          OR P.idColor IS NULL
   )
;

结果:

idSet  idCategory
 1       1
 2       3
 1       4

如果我理解您的问题,就应该这样做

select distinct idCategory
  from Products 
 where idColors in (4,5,6)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM