如何生成两个字母数字值之间的数字范围?
How to generate a range of numbers between two alphanumeric values?
我有两个字母数字作为用户输入,例如 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
这些输入值的长度大小不一。其中一些在字母表后有前导零,有些则没有。
这并不像看起来那么容易。字符串前缀的长度可能会有所不同;数字部分可能有前导零。
这是一种使用递归查询的方法。这个想法是首先将 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)
。
| res |
| :------- |
| WAC01001 |
| WAC01002 |
| WAC01003 |
| WAC01004 |
| WAC01005 |
| WAC01006 |
| WAC01007 |
| WAC01008 |
| WAC01009 |
| WAC01010 |
| WAC01011 |
| WAC01012 |
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,这样查询就不会很快。
我有两个字母数字作为用户输入,例如 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
这些输入值的长度大小不一。其中一些在字母表后有前导零,有些则没有。
这并不像看起来那么容易。字符串前缀的长度可能会有所不同;数字部分可能有前导零。
这是一种使用递归查询的方法。这个想法是首先将 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)
。
| res | | :------- | | WAC01001 | | WAC01002 | | WAC01003 | | WAC01004 | | WAC01005 | | WAC01006 | | WAC01007 | | WAC01008 | | WAC01009 | | WAC01010 | | WAC01011 | | WAC01012 |
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,这样查询就不会很快。