如何通过 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
部分将它们过滤掉,并且不要再次插入它们。
您可以使用 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;
我有 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
部分将它们过滤掉,并且不要再次插入它们。
您可以使用 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;