select * from
(select 0 as hour
union select 2 union select 4 union select 6 union select 8
union select 10 union select 12 union select 14 union select 16
union select 18 union select 20 union select 22 union select 24) hours
go
在上面的代码中,"小时"包含 2 的倍数小时。我需要写一些sql语句,如上面的例子,这些语句之间的区别在于它们是其他数字的倍数,例如3或4的倍数。所以我想用参数优化上面的sql语句,就像下面的伪代码一样:
#Below code creates "hours" with multiple of 3 from 0 to 24.
parameter = 3
select * from
(select 0 as hour
union select parameter union select 2*parameter union select 3*parameter
... ...
union select 24) hours
go
但是我不知道如何用sql编写它,你能帮我吗?谢谢。
您可以使用递归 CTE:
with hours as (
select 0 as hh
union all
select hh + @param
from cte
where hh + @param < 24
)
select *
from hours;
如果您愿意,可以将其放入用户定义的表值函数中。 然后你可以称之为:
select . . .
from dbo.Hours(2) h(hh);
注意:hour
是SQL Server中的保留字,因此我更喜欢使用hh
作为列的名称。
我认为这应该是一个简单的表格和模数(%(的教科书用例。没有必要使用递归 CTE。我希望我的解决方案表现良好,而且很简单。
DECLARE @InputNum INT = 2 /*Sample parameter*/
SELECT hr
FROM (
/*Values should probably be put into a physical table*/
VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23),(24)
) AS A(hr)
WHERE hr % @InputNum = 0
返回:
hr
0
2
4
6
8
10
12
14
16
18
20
22
24
如果我正确阅读了您的问题,这将起作用:
对数字使用堆叠 cte(公用表表达式(:
declare @everyN int = 3;
declare @maxN int = 24;
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, numbers as (
select n = row_number() over(order by (select 1))-1
from n as deka cross join n as hecto cross join n as kilo
--cross join n as tenK cross join n as hundredK
)
select n
from numbers
where n <= @maxN
and n % @everyN = 0;
Rextester 演示:http://rextester.com/PHZDZA97504
返回:
+----+
| n |
+----+
| 0 |
| 3 |
| 6 |
| 9 |
| 12 |
| 15 |
| 18 |
| 21 |
| 24 |
+----+
对于任何类型的序列,在数据库中有一个所谓的"Tally"表都是有意义的。计数表仅包含从 0 到 x 的数字(例如 100'000(。基于此,您可以创建所需的任何类型的序列,无论是"3 小时",例如您的案例或日期范围或其他数字范围。您将使用如下所示的计数表:
select Id * 3
from dbo.Tally
where Id * 3 <= 24;
或更好:
select Id * 3
from dbo.Tally
where Id <= 8;
当您需要在给定的开始日期和结束日期之间创建日期范围时,这非常有用:
select dateadd(day, Id, StartDate)
from dbo.Tally
where dateadd(day, Id, StartDate) <= EndDate;