【问题标题】:The recursive coalesce challenge递归合并挑战
【发布时间】:2013-04-11 02:19:05
【问题描述】:

我有一张包含Product 记录和Model 记录的表格。产品和型号记录都有 QTYSize 列。对于给定的product_id,我想从Model 记录中获取所有qtyssizes,并将它们放入**parent 的single* qty and size 字段 Product 记录,由管道“|”分隔。这是我到目前为止的sql。它成功地从给定 product_id 的模型记录中获取大小和数量值,但我无法让它更新父产品记录字段,并递归执行。有人可以帮帮我吗?谢谢

本示例使用 product_id '26206'

--declare local variables
DECLARE
      @size_DelimitedString VARCHAR(MAX),
      @qty_DelimitedString VARCHAR(MAX)

 --pivot rows into delimited string
SELECT
      @size_DelimitedString = COALESCE(@size_DelimitedString, '') + CONVERT(VARCHAR(10), [BD New Product Data].model_size) + '|'
FROM
      [BD New Product Data]
      where record_type = 'model' and product_id = '26206'

 SELECT
      @qty_DelimitedString = COALESCE(@qty_DelimitedString, '') + CONVERT(VARCHAR(10), [BD New Product Data].model_quantity) + '|'
FROM
      [BD New Product Data]
      where record_type = 'model' and product_id = '26206'

--trim off last pipe
SET @size_DelimitedString = (SELECT SUBSTRING(@size_DelimitedString, 1, LEN(@size_DelimitedString)-1))
SET @qty_DelimitedString = (SELECT SUBSTRING(@qty_DelimitedString, 1, LEN(@qty_DelimitedString)-1)) 

--show results  
SELECT @size_DelimitedString 
SELECT @qty_DelimitedString 

【问题讨论】:

  • 什么 RDBMS 和版本? Oracle 支持 WM_CONCAT,它可以在 10g 或更早的版本中轻松执行此操作,而 LIST_AGG 或 XML_AGG 通过将多行组合为 1 来消除递归部分。SQL Server 这是我的猜测,这是...使用 XML Path 这是有点复杂,但可以工作example
  • 我正在使用 MS SQL 2012.Microsoft SQL Server Management Studio 11.0.2100.60 Microsoft 数据访问组件 (MDAC) 6.1.7601.17514 Microsoft MSXML 3.0 4.0 5.0 6.0 Microsoft Internet Explorer 9.10.9200.16540 Microsoft .NET Framework 4.0 .30319.296 操作系统 6.1.7601
  • 完全没有压力,但是meta.stackexchange.com/questions/10672/…。 :)

标签: sql sql-server sql-server-2012 recursive-query coalesce


【解决方案1】:
SELECT 
   product_id
 , STUFF((
    SELECT '|' + CONVERT(VARCHAR(10), A.model_size)
    FROM [BD New Product Data] A 
    WHERE A.record_type = 'model' AND A.product_id = T.product_id
    FOR XML PATH(''), TYPE
   ).value('.', 'VARCHAR(MAX)'), 1, 1, '') AS product_sizes
 , STUFF((
    SELECT '|' + CONVERT(VARCHAR(10), A.model_quantity)
    FROM [BD New Product Data] A 
    WHERE A.record_type = 'model' AND A.product_id = T.product_id
    FOR XML PATH(''), TYPE
    ).value('.', 'VARCHAR(MAX)'), 1, 1, '') AS product_quantities
FROM [BD New Product Data] T 
WHERE T.record_type = 'product' 
 --AND T.product_id = '26206'

【讨论】:

  • 这太棒了!谢谢。那么我将如何将其作为更新语句来更新产品记录中的 qty 和 size 字段呢?
  • 抱歉没有解释,时间紧迫。谁知道为什么 T-SQL 不提供类似 WM_CONCAT 的聚合函数,但事实并非如此。令人高兴的是,事实证明FOR XML PATH('') 可以用来完成同样的事情。所以上面使用 XML 生成连接字符串,然后只使用 STUFF() 删除打开管道,返回最终字符串。要更新您的数量和大小字段,只需将 SELECT 更改为 UPDATE,例如 UPDATE T SET product_size = STUFF(...), product_quantity = STUFF(...) FROM [BD New Product Data] T WHERE T.record_type = 'product'
  • 最后遗漏了什么?更新 T Set T.size = STUFF(( SELECT '|' + CONVERT(VARCHAR(10), A.model_size) FROM [dbo].[BD 新产品数据测试] A WHERE A.record_type = 'model' AND A. product_id = T.sku FOR XML PATH(''), TYPE ).value('.', 'VARCHAR(MAX)'), 1, 1, '') , T.qty = STUFF(( SELECT '|' + CONVERT(VARCHAR(10), A.model_quantity) FROM [dbo].[BD 新产品数据测试] A WHERE A.record_type = 'model' AND A.product_id = T.sku FOR XML PATH(''), TYPE ) .value('.', 'VARCHAR(MAX)'), 1, 1, '') FROM [dbo].[BD Active Test] T WHERE T.sku = A.product_id
  • 为了让它在 T 中更新所有产品记录,其中 t.sku = a.product_id
【解决方案2】:
USE Prod
Update dbo.[BD Active Test]
 Set dbo.[BD Active Test].size = STUFF((
    SELECT '|' + CONVERT(VARCHAR(10), [dbo].[BD New Product Data Test].model_size)
    FROM [dbo].[BD New Product Data Test] 
    WHERE [dbo].[BD New Product Data Test].record_type = 'model' AND [dbo].[BD New Product Data Test].product_id = dbo.[BD Active Test].sku
    FOR XML PATH(''), TYPE
   ).value('.', 'VARCHAR(MAX)'), 1, 1, '')
 , dbo.[BD Active Test].qty = STUFF((
    SELECT '|' + CONVERT(VARCHAR(10), [dbo].[BD New Product Data Test].model_quantity)
    FROM [dbo].[BD New Product Data Test] 
    WHERE [dbo].[BD New Product Data Test].record_type = 'model' AND [dbo].[BD New Product Data Test].product_id = dbo.[BD Active Test].sku
    FOR XML PATH(''), TYPE
    ).value('.', 'VARCHAR(MAX)'), 1, 1, '')
from dbo.[BD Active Test]
INNER JOIN dbo.[BD New Product Data Test] ON dbo.[BD Active Test].sku = dbo.[BD New Product Data Test].product_id 
where dbo.[BD New Product Data Test].record_type = 'PRODUCT' 

【讨论】:

  • 我很困惑,这个[BD Active Test] 表和原始帖子中的sku 列在哪里?就您的问题的解决方案而言,这个答案似乎与我的答案相同。
  • 我忽略了我正在更新另一个表的事实。这成功了.. 感谢您的帮助。