有没有办法为 SQL 中的特定 ID 生成下一个字母 'Sequence Code'?

Is there any way to generate Next Alphabetic 'Sequence Code' For Specific ID's In SQL?

我从中得到了一些帮助,还需要一些进一步的帮助。

我们如何编写一个 SQL 函数,它可以只为那些具有状态 'A' 的 ID 生成下一个 Sequence_Code。

注意:如果Table已经有一些Sequence_Code,应该是这样,不应该有任何变化,但是如果Sequence_Code在table, 那么函数应该生成下一个 Sequence_Code。即在生成 Sequence_Code 之前,它 应该检查前一个 Sequence_Code,然后它应该生成下一个。 对于每个新 ID(状态为 'A'),它应该生成下一个 Sequence_Code.

字母表 'Sequence_Code' 必须是 'Current_Year' 的最后两位数字和 2 个字符字母表的组合,例如 AA、AB、AC....AZ, BA、BB、BC……BZ。 CA,CB,CC....

例如:如果Current_Year是2017,那么Sequence_Code应该是17AA。

我的 table 是 'LoadData':

Sequence_Code ID Current_Year Record_Date Status
17AA 310001 2017 2017-01-01 S
18AB 310002 2018 2018-02-22 S
19AC 310003 2019 2019-02-10 S
20AD 310004 2019 2019-02-20 A
20AE 310005 2020 2020-03-20 S
NULL 310006 2020 2020-04-20 A

预期输出为:

Sequence_Code ID Current_Year Record_Date Status
17AA 310001 2017 2017-01-01 S
18AB 310002 2018 2018-02-22 S
19AC 310003 2019 2019-02-10 S
20AD 310004 2019 2019-02-20 A
20AE 310005 2020 2020-03-20 S
20AF 310006 2020 2020-04-20 A

有方便的方法请指教

您需要为当前条件应用 WHERE 子句:

WITH cte AS (SELECT *, ROW_NUMBER() OVER (ORDER BY Record_Date) rn FROM LoadData)
UPDATE cte
SET Sequence_Code = RIGHT(Current_Year, 2) + 
    CHAR(ASCII('A') + rn / 26 + CASE rn % 26 WHEN 0 THEN -1 ELSE 0 END) + 
    CHAR(ASCII('A') - 1 + CASE rn % 26 WHEN 0 THEN 26 ELSE rn % 26 END) 
WHERE Status = 'A' AND Sequence_Code IS NULL

Sequence_Code 是根据 table 中每一行的行号,按列 Current_Year 的顺序生成的。

参见demo
结果:

> Sequence_Code |     ID | Current_Year | Record_Date | Status
> :------------ | -----: | -----------: | :---------- | :-----
> 17AA          | 310001 |         2017 | 2017-01-01  | S     
> 18AB          | 310002 |         2018 | 2018-02-22  | S     
> 19AC          | 310003 |         2019 | 2019-02-10  | S     
> 19AD          | 310004 |         2019 | 2019-02-20  | A     
> 20AE          | 310005 |         2020 | 2020-03-20  | S     
> 20AF          | 310006 |         2020 | 2020-04-20  | A 

这个比较复杂。我将从生成所有对到两个字符开始。然后执行以下操作:

  • 按字母顺序列举所有代码。
  • 查找当前使用的最大代码。
  • 枚举没有序号的行
  • 匹配回枚举代码。

这适用于任意数量的 NULL 个值。

作为 select,这看起来像:

with alphas as (
      select convert(char(1), 'A') as chr
      union all
      select char(ascii(chr) + 1)
      from alphas
      where chr < 'Z'
     ),
     alpha2 as (
      select concat(a1.chr, a2.chr) as alpha2, row_number() over (order by a1.chr, a2.chr) as seqnum
      from alphas a1 cross join alphas a2
     )
select lda.*, alpha2.alpha2
from (select row_number() over (order by Current_Year, id) as seqnum, alpha2.seqnum as alpha2_maxseqnum, ld.*
      from (select ld.*, max(right(ld.Sequence_Code, 2)) over () as max_seq2
            from loaddata ld 
           ) ld join
           alpha2
           on alpha2.alpha2 = max_seq2
      where ld.Sequence_Code is null
     ) lda join
     alpha2 
     on lda.seqnum = alpha2.seqnum - lda.alpha2_maxseqnum ;

作为 update:

with alphas as (
      select convert(char(1), 'A') as chr
      union all
      select char(ascii(chr) + 1)
      from alphas
      where chr < 'Z'
     ),
     alpha2 as (
      select concat(a1.chr, a2.chr) as alpha2, row_number() over (order by a1.chr, a2.chr) as seqnum
      from alphas a1 cross join alphas a2
     ),
     toupdate as (
      select lda.*, alpha2.alpha2
      from (select row_number() over (order by Current_Year, id) as seqnum, alpha2.seqnum as alpha2_maxseqnum, ld.*
            from (select ld.*, max(right(ld.Sequence_Code, 2)) over () as max_seq2
                  from loaddata ld 
                 ) ld join
                 alpha2
                 on alpha2.alpha2 = max_seq2
            where ld.Sequence_Code is null
           ) lda join
           alpha2 
           on lda.seqnum = alpha2.seqnum - lda.alpha2_maxseqnum 
      )
update toupdate
    set Sequence_Code = concat(right(current_year, 2), alpha2);

Here 是一个 db<>fiddle.