我正在尝试根据某些条件自动为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
答案 0 :(得分:2)
您不能重复使用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)
)
答案 1 :(得分:1)
我认为您的存在率为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
的性能可能有些粗糙。