【问题标题】:SQL: Find all possible combinations/permutations of product option dataSQL:查找产品选项数据的所有可能组合/排列
【发布时间】:2011-06-27 19:50:13
【问题描述】:

我有以下产品数据(用于在线商店):

ProductId  ProductOptionGroupId  ProductOptionId
26         1                     13
26         1                     12
44         1                     22
44         1                     23
44         2                     20
44         2                     21
44         3                     25
44         3                     24

ProductOptionGroup 是(比如说)“Size”或“Color”,ProductOption 是(比如说)“Large”、“Extra Large”和“Red”、“Black”等。

基本上,我想为每种产品找到所有可能的产品选项组合。例如,对于产品 44,我想要:

22, 20, 25  (Large, Black, Cotton)
22, 20, 24  (Large, Black, Nylon)
22, 21, 25  (Large, Red, Cotton)
22, 21, 24  (Large, Red, Nylon)
23, 20, 25  (Extra Large, Black, Cotton)
23, 20, 24  etc...
23, 21, 25
23, 21, 24

每一行的每个产品选项组中只有一个产品选项。 IE。大号和特大号是互斥的。

理想情况下,我希望将这些值连接到每个产品的单个 VARCHAR 中(“22,21,25”等)。

如何在 SQL Server 2005 中实现这一点?

谢谢

【问题讨论】:

  • Cross join 也许?
  • 与您之前的问题重复,包含三个答案,您接受了其中一个。 How to generate all possible data combinations in SQL?
  • 啊。在寻找可能的解决方案时,我不知何故错过了这一点(我完全忘记了我之前曾问过这个问题)。可以说,我从来没有让它工作。要求也略有不同。

标签: sql tsql


【解决方案1】:
WITH
  data (ProductId, ProductOptionGroupId, ProductOptionId) AS (
    /* defining sample data */
    SELECT 26, 1, 13 UNION ALL
    SELECT 26, 1, 12 UNION ALL
    SELECT 44, 1, 22 UNION ALL
    SELECT 44, 1, 23 UNION ALL
    SELECT 44, 2, 20 UNION ALL
    SELECT 44, 2, 21 UNION ALL
    SELECT 44, 3, 25 UNION ALL
    SELECT 44, 3, 24
  ),
  ranked AS (
    /* ranking the group IDs */
    SELECT
      ProductId,
      ProductOptionGroupId,
      ProductOptionId,
      GroupRank = DENSE_RANK() OVER (PARTITION BY ProductId
                                         ORDER BY ProductOptionGroupId)
    FROM data
  ),
  crossjoined AS (
    /* obtaining all possible combinations */
    SELECT
      ProductId,
      GroupRank,
      ProductVariant = CAST(ProductOptionId AS varchar(250))
    FROM ranked
    WHERE GroupRank = 1
    UNION ALL
    SELECT
      r.ProductId,
      r.GroupRank,
      ProductVariant = CAST(c.ProductVariant + ','
        + CAST(r.ProductOptionId AS varchar(10)) AS varchar(250))
    FROM ranked r
      INNER JOIN crossjoined c ON r.ProductId = c.ProductId
                              AND r.GroupRank = c.GroupRank + 1
  ),
  maxranks AS (
    /* getting the maximum group rank value for every product */
    SELECT
      ProductId,
      MaxRank = MAX(GroupRank)
    FROM ranked
    GROUP BY ProductId
  )
/* getting the max ranked combinations for every product */
SELECT c.ProductId, c.ProductVariant
FROM crossjoined c
  INNER JOIN maxranks m ON c.ProductId = m.ProductId
                       AND c.GroupRank = m.MaxRank

输出:

ProductId   ProductVariant
----------- --------------
26          12
26          13
44          22,20,24
44          22,20,25
44          22,21,24
44          22,21,25
44          23,20,24
44          23,20,25
44          23,21,24
44          23,21,25

有用的阅读:

【讨论】:

  • 太棒了!谢谢你。我现在会花一些时间来看看这个,试图了解你是如何解决我的问题的......
  • @Milky Joe:用几个链接更新了答案。很抱歉一开始没有这样做。
  • 如果您在ranked CTE 中计算MaxRank,您可以加快查询速度。
  • 是的,那样可能会更快。但是,您无法在 ranked CTE 中计算 MaxRank。至少除了使用COUNT(DISTINCT …) 作为窗口函数之外,我看不到任何其他方法,并且SQL Server 不支持它(无论如何都不支持2005 版本)。不过,我很乐意了解其他方法。
  • @STiLeTT:是的,我现在可以看到了,谢谢。它可以是派生表,但也可以是另一个 CTE(然后将替换 ranked 作为 crossjoined 的基础)。正如您所说,MaxRank 将简单地在crossjoined 中结转,直到它可以在主 SELECT 中过滤而无需任何连接。而且我刚刚记得我最近看到this DBA.SE answer 提出了一种无需派生表即可计算COUNT(DISTINCT) 的简洁方法,尽管仅适用于非空数据(在这种情况下可能仍然适用)。
【解决方案2】:

示例:

declare @t table(id int, type1 int, type2 int)

insert @t values(1, 1, 1), (1, 1, 2), (1, 2, 1), (2, 2, 1)

select distinct t1.id, t1.type1, t2.type2
from
(
    select id, type1
    from @t
)t1
full join
(
    select id, type2
    from @t
)t2 on t2.id = t1.id

输出:

id          type1       type2
----------- ----------- -----------
1           1           1
1           1           2
1           2           1
1           2           2
2           2           1

【讨论】:

  • 不幸的是,这并没有给我我想要的输出。还是谢谢。
【解决方案3】:

SQL 将取决于您的表结构。如果列存储在单独的表中,那么简单的笛卡尔积(无条件连接)应该会产生所需的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-27
    • 2020-01-27
    • 1970-01-01
    • 2022-01-22
    相关资源
    最近更新 更多