Microsoft SQL Server 如何生成连续的数字/字符/时间序列
有时候我们需要在数据库中生成一些连续的数字、字符或者时间序列值,本文介绍如何在 Microsoft SQL Server 中实现这个功能。
使用系统视图生成序列
生成一个连接的数字序列
select number
from master.dbo.spt_values
where type = 'P'
and number between 11 and 15;
number|
------|
11|
12|
13|
14|
15|
create view generator
as
select t1.number * 2048 + t2.number as number
from master.dbo.spt_values t1
cross join master.dbo.spt_values t2
where t1.type = 'P' and t2.type = 'P';
select min(number) as min, max(number) as max, count(number) as count
from generator;
min|max |count |
---|-------|-------|
|4194303|4194304|
生成一个间隔的数字序列
select number
from master.dbo.spt_values
where type = 'P'
and number between 1 and 10
and number % 3 = 1;
number|
------|
1|
4|
7|
10|
select 15 + number * -2.5 as number
from master.dbo.spt_values
where type = 'P'
and 15 + number * -2.5 >= 1.4;
number|
------|
15.0|
12.5|
10.0|
7.5|
5.0|
2.5|
生成一个连续的字符序列
select char(number) as letter
from master.dbo.spt_values
where type = 'P'
and number between 65 and 70;
letter|
------|
A |
B |
C |
D |
E |
F |
生成一个间隔的时间序列
select dateadd(hour, number, '2020-01-01 00:00:00') as ts
from master.dbo.spt_values
where type = 'P'
and number between and 12;
ts |
-------------------|
2020-01-01 00:00:00|
2020-01-01 01:00:00|
2020-01-01 02:00:00|
2020-01-01 03:00:00|
2020-01-01 04:00:00|
2020-01-01 05:00:00|
2020-01-01 06:00:00|
2020-01-01 07:00:00|
2020-01-01 08:00:00|
2020-01-01 09:00:00|
2020-01-01 10:00:00|
2020-01-01 11:00:00|
2020-01-01 12:00:00|
使用通用表表达式生成序列
生成一个等差数字序列
with t(n) as (
select
union all
select n+2 from t where n < 10
)
select n from t;
n |
--|
|
2|
4|
6|
8|
10|
首先,执行 CTE 中的初始化查询,生成一行数据(0);
然后,次执行递归查询,判断 n < 10,生成一行数据 2(n+2);
接着,重复执行递归查询,生成更多的数据;直到 n = 10 时不满足条件终止递归;此时临时表 t 中包含 6 条数据;
后,执行主查询,返回所有的数据。
生成一个等比数字序列
with t(n) as (
select 1
union all
select n*4 from t where n*4 < 1000
)
select n from t;
n |
---|
1|
4|
16|
64|
256|
生成斐波那契数列
with fibonacci (n, fib_n, next_fib_n) as (
select 1, , 1
union all
select n + 1, next_fib_n, fib_n + next_fib_n
from fibonacci
where n < 10 )
select * from fibonacci;
n |fib_n|next_fib_n|
--|-----|----------|
1| | 1|
2| 1| 1|
3| 1| 2|
4| 2| 3|
5| 3| 5|
6| 5| 8|
7| 8| 13|
8| 13| 21|
9| 21| 34|
10| 34| 55|
生成一个连续的字符序列
with t(n) as (
select 65
union all
select n+1 from t where n < 70
)
select char(n) as letter from t;
letter|
------|
A |
B |
C |
D |
E |
F |
生成一个间隔的时间序列
with ts(v) as (
select cast('2020-01-01 00:00:00' as datetime2)
union all
select dateadd(hour,1, v) from ts where v < cast('2020-01-01 12:00:00' as datetime2)
)
select v from ts;
v |
-------------------|
2020-01-01 00:00:00|
2020-01-01 01:00:00|
2020-01-01 02:00:00|
2020-01-01 03:00:00|
2020-01-01 04:00:00|
2020-01-01 05:00:00|
2020-01-01 06:00:00|
2020-01-01 07:00:00|
2020-01-01 08:00:00|
2020-01-01 09:00:00|
2020-01-01 10:00:00|
2020-01-01 11:00:00|
2020-01-01 12:00:00|
使用表值函数生成序列
创建模拟的 generate_series 表值函数
create or alter function generate_series(@pstart numeric(38,10), @pstop numeric(38,10), @pstep numeric(38,10) = 1.0)
returns @generate_series table(n numeric(38,10))
as
begin
if @pstep = return
if @pstart > @pstop and @pstep > return
if @pstart < @pstop and @pstep < return
;with t(n, v) as (
select 1, @pstart
union all
select n+1, cast(@pstart + n * @pstep as numeric(38,10)) from t where n <= floor(abs((@pstop-@pstart)/@pstep))
)
insert into @generate_series
select v from t
return
end;
使用 generate_series 函数生成序列
select cast (n as integer) as n
from generate_series(11, 15, default);
n |
--|
11|
12|
13|
14|
15|
select n from generate_series(15, 1.4, -2.5);
n |
-------------|
15.0000000000|
12.5000000000|
10.0000000000|
7.5000000000|
5.0000000000|
2.5000000000|
select char(n) as letter
from generate_series(65, 70, 1);
letter|
------|
A |
B |
C |
D |
E |
F |
select dateadd(hour, n, timefromparts(,,,,)) as time
from generate_series(, 12, default);
time |
--------|
00:00:00|
01:00:00|
02:00:00|
03:00:00|
04:00:00|
05:00:00|
06:00:00|
07:00:00|
08:00:00|
09:00:00|
10:00:00|
11:00:00|
12:00:00|
来源 https://mp.weixin.qq.com/s/UuDpM2gmzjpJsOiggr4Slg
相关文章