我有一个包含 SQL Server 2016 的多个字段的视图,如果确定条件满足,我想要输入一个序列号。 举例来说,请考虑此表:
表格:
GLOBALID | SERVICE_GLOBALID | PHOTO_A_GLOBALID | PHOTO_B_GLOBALID
---------+------------------+------------------+-----------------
EB8F9BE7 | 0CD85BE7 | 490794EC | 181C5426
EB8F9BE7 | 04405456 | C3A75999 | 5BA26B15
ECF5F7D1 | 8E8A63C2 | 1A225178 | NULL
ECF5F7D1 | 4EB18887 | 2139CF18 | C7B96E0E
一些细节:
GLOBALID
可以重复(因为这是来自多个表CROSS APPLY
和OUTER APPLY
)的视图; SERVICE_GLOBALID
永远不会重复; PHOTO_A_GLOBALID
总是有值(永不重复); PHOTO_B_GLOBALID
可以有一个值,但有时候是NULL
(在有值时不会重复)。因此,我想为PHOTO_A_GLOBALID
和PHOTO_B_GLOBALID
添加序号,但序列号必须使用视图中的两列。如果PHOTO_B_GLOBALID
为NULL
,则序号不得递增。
这是我想要的结果(请看第三行):
结果
GLOBALID | SERVICE_GLOBALID | PHOTO_A_GLOBALID | PHOTO_B_GLOBALID | SEQ_A | SEQ_B
---------+------------------+------------------+------------------+-------+------
EB8F9BE7 | 0CD85BE7 | 490794EC | 181C5426 | 1 | 2
EB8F9BE7 | 04405456 | C3A75999 | 5BA26B15 | 3 | 4
ECF5F7D1 | 8E8A63C2 | 1A225178 | NULL | 5 | NULL
ECF5F7D1 | 4EB18887 | 2139CF18 | C7B96E0E | 6 | 7
我尝试过使用ROW_NUMBER(),但我真的不知道如何用两列来做这件事。
答案 0 :(得分:2)
试试这个:
rextester:http://rextester.com/IPBQPM64562
if exists (select * from tempdb.sys.objects where name like '#global%') begin; drop table #global; end;
if not exists (select * from tempdb.sys.objects where name like '#global%')
begin
create table #global (globalid varchar(32) ,service_globalid varchar(32) ,photo_a_globalid varchar(32) ,photo_b_globalid varchar(32) )
insert into #global values
('EB8F9BE7' ,'0CD85BE7' ,'490794EC' ,'181C5426')
, ('EB8F9BE7' ,'4405456' ,'C3A75999' ,'5BA26B15')
, ('ECF5F7D1' ,'8E8A63C2' ,'1A225178' ,null)
, ('ECF5F7D1' ,'4EB18887' ,'2139CF18' ,'C7B96E0E')
, ('XXXXXXXX' ,'VVVVVVVV' ,'ZZZZAAAA' ,null)
, ('XXXXXXXX' ,'YYYYYYYY' ,'ZZZZBBBB' ,'ZZZZCCCC')
end;
with cte as (
select
globalid
, service_globalid
, photo_globalid=photo_a_globalid
, AorB = convert(char(1), 'A')
from #global
union all
select
globalid
, service_globalid
, photo_globalid=photo_b_globalid
, AorB = convert(char(1), 'B')
from #global
where photo_b_globalid is not null
)
, x as (
select
globalid
, service_globalid
, photo_globalid
, seq = row_number() over (order by globalid asc, service_globalid, AorB asc)
from cte
)
select
g.globalid
, g.service_globalid
, g.photo_a_globalid
, g.photo_b_globalid
, seq_a = xa.seq
, seq_b = xb.seq
from #global g
left join x as xa on g.globalid=xa.globalid and g.service_globalid=xa.service_globalid and g.photo_a_globalid=xa.photo_globalid
left join x as xb on g.globalid=xb.globalid and g.service_globalid=xb.service_globalid and g.photo_b_globalid=xb.photo_globalid
order by g.globalid, g.service_globalid
答案 1 :(得分:1)
正如其他答案所示,有不止一种方法可以做到这一点,但对我来说最直接的翻译是使用count
函数计算:
select *,
case
when PHOTO_A_GLOBALID is not null
then count(PHOTO_A_GLOBALID)
over (order by DATE rows unbounded preceding)
+ count(PHOTO_B_GLOBALID)
over (order by DATE rows between unbounded preceding and 1 preceding)
end,
case
when PHOTO_B_GLOBALID is not null
then count(PHOTO_A_GLOBALID)
over (order by DATE rows unbounded preceding)
+ count(PHOTO_B_GLOBALID)
over (order by DATE rows unbounded preceding)
end
from t;
基本思路是计算当前行所见的所有PHOTO_A_GLOBALID
值,以及直到当前行所见的所有PHOTO_B_GLOBALID
值,只需稍微调整即可确保当前行和#39; PHOTO_B_GLOBALID
值不会影响SEQ_A
的计算值。
现在,您可以通过PHOTO_A_GLOBALID
永远不会NULL
的知识来缩短这一点,但在我看来,对于这两个列具有相同的逻辑使查询更容易理解。
您还可以在指定rows unbounded preceding
时order by
是默认值的情况下缩短这一点,但您需要明确rows between unbounded preceding and 1 preceding
位。
答案 2 :(得分:0)
这有点棘手。我建议做一个累积和和一些额外的算术:
select t.*,
(sum(incThisRow) over (order by globalid, service_globalid) - incThisRow + 1
) as seq_A,
(case when photo_b_globalid is not null
then sum(incThisRow) over (order by globalid, service_globalid)
end) as seq_B
from (select t.*,
(case when PHOTO_B_GLOBALID is null then 1 else 2 end) as incThisRow
from t
) t;
答案 3 :(得分:0)
你可以......
UNTESTED
With CTE AS (
SELECT GLOBALID, SERVICE_GLOBALID, PHOTO_A_GLOBALID, 'a' as RowID
union
SELECT GLOBALID, SERVICE_GLOBALID, PHOTO_B_GLOBALID, 'b'),
CTE2 as (
SELECT A.*, row_number() over order by (date) RN
FROM CTE A
WHERE PHOTO_B_GLOBALID is not null)
SELECT A.*, B.PHOTO_B_GLOBALID, A.RN as SEQ_A, B.RN as SEQ_B
FROM cte A
LEFT JOIN CTE2 B
on A.GLOBALID =B.GLOBALID
and A.SERVICE_GLOBALID = B.SERVICE_GLOBALID
and A.RowID = 'a'
and b.rowID = 'b'
答案 4 :(得分:0)
你可以尝试这样......
;WITH cte
AS (SELECT *, RowN = ROW_NUMBER() OVER (ORDER BY (SELECT NULL) )
FROM (SELECT GLOBALID, SERVICE_GLOBALID, PHOTO_A_GLOBALID
FROM yourglobal WHERE PHOTO_A_GLOBALID IS NOT NULL
UNION ALL
SELECT GLOBALID, SERVICE_GLOBALID, PHOTO_B_GLOBALID
FROM yourglobal WHERE PHOTO_B_GLOBALID IS NOT NULL) a)
SELECT
yg.*, c.RowN AS SEQ_A, cb.RowN AS SEQ_B
FROM yourglobal yg
LEFT JOIN cte c
ON yg.PHOTO_A_GLOBALID = c.PHOTO_A_GLOBALID
LEFT JOIN cte cb
ON yg.PHOTO_B_GLOBALID = cb.PHOTO_A_GLOBALID