【问题标题】:sequential number with some conditions带有某些条件的序号
【发布时间】:2016-12-08 18:46:04
【问题描述】:

我有一个包含多个字段的视图,来自 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 APPLYOUTER APPLY);
  • SERVICE_GLOBALID 永不重复;
  • PHOTO_A_GLOBALID 总是有一个值(从不重复);
  • PHOTO_B_GLOBALID 可以有值,但有时是NULL(有值时从不重复)。

所以,我喜欢为PHOTO_A_GLOBALIDPHOTO_B_GLOBALID 设置一个序号,但序号必须使用视图中的两列。如果PHOTO_B_GLOBALIDNULL,则序号不能递增。

这是我想要的结果(看第三行):

结果

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(),但我真的不知道如何处理两列。

【问题讨论】:

  • 分配的数字在顺序上真的很重要吗?我们如何知道 1,2 集与 3,4 集?
  • @xQbert 我想我不明白你的问题。必须是一个序列,从 1 到无穷大,与行出现的顺序相同(行的顺序是按日期顺序生成此视图)。
  • 你覆盖了它,结果是按日期排序的,因此应该按那个 dat.e 编号

标签: sql sql-server sql-server-2016


【解决方案1】:

试试这个:

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

【讨论】:

  • 不工作!在 rextester 上,将第 3 行中的 ('EB8F9BE7' ,'0CD85BE7' ,'490794EC' , '181C5426') 更改为 ('EB8F9BE7' ,'0CD85BE7' ,'490794EC' , null) 或在 PHOTO_B_GLOBALID 上添加更多 NULLs
【解决方案2】:

正如其他答案所示,有不止一种方法可以做到这一点,但对我来说最直接的翻译是计数,使用 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 值,只需稍作调整以确保当前行的PHOTO_B_GLOBALID 值不会影响 SEQ_A 的计算值。

现在,您可以在知道PHOTO_A_GLOBALID 永远不是NULL 的情况下缩短它,但我认为两列的逻辑相同会使查询更容易理解。

您也可以在指定order by 时知道rows unbounded preceding 是默认值,但您确实需要明确rows between unbounded preceding and 1 preceding 位。

【讨论】:

  • 您的解决方案奏效了!但我不明白你从哪里得到DATE 字段。该字段在视图中不存在。我替换为globalid 并且工作正常。
  • @RobertoCorreia 您对您的问题发表了评论“(行的顺序是按日期顺序生成此视图)”。如果DATE不是用于排序的字段,请使用应该确定顺序的真实字段。
  • stackoverflow 上的示例比真实视图(有 26 列)简单得多。我会尝试使用DATE!谢谢! (更新:与DATE 合作良好)
【解决方案3】:

你可以...

  • 将照片数据还原为两组(A、B)并将它们合并
  • 从 B & Number 中删除空照片的记录
  • 加入基集以获取完整数据

未经测试

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】:

    你可以这样试试……

    ;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
    

    【讨论】:

      【解决方案5】:

      这有点棘手。我建议做一个累积和和一些额外的算术:

      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;
      

      【讨论】:

      • 不工作! seq_a = 1, seq_b = 1, 然后seq_a = 3, seq_b = 3, 最后seq_a = 5, seq_b = NULL
      • @RobertoCorreia 。 . .这似乎是seq_b 上的一个错误。我认为这是解决问题的最简单方法。
      猜你喜欢
      • 2011-08-19
      • 2021-05-22
      • 2014-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-01
      • 2012-06-03
      • 1970-01-01
      相关资源
      最近更新 更多