基于具有序列的条件递增计数器
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于具有序列的条件递增计数器相关的知识,希望对你有一定的参考价值。
我试图根据一些标准自动增加SELECT查询的计数器。
当BatchID和Reference值发生变化时,应该有一个计数器增加1。
在BatchID保持不变的情况下,它应该只使用2个潜在的唯一数字,一个用于有参考值的地方,另一个用于没有参考值的地方。我在下面的示例数据中添加了一个列,其中包含ExpectedResultCounter,它显示了我期望的结果。
我已成功通过以下查询获得编号:
select
NEXT VALUE FOR seqAutoNumber OVER (ORDER BY RowFilter) AS ID,
*
from
(
select
DENSE_RANK() OVER (ORDER BY BatchID, ContainsValue) AS RowFilter,
ExpectedResultCounter,
BatchID,
Reference
from
(
select CASE WHEN Reference is null then 1 else 0 END as ContainsValue, *
from #Temp
) a
)
b
order by
BatchID,
Reference
但是我不能让序列号与RowFilter匹配相同的编号,并且在给定的情况下它会坚持相同的编号。如果我尝试PARTITION BY,我会收到以下错误:
Msg 11716, Level 15, State 1, Line 41
NEXT VALUE FOR function does not support the PARTITION BY clause.
有人有任何想法吗?是否可以使用序列重复使用相同的数字?如果没有,那么在每次运行查询时不需要重新使用先前执行的先前数字时,需要生成一组新数字来解决此问题的好方法是什么。
CREATE SEQUENCE [dbo].[seqAutoNumber]
AS [int]
START WITH 1
INCREMENT BY 1
MINVALUE 1
MAXVALUE 999999
CYCLE
CACHE
GO
Create Table #Temp
(
Reference varchar(50) NULL,
BatchID int,
ExpectedResultCounter int
)
insert into #Temp
(
Reference,
BatchID,
ExpectedResultCounter
)
SELECT 'P044276-8',21416,1 UNION ALL
SELECT 'E3723492-6',21419,2 UNION ALL
SELECT 'A62723432-1',21419,2 UNION ALL
SELECT 'P0402343250-4',21419,2 UNION ALL
SELECT 'P2602348-4',21419,2 UNION ALL
SELECT 'B0110662-2',21419,2 UNION ALL
SELECT 'P3234977-7',21419,2 UNION ALL
SELECT NULL,21419,3 UNION ALL
SELECT NULL,21419,3 UNION ALL
SELECT 'P382342391-1',21419,2 UNION ALL
SELECT NULL,21419,3 UNION ALL
SELECT 'Q234234234-3',21419,2 UNION ALL
SELECT 'E37234234-6',21468,4 UNION ALL
SELECT 'A6232432-1',21468,4 UNION ALL
SELECT 'P04023423450-4',21468,4 UNION ALL
SELECT 'P2623432408-4',21468,4 UNION ALL
SELECT 'B0023423462-2',21468,4 UNION ALL
SELECT NULL,21468,5 UNION ALL
SELECT NULL,21468,5 UNION ALL
SELECT NULL,21468,5 UNION ALL
SELECT NULL,21468,5 UNION ALL
SELECT NULL,21468,5
select * from #Temp
order by ExpectedResultCounter
drop table #Temp
你不能重复使用SEQUENCE
号码。使用它有很多限制和限制。你可以参考NEXT VALUE FOR (Transact-SQL)
您的要求的一个解决方法是将结果放入临时表中。
然后根据BatchID分组生成ID并更新回临时表
update t
set ResultCounter = r.ID
from
(
select BatchID, ID = NEXT VALUE FOR seqAutoNumber OVER (ORDER BY BatchID)
from #Temp
group by BatchID
) r
inner join #Temp t on r.BatchID = t.BatchID
编辑1:
update t
set ResultCounter = r.ID
from
(
select BatchID,
RefIsNull = CASE WHEN Reference IS NULL THEN 1 ELSE 0 END,
ID = NEXT VALUE FOR seqAutoNumber OVER (ORDER BY BatchID)
from #Temp
group by BatchID, CASE WHEN Reference IS NULL THEN 1 ELSE 0 END
) r
inner join #Temp t on r.BatchID = t.BatchID
and (
(r.RefIsNull = 1 and t.Reference is null)
or (r.RefIsNull = 0 and t.Reference is not null)
)
我认为你在那里是99%。有时必须将事物分成多个步骤(子查询)以使SQL执行您希望它执行的操作。
下面的查询具有基于您的样本数据的列ExpectedResultCounter
,以及作为查询中逻辑的最终结果的列ResultCounter
。
回答:
select a.Reference
, a.BatchID
, a.ExpectedResultCounter
, b.ResultCounter
from #temp as a
inner join
(
select distinct t.BatchID
, iif(t.reference is null, 1, 0) as is_ref_null_flg
, dense_rank() over (order by t.BatchId, iif(t.reference is null, 1, 0)) as ResultCounter
from #temp as t
) as b
on a.BatchID = b.BatchID
and iif(a.reference is null, 1, 0) = b.is_ref_null_flg
order by b.ResultCounter
, a.Reference
更新:
为了利用您在问题中定义的sequence
对象,您必须使用下面的逻辑。您的定义将确保您每次都不会返回相同的ResultCounter
值。
select c.BatchID
, c.is_ref_null_flg
, next value for dbo.seqAutoNumber over (order by c.ResultCounterPrelim) as ResultCounter
into #temp_step_one
from (
select distinct t.BatchID
, iif(t.reference is null, 1, 0) as is_ref_null_flg
, dense_rank() over (order by t.BatchId, iif(t.reference is null, 1, 0)) as ResultCounterPrelim
from #temp as t
) as c
select a.Reference
, a.BatchID
, a.ExpectedResultCounter
, b.ResultCounter
from #temp as a
inner join #temp_step_one as b on a.BatchID = b.BatchID
and iif(a.reference is null, 1, 0) = b.is_ref_null_flg
order by b.ResultCounter
, a.Reference
这个修改后的答案被分成两个查询,而不是使用子查询,因为next value for
语法不能在子查询中使用(根据documentation)。
旁注:根据所涉及的数据量,join
的性能可能有点粗糙。
以上是关于基于具有序列的条件递增计数器的主要内容,如果未能解决你的问题,请参考以下文章