【问题标题】:SQL-Query - finding pattern of another tableSQL-Query - 查找另一个表的模式
【发布时间】:2023-03-31 00:51:01
【问题描述】:

我有一张带颜色的桌子:

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 个元素具有相同的idColor 时,我只想从Products 返回行值4, 5, 6

对于这个例子,查询应该返回:

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

【问题讨论】:

  • 请问什么版本的 SQL Server?

标签: sql sql-server comparison


【解决方案1】:

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

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

【讨论】:

  • 这也返回 3、5 和 6。
【解决方案2】:

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

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...当数据在表中并且可能在下次他想要运行查询时改变时,这怎么可能是 OP 想要的?
【解决方案3】:

试试这个:

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你试试。

更新

如果要根据表`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 这个例子。

【讨论】:

  • +1 我喜欢这种语法。动态生成IN 列表时,比我的回答更简洁——不必提供两次。
  • @EliGassert 你的回答也很好,所以也给你 +1 给 OP 不同的选择
  • 但是您已经硬编码了值4, 5, 6...当数据在表中并且可能在下次他想要运行查询时更改时,这怎么可能是 OP 想要的?
  • @ErikE 在他的示例中,我实际上并没有认为COLORS 表的值只是(4,5,6),我将该表视为具有所有可用颜色的表。现在我真的不知道这些值需要硬编码或从COLORS 表中检索
  • @ErikE 也许是,也许不是。我们需要 op 来澄清他的问题
【解决方案4】:

我猜您希望根据表格中的数据执行此任务,而不是硬编码值 4、5 和 6(就像给出的某些答案一样)。为此,在my solution 中,我创建了一个dbo.ColorSets 表,您可以根据需要填充任意多组不同的颜色,然后运行查询并查看与这些颜色组匹配的所有产品类别。我不只是使用您的 dbo.Color 表的原因是它似乎是查找表,并带有颜色名称,所以它似乎不适合挑选一个 特定的集合 em> 颜色而不是整个列表。

与仅使用聚合的其他查询方法相比,我使用了一种即使在处理大量数据时也能保持良好性能的技术。无论使用哪种方法,此任务几乎总是需要扫描整个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
;

还有查询(see this working in a 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-14
    • 1970-01-01
    • 2018-07-08
    • 1970-01-01
    • 1970-01-01
    • 2013-12-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多