微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何按 ID 值增加列组?

如何解决如何按 ID 值增加列组?

我有 3 列:ID(Varchar 类型)、Age(INT 类型)和金额($)。真正的表是 100K 行:该表列出了客户在每个年龄段收到的每一笔金额。

ID 年龄 金额
A01 1 10
A01 2 11
A01 3 12
A02 90 50
A02 100 51
A02 110 52

我需要将每个客户的每个年龄增加到 120 并得到这样的结果

ID 年龄 金额
A01 1 10
A01 2 11
A01 3 12
A01 4 13
A01 n+1 ...
A01 120 1500
A02 90 50
A02 100 51
A02 110 52
A02 111 53
A02 n+1 ...
A02 120 600

这是我第一次做循环,经过多次尝试,这是我能写的最好的,但它不起作用。

  SELECT disTINCT [id],[Age],ROW_NUMBER() OVER (PARTITION BY [id] ORDER BY 
     [Age])AS Rnk INTO tableRanked FROM  MyTable
        
           DECLARE @Agefirst AS INT 
           DECLARE @Agelast AS INT 
           DECLARE @AgeCurent AS INT 
           DECLARE @id as nvarchar(max)
               
           SET @Agelast = 120
           SET @id = 0
           SET @AgeCurent = 0
                
           WHILE(@AgeCurent <= @Agelast)
           BEGIN
           SET @AgeCurent = @AgeCurent+1                
           INSERT INTO tableRanked ([Id],[Age])
           SELECT [Rnk],[Id],[Age] FROM  tableRanked 
            SET @id = @id+1

            END

非常感谢!

解决方法

您可以使用 numbers function,or tally table 代替循环(或递归 CTE,它也是一个循环)。 Numbers 函数使用的资源很少,而且速度非常快。从您的代码看来,每个 ID 的年龄范围应介于 1 到 120 岁之间。 像这样

;with unq_id(id) as (
    select distinct id
    from MyTable)
insert into tableRanked
select ui.id as ID,fn.n as Age,isnull(m.Amount,0) Amount
from unq_id ui
     cross join dbo.fnTally(1,120) fn
     left join MyTable m on ui.id=m.Id
                            and fn.n=m.Age
order by ui.id,fn.n;
,

我不明白如果每个增加 1,最终金额怎么会是 1500 或 600。但是,如果我认为这是问题中的错误并将其放在一边,我建议您可以在此处使用带有递归 CTE 的 INSERT ... SELECT ...。那么就没有必要在这里摆弄程序代码了。

WITH cte
AS
(
SELECT 1 is_anchor,x.id,x.age,x.amount FROM
       (SELECT r.id,r.age,r.amount,row_number() OVER (PARTITION BY r.id
                                  ORDER BY r.age DESC) r
               FROM tableranked r) x
       WHERE x.r = 1
UNION ALL
SELECT 0 is_anchor,c.id,c.age + 1,c.amount + 1
       FROM cte c
       WHERE c.age + 1 <= 120
)
INSERT INTO tableranked
            (id,age,amount)
SELECT c.id,c.age,c.amount
       FROM cte c
       WHERE c.is_anchor = 0
       OPTION(MAXRECURSION 120);

您可以使用 row_number() 获取锚行,这些是每个 ID 具有最大年龄的行。将它们标记为锚行以在 SELECTINSERT ... SELECT ... 部分将它们过滤掉并且不再插入它们。

db<>fiddle

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。