使用其他列生成新列
Posted
技术标签:
【中文标题】使用其他列生成新列【英文标题】: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, 2010
。 1
不应该是2
吗? 45 B 2 April 26, 2011
不应该是 3
吗?
【参考方案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 中确实应该避免这样的循环。尝试在几千条记录上运行它,你就会明白我的意思了。以上是关于使用其他列生成新列的主要内容,如果未能解决你的问题,请参考以下文章
使用 UDF 从 Apache Spark 中的其他列创建新列