如何通过 ID 值增加列组?

How to increment column group by an ID Value?

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

ID Age Amount
A01 1 10
A01 2 11
A01 3 12
A02 90 50
A02 100 51
A02 110 52

我需要将每个客户的每个年龄增加到 120 并得到类似这样的东西

ID Age Amount
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

非常感谢!

我不明白如果每个增加1,最终数量可以是1500或600。但是,如果我认为这是问题中的错误并将其搁置一旁,我建议您可以在此处使用 INSERT ... SELECT ... 和递归 CTE。那么这里就没有必要 fiddle 处理程序代码了。

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 具有最大年龄的行。将它们标记为锚行以在 INSERT ... SELECT ...SELECT 部分将它们过滤掉,并且不要再次插入它们。

db<>fiddle

您可以使用 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;