【问题标题】:Get all possible concatenations获取所有可能的连接
【发布时间】:2011-11-01 16:25:34
【问题描述】:

我有一个继承的数据库,需要创建一个查询来生成 SKU 的所有可能变体。一个表具有“基本”SKU,另一个表具有所有 SKU 修饰符。

示例

基础 SKU:MARIN 可以修改为

MARINR15 MARINB15 MARING15 MARINR17 MARINB17 MARING17 MARINR19 MARINB19 MARING19 MARINR20 MARINB20 MARING20

基本 SKU

ProductID   SKU
----------- ---------------
532         MARIN

SKU 修饰符

ProductID   OptionName           OptionValue              SkuModifier
----------- -------------------- ------------------------ -----------
532         Color                Red                      R
532         Color                Green                    G
532         Color                Blue                     B
532         Size                 17"                      17
532         Size                 15"                      15
532         Size                 19"                      19
532         Size                 20"                      20

【问题讨论】:

  • 这不够通用,或者您的问题不够清晰。您似乎要添加OptionValue 的第一个字符,其中OptionName 是颜色,但如果OptionName 是大小,则添加OptionValue 的数字部分。你还有哪些OptionNames,他们是如何对待的?
  • 抱歉,格式似乎关闭了,并且“SkuModifier”列已关闭。这些值来自“SkuModifier”列。
  • @Bryan - 您是否(可能)拥有超过 2 组修饰符 - 或者只是与此处列出的修饰符不同的修饰符?以及如何确定修饰符的顺序(串联顺序)?
  • @X-Zero 有可能存在一组或多组修饰符。如果所有可能的组合都在那里,订单并不是什么大问题,因为我有另一个表,其中包含来自我们仓库的数据,其中包含所有修改后的 SKU,但没有 ProductID。
  • @Bryan - 我想没有order 是有道理的,因为有些产品可能不需要特定的修饰符(......您希望如何处理这些修饰符?)。请注意,您最终会得到一个大的中间集。但如果 的情况......什么决定了获取 SKU 时要使用的“规范”排序(保持两个 SKU 具有相同的修饰符,但顺序不同)?

标签: sql tsql concatenation skus


【解决方案1】:
DROP TABLE #Base
DROP TABLE #Modifiers

CREATE TABLE #Base
(
    ProductId int,
    SKU varchar(32)
)

CREATE TABLE #Modifiers
(
    ProductId int,
    OptionName varchar(32),
    OptionValue varchar(32),
    SKUModifier varchar(32)
)

INSERT INTO #Base
SELECT 532, 'MARIN'

INSERT INTO #Modifiers
SELECT 532, 'Color', 'Red', 'R' UNION ALL
SELECT 532, 'Color', 'Green', 'G' UNION ALL
SELECT 532, 'Color', 'Blue', 'B' UNION ALL
SELECT 532, 'Size', '17"', '17' UNION ALL
SELECT 532, 'Size', '15"', '15' UNION ALL
SELECT 532, 'Size', '19"', '19' UNION ALL
SELECT 532, 'Size', '20"', '20'

SELECT B.SKU + M.SKUModifier + M2.SKUModifier FROM #Base B
    JOIN #Modifiers M ON B.ProductId = M.ProductId AND M.OptionName = 'Color'
    JOIN #Modifiers M2 ON B.ProductId = M2.ProductId AND M2.OptionName = 'Size'

结果:

MARINR17
MARING17
MARINB17
MARINR15
MARING15
MARINB15
MARINR19
MARING19
MARINB19
MARINR20
MARING20
MARINB20

【讨论】:

    【解决方案2】:

    您可以使用递归解决方案(事实上,这可能是唯一可行的答案)。如果您有预定义的顺序,您可能会节省处理(因为目前我能想到的唯一方法是文本连接)。

    这是一个通用解决方案,可以为您提供所需的结果。
    请注意,这是在 DB2 (iSeries) 上编写和运行的 - 您可能需要针对 SQL Server 对其进行调整。

    WITH Combined(productId, options, combination, level) as (
                  SELECT productId, optionName, skuModifier, 1
                  FROM #Modifiers
                  UNION ALL
                  SELECT a.productId, a.options || b.optionName,
                         a.combination || b.skuModifier, a.level + 1
                  FROM Combined as a
                  JOIN #Modifiers as b
                  ON b.productId = a.productId
                  AND a.options not like ('%' || b.optionName || '%')),
         Option_Count(productId, count) as (SELECT productId, COUNT(DISTINCT optionName)
                                            FROM #Modifiers
                                            GROUP BY productId)
    SELECT a.sku || COALESCE(b.combination, '')
    FROM #Base as a
    LEFT JOIN (Combined as b
               JOIN Option_Count as c
               ON c.productId = b.productId
               AND c.count = b.level)
    ON b.productId = a.productId)
    

    产量:

    MARIN17R        
    MARIN15R        
    MARIN19R        
    MARIN20R        
    MARIN17G        
    MARIN15G        
    MARIN19G        
    MARIN20G        
    MARIN17B        
    MARIN15B        
    MARIN19B        
    MARIN20B        
    MARINR17        
    MARING17        
    MARINB17        
    MARINR15        
    MARING15        
    MARINB15        
    MARINR19        
    MARING19   
    MARINB19   
    MARINR20   
    MARING20   
    MARINB20
    

    不过,就我个人而言,我想我会尝试建立某种排序 - 这至少可以让您不再处理 optionName(尽管在这种情况下您可能希望进一步规范化表格)。
    请注意,CTE Option_Count 用于将结果限制为“全长”组合 - 使用所有选项的排列,而不仅仅是其中的一部分。

    【讨论】:

    • 此示例是否特定于某些版本的 SQL Server?我似乎无法让它运行。我在 SQL Server 2005 上。我想我需要替换所有的“||”与 +。之后,我收到有关“选项”列中的锚点和递归部分之间的类型不匹配以及“组合”列中的类型不匹配的错误
    • 啊,抱歉,这在 DB2 上运行得非常好。我认为|| 对于 SQL 上的字符串连接是通用的,我猜不是(DB2 不使用+ - 你有CONCAT() 函数吗?我不知道你为什么会遇到类型不匹配递归查询的错误 - CTE 应该从所选列继承类型。也许您需要将其包装在手动转换为 varchar 或其他东西中?
    【解决方案3】:
    SELECT 
      base.sku+color.SkuModifier+size.SkuModifier 
    FROM base 
    INNER JOIN modifiers as color ON color.OptionName = 'Color'
    INNER JOIN modifiers as size ON size.OptionName = 'Size'
    

    您可能必须处理 OptionValue(例如,从 Size 中删除 " 并从 Color 中获取第一个字母),但这会让您走上正确的道路。

    编辑 -- 感谢您的澄清,我已经更新了 SQL。

    【讨论】:

    • 似乎没问题,但也许base.ProductID = color.ProductIDsize 同样应该添加到连接条件中。你怎么看?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    相关资源
    最近更新 更多