【问题标题】:How to increment column group by an ID Value?如何通过 ID 值增加列组?
【发布时间】:2021-05-07 05:18:55
【问题描述】:

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

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

非常感谢!

【问题讨论】:

  • Doesn't work 不是对错误的有用描述。请描述什么是错误的或你有什么错误。
  • while 无限加载,没有任何增加。
  • 嗯,这就是您在查询中写的:进入一个循环,一次又一次地将数据插入自身。它没有过滤器。不清楚你到底想要什么,但看起来像是一个运行总和,或者某种从当前最大值增加到 120 的额外行
  • @charlieface 嗨,正如我在消息中所说,我完全不知道如何做我想要的结果。我希望每个 ID 的年龄增加 1 直到年龄为 120。然后它转到下一个 ID 并对我拥有的 100K 客户执行相同的操作。我了解如何增加年龄,但如何为每个 ID 执行此操作?我怎样才能拥有 1 个 ID,并且每个年龄递增,然后转到下一个 ID?我不知道该怎么做,这就是我在这里的原因
  • 你能更好地定义你需要什么吗?对于每个 ID,您需要从 1 开始到 120 的行,还是从第一个可用的 Age 或最后一个可用的 Age 开始?

标签: sql sql-server sql-server-2012


【解决方案1】:

我不明白如果每个增加 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 的最大年龄。将它们标记为锚行以在INSERT ... SELECT ...SELECT 部分中将它们过滤掉,并且不要再次插入它们。

db<>fiddle

【讨论】:

  • 嗨,非常感谢您的回答。我显示的金额只是一个示例,以显示我拥有什么样的数据,金额不应该增加。我对 cte 不熟悉,所以我会检查您的操作并尝试了解您的逻辑以及查询失败的原因和原因
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2023-01-27
    • 1970-01-01
    • 1970-01-01
    • 2011-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多