问题描述
我从这个 Question 中得到了一些帮助,仍然需要一些进一步的帮助。
我们如何编写一个 sql 函数,它可以只为状态为“A”的 ID 生成 Next Sequence_Code。
注意:如果表已经有Some Sequence_Code,就应该保持原样,不应该有任何变化,但如果表中没有Sequence_Code, 然后函数应该生成下一个 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。
我的表是“LoadData”:
Sequence_Code | ID | Current_Year | Record_Date | 状态 |
---|---|---|---|---|
17AA | 310001 | 2017 | 2017-01-01 | S |
18AB | 310002 | 2018 | 2018-02-22 | S |
19AC | 310003 | 2019 | 2019-02-10 | S |
公元20年 | 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 | 状态 |
---|---|---|---|---|
17AA | 310001 | 2017 | 2017-01-01 | S |
18AB | 310002 | 2018 | 2018-02-22 | S |
19AC | 310003 | 2019 | 2019-02-10 | S |
公元20年 | 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),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,ld.*
from (select ld.*,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 是一个 dbfiddle。
,您需要为当前条件应用 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
是用行号生成的,按照列 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