如何在两个字母数字值之间生成一系列数字?

ewm0tg9j  于 2021-07-29  发布在  Java
关注(0)|答案(2)|浏览(307)

我有两个字母数字作为用户的输入,比如wac01001和wac01012。
如何使用sql查询在单独的行中生成这两个值之间的数字?我想要这个

ID
---------
WAC01001
WAC01002
WAC01003
WAC01004
WAC01005
WAC01006
WAC01007
WAC01008
WAC01009
WAC01010
WAC01011
WAC01012

类似地,对于wac01和wac12,预期结果将是

ID
-----
WAC01
WAC02
WAC03
WAC04
WAC05
WAC06
WAC07
WAC08
WAC09
WAC10
WAC11
WAC12

这些输入值的长度大小不同。其中有些字母表后面有前导零,有些则没有。​

qkf9rpyu

qkf9rpyu1#

这并不像看上去那么容易。字符串前缀的长度可能不同;数字部分可能有前导零。
下面是一个使用递归查询的方法。其思想是首先将sring前缀与数字后缀分离(我假设字符串中第一个数字之后的所有内容),然后生成一系列数字,最后连接回字符串(相对于原始字符串的长度)。

declare @str1 nvarchar(max) = 'WAC01001';
declare @str2 nvarchar(max) = 'WAC01012';

with cte as (
    select 
        n,
        cast(substring(@str1, n, len(@str1)) as int) num,
        cast(substring(@str2, n, len(@str2)) as int) end_num,
        left(@str1, n - 1) prefix
    from (select patindex('%[0-9]%', @str1) n) x
    union all
    select 
        n,
        num + 1,
        end_num,
        prefix
    from cte 
    where num < end_num
)
select concat(
    prefix, 
    replicate('0', len(@str1) - n - len(num) + 1),
    num
) res
from cte
order by num

如果需要处理超过100个增量,则需要添加 option (maxrecursion 0) 在查询的末尾。
db小提琴演示:

| res      |
| :------- |
| WAC01001 |
| WAC01002 |
| WAC01003 |
| WAC01004 |
| WAC01005 |
| WAC01006 |
| WAC01007 |
| WAC01008 |
| WAC01009 |
| WAC01010 |
| WAC01011 |
| WAC01012 |
iaqfqrcu

iaqfqrcu2#

DECLARE @v1 varchar(32) = 'WAC01001', 
        @v2 varchar(32) = 'WAC01012';

-- where does the string switch to a numeric sequence?
DECLARE @pos int = PATINDEX('%[0-9]%', @v1);

;WITH y AS
(
    SELECT 
      c = 2+LEN(@v1)-@pos,          -- where sequence starts
      prefix = LEFT(@v1, @pos-1),   -- fixed portion at beginning
      s = SUBSTRING(@v1, @pos, 32), -- start of numeric sequence
      e = SUBSTRING(@v2, @pos, 32)  -- end of numeric sequence
), nums AS
(
    -- recursive CTE to generate all the numbers in the sequence
    SELECT n = TRY_CONVERT(int, s), e FROM y
    UNION ALL SELECT n + 1, e FROM nums WHERE n < e
)
SELECT q.ID FROM nums CROSS APPLY 
(
  SELECT ID = prefix + RIGHT(REPLICATE('0', c) 
    + CONVERT(varchar(11), CONVERT(int, nums.n)), LEN(s))
  FROM y
) AS q
ORDER BY q.ID OPTION (MAXRECURSION 32767);

如果该范围内的值不能超过100个,则可以忽略 OPTION (MAXRECURSION 32767) . 如果该范围内的值可能超过32k,则必须将32767更改为0,并且查询不会很快。

相关问题