简体   繁体   English

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

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

I have a table with colors: 我有一张桌子有颜色:

COLORS

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

And I have another table with data: 我还有另一个数据表:

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     

I just want return rows from Products when the idColor values from table Colors (4, 5, 6) are present in the second table and IdCategory has exactly 3 elements with the same idColor values 4, 5, 6 . 当第二个表中存在表Colors (4、5、6)的idColor值并且IdCategory具有3个具有相同idColor4, 5, 6元素时,我只想从Products返回行。

For this example, The query should return: 对于此示例,查询应返回:

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

Try this: 尝试这个:

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

Here is a demo for you to try. 这是一个演示供您尝试。

UPDATED 更新

If you want to dynamically filter the results depending on the values of the table `COLOR 如果要根据表`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)

Here is a fiddle with this example. 这是一个摆弄这个例子的东西。

You can use aggregates to make sure it has all 3 colors, and also to make sure it DOESN'T have any other colors. 您可以使用聚合来确保它具有所有三种颜色,也可以确保它没有任何其他颜色。 Something like this: 像这样:

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

Note, if the 4, 5, 6 is found more than once per idCategory then a different technique must be employed. 注意,如果在每个idCategory中多次发现4、5、6,则必须采用其他技术。 But from your example, it doesn't appear that way. 但是从您的示例来看,情况并非如此。

I am guessing that you would like to perform this task based on data in a table, rather than hardcoding the values 4, 5, and 6 (like in some of the answers given). 我猜想您希望基于表中的数据执行此任务,而不是对值4、5和6进行硬编码(就像在给出的某些答案中一样)。 To that end, in my solution I created a dbo.ColorSets table that you can fill with as many different sets of colors as you want, then run the query and see all the product Categories that match those color Sets. 为此,在我的解决方案中,我创建了一个dbo.ColorSets表,您可以根据需要填充许多不同的颜色集,然后运行查询并查看与这些颜色集匹配的所有产品类别。 The reason I didn't just use your dbo.Color table is that it appeared to be the lookup table, complete with color names, so it didn't seem like the right one to be picking out a particular set of colors rather than the entire list possible. 我之所以不只是使用dbo.Color表,是因为它看起来像是查找表,并带有颜色名称,因此,选择特定的颜色而不是正确的颜色似乎并不是一个正确的选择完整列表。

I used a technique that will maintain good performance even on huge amounts of data, as compared to other query methods that use aggregates exclusively. 与仅使用聚合的其他查询方法相比,我使用了一种即使在海量数据上也能保持良好性能的技术。 No matter what method one uses, this task will pretty much always require a scan of the entire Products table because you can't compare all the rows without, well, comparing all the rows. 无论使用哪种方法,此任务几乎总是需要扫描整个Products表,因为如果没有比较所有行,就无法比较所有行。 But the JOIN is on indexable columns and is only for the candidates that have a very good chance of being proper matches, so the amount of work required is greatly reduced. 但是JOIN位于可索引列上,仅适用于极有可能成为正确匹配项的候选人,因此所需的工作量大大减少了。

Here's what the ColorSets table looks like: 这是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
;

And the query ( see this working in a SqlFiddle ): 和查询( 请参见在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
   )
;

Result: 结果:

idSet  idCategory
 1       1
 2       3
 1       4

If I understand your question, this should do it 如果我理解您的问题,就应该这样做

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