【问题标题】:generate new column using other columns使用其他列生成新列
【发布时间】:2011-05-17 20:16:46
【问题描述】:

我无法生成一个新列。该表有三列(C_ID、C_rank、Date)。

C_ID C_ Rank NewColumn(Cycle) Date
 42     A        1            October 14, 2010
 42     B        1            October 26, 2010
 42     A        2            February 16, 2011

 43     A        1            December 17, 2010

 44     A        1            July 28, 2010
 44     B        1            August 10, 2010
 44     A        2            January 11, 2011
 44     B        2            January 28, 2011

 45     A        1            July 30, 2010
 45     B        1            August 9, 2010
 45     B        1            September 24, 2010
 45     A        2            April 5, 2011
 45     B        2            April 26, 2011

我想再生成一个名为Cycle 的列,这样对于每个C_ID,它应该生成从一开始的数字并从下一个C_rank = 'A' 开始递增数字(如上所示)。

我尝试使用 row_number,但没有成功。

也许一些循环选项直到下一个C_Rank = 'A' 有效。

如何做到这一点?

【问题讨论】:

  • 我一直追到 '45 组中的几行。 45 B 1 September 24, 20101 不应该是2 吗? 45 B 2 April 26, 2011 不应该是 3 吗?

标签: tsql


【解决方案1】:

您应该能够使用ROW_NUMBER()PARTITION BY 完成此操作

;WITH YourDataCTE AS
(
   SELECT
      C_ID, C_Rank, Date,
      ROW_NUMBER() OVER(PARTITION BY C_ID,C_Rank ORDER BY Date DESC) AS 'Cycle'
   FROM
      dbo.YourTable
)
SELECT *
FROM YourDataCTE

这是否符合您的要求??

PARTITION BY C_ID,C_Rank 将导致ROW_NUMBER 对于C_ID,C_Rank 的每个不同值再次从 1 开始 - 我不知道单个分区中的 ORDER BY 子句(C_ID,C_Rank 的单个值)您正在寻找并且只是猜测它可能是Date DESC(最新日期优先)。

【讨论】:

  • 这会为C_ID, Rank 组中的每一行分配递增的数字。不是问题所要求的
  • @Andomar: 嗯....是的,似乎 OP 的要求比这更复杂....不确定如何轻松满足该要求....
【解决方案2】:

您可以在子查询中计算之前A 的数量:

select  *
,       (
        select  count(*)
        from    @YourTable yt2
        where   yt2.C_ID = yt1.C_ID
                and yt2.C_Rank = 'A'
                and yt2.Date <= yt1.Date
        ) as Cycle
from    @YourTable yt1
order by
        C_ID, Date

Example at ODATA.

【讨论】:

    【解决方案3】:

    对具有相同 C_ID、上一个日期和 C_Rank='A' 的所有记录进行自联接并计算它们。

    select t1.C_ID, t1.C_Rank, count(t2.C_Rank) Cycle, t1.Date
    from MyTable t1
      left join MyTable t2 on t1.C_ID=t2.C_ID
                          and t2.Date<=t1.Date
                          and t2.C_Rank='A'
    group by t1.C_ID, t1.C_Rank, t1.Date
    order by t1.C_ID, t1.Date
    

    【讨论】:

    • 谢谢 Chezy,你说得对,计数器会降低性能!!您的代码也可以与我的要求一起使用,并且执行时间更短。谢谢
    【解决方案4】:

    以下代码满足要求:

    create table #Temp_Table
    (
    C_ID int
    , C_Rank char(1)
    , Date datetime
    , NewColumn int
    )
    
    insert into #Temp_Table
    (
    C_ID
    , C_Rank
    , Date
    )
    select 42, ‘A’, ’10/14/2010′
    union all
    select 42, ‘B’, ’10/26/2010′
    union all
    select 42, ‘B’, ’10/14/2010′
    union all
    select 42, ‘C’, ’10/26/2010′
    union all
    select 42, ‘A’,’02/16/2011′
    union all
    select 43, ‘A’, ’12/17/2010′
    union all
    select 44, ‘A’, ’07/28/2010′
    union all
    select 44, ‘B’, ’08/10/2010′
    union all
    select 44, ‘A’, ’01/11/2011′
    union all
    select 44, ‘B’, ’01/28/2011′
    union all
    select 44, ‘C’, ’10/14/2010′
    union all
    select 44, ‘D’, ’10/26/2010′
    
    Select ‘Original Data’ Comment
    ,*
    from #Temp_Table
    
    /*
    This would be Actual Script to get the New ID based on information you provided
    */
    Declare @Count int
    ,@C_ID int
    ,@C_Rank char(1)
    ,@total_Count int
    ,@Count_Partition int
    ,@Previous_ID int 
    
    Declare @Table Table (ID int IDENTITY(1,1), C_ID int, C_Rank char(1), Date datetime, NewColumn int )
    
    Set @Count = 1
    Set @Count_Partition = 0
    
    insert into @Table
    Select *
    from #Temp_Table 
    
    Select @total_Count = ISNULL(MAX(ID),0)
    from @Table
    
    While @Count < = @total_Count
    Begin
    Select @C_ID = C_ID
    ,@C_Rank = C_Rank
    From @Table
    Where ID = @Count
    
    If @Count = 1
    Set @Previous_ID = @C_ID
    
    If @Previous_ID != @C_ID
    Set @Count_Partition = 1
    
    Else If @C_Rank = 'A'
    Set @Count_Partition = @Count_Partition + 1
    
    update @Table
    Set NewColumn = @Count_Partition
    Where ID = @Count
    
    Set @Previous_ID = @C_ID
    Set @Count = @Count + 1
    End 
    
    Select C_ID
    , C_Rank
    , [Date]
    , NewColumn
    from @Table
    
    –Drop table #Temp_Table 
    

    【讨论】:

    • 我使用计数器来获取循环值。
    • 在 SQL 中确实应该避免这样的循环。尝试在几千条记录上运行它,你就会明白我的意思了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-04
    • 1970-01-01
    • 2021-12-09
    • 2017-10-23
    • 2021-10-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多