【问题标题】:Repeat Rows N Times According to Column Value根据列值重复行N次
【发布时间】:2015-10-25 08:51:35
【问题描述】:

我有下表。

Table A:
ID         ProductFK         Quantity       Price
------------------------------------------------
10         1                  2           100
11         2                  3           150
12         1                  1           120
----------------------------------------------

我需要根据数量列值选择重复行 N 次。

所以我需要以下选择结果:

ID        ProductFK         Quantity        Price
------------------------------------------------
10        1                   1          100
10        1                   1          100
11        2                   1          150
11        2                   1          150
11        2                   1          150
12        1                   1          120

【问题讨论】:

    标签: sql sql-server-2008 tsql repeat


    【解决方案1】:

    您可以使用简单的JOIN 来获得所需的结果,如下所示:

    SELECT  t1.*, t2.number + 1 RepeatNumber
    FROM    TableA t1
    JOIN    master.dbo.spt_values t2 ON t2.type = 'P' AND t2.number < t1.Quantity
    

    上述查询以Quantity列中的指定数量重复每条记录。


    master.dbo.spt_values on type = 'P' 的注意事项:
    该表用于获取通过type = 'P'
    条件硬编码在其中的一系列数字。

    【讨论】:

    • 效果很好,简单明了。小编辑 master.dbo.spt_values t2 on t2.type = 'P' and t2.number
    • 这里的问题是它只适用于 2048 条以下的记录。 :(
    • @Barsham,你是对的。但这是小域的简单答案。如果您需要超过 2048 条记录,则必须使用其他一些方式,例如 Recursive CTECROSS JOINmaster.dbo.spt_values 以获得更大的值。
    • 感谢@SiyavashHamdi 的评论。我最终将 JOIN 与系统中包含 100 万条连续记录的现有表一起使用,并且性能更符合我的要求。
    【解决方案2】:

    您可以使用 UNION ALL 使用递归 CTE 来做到这一点:

    ;WITH cte AS
      (
        SELECT * FROM Table1
    
        UNION ALL
    
        SELECT cte.[ID], cte.ProductFK, (cte.[Order] - 1) [Order], cte.Price
        FROM cte INNER JOIN Table1 t
          ON cte.[ID] = t.[ID]
        WHERE cte.[Order] > 1
    )
    SELECT [ID], ProductFK, 1 [Order], Price
    FROM cte
    ORDER BY 1
    

    这是一个有效的SQLFiddle

    Here's a longer explanation of this technique.


    由于您的输入对于此递归来说太大了,您可以使用辅助表来包含“许多”虚拟行,然后为每个输入行使用 SELECT TOP([Order]) (CROSS APPLY):

    ;WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
          E02(N) AS (SELECT 1 FROM E00 a, E00 b),
          E04(N) AS (SELECT 1 FROM E02 a, E02 b),
          E08(N) AS (SELECT 1 FROM E04 a, E04 b),
          E16(N) AS (SELECT 1 FROM E08 a, E08 b)
    SELECT t.[ID], t.ProductFK, 1 [Order], t.Price
    FROM Table1 t CROSS APPLY (
      SELECT TOP(t.[Order]) N
      FROM E16) ca
    ORDER BY 1
    

    (辅助表借用here,每行最多允许65536行,如果需要可以扩展)

    这是一个有效的SQLFiddle

    【讨论】:

    • 我得到这个错误:在语句完成之前最大递归100已经用完
    • 你拥有的最大[Order] 值是多少?
    • 可以用 Cross Apply 实现吗?
    • @franchescototti:使用option maxrecursion
    • @cha - maxrecursion 在这里无济于事。当第一个解决方案中不再需要递归时,递归结束。限制到任何下限都不会产生所需的输出
    【解决方案3】:
    CREATE TAblE #temp
    (
    T_Name      VARCHAR(50),
    T_Times      BIGINT
    )
    
    INSERT INTO #temp(T_Name,T_Times) VALUES ('ASHISH',4)
    INSERT INTO #temp(T_Name,T_Times) VALUES ('PANKAJ',3)
    INSERT INTO #temp(T_Name,T_Times) VALUES ('RUPESH',2)
    INSERT INTO #temp(T_Name,T_Times) VALUES ('MANISH',5)
    
    SELECT t.T_Name ,t.T_Times FROM
    (SELECT  T_Name,T_Times,CAST(('<val>'+REPLICATE(T_Name+'</val><val>',T_Times-1)
    +'</val>') AS XML )AS X FROM #temp)t CROSS APPLY t.X.nodes('/val')y(z)
    
    drop table #temp
    

    【讨论】:

    • 请保持您的答案独立!经常引用您的博客网站几乎是垃圾邮件,在 Stack Overflow 上并没有真正被认为有用。
    猜你喜欢
    • 2019-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-10
    • 2015-06-17
    • 2016-06-27
    相关资源
    最近更新 更多