我需要填充一个表,该表将存储2个给定日期之间的日期范围:09/01/11 - 10/10/11
因此,在这种情况下,该表将从2011年1月9日开始并存储每天直到它到达10/10/11 我想知道在SQL Server中是否有一种灵巧的方式 - 我目前正在使用SQL Server 2008.谢谢
答案 0 :(得分:35)
如果您使用的是SQL Server 2005或更高版本,请尝试此操作:
WITH Dates AS (
SELECT
[Date] = CONVERT(DATETIME,'09/01/2011')
UNION ALL SELECT
[Date] = DATEADD(DAY, 1, [Date])
FROM
Dates
WHERE
Date < '10/10/2011'
) SELECT
[Date]
FROM
Dates
OPTION (MAXRECURSION 45)
一个很好的例子,你可以用CTE做很酷的事情。
答案 1 :(得分:32)
Easy on SQL 2005+;如果您有数字或计数表,则更容易。我把它假装在下面:
DECLARE @StartDate DATE = '20110901'
, @EndDate DATE = '20111001'
SELECT DATEADD(DAY, nbr - 1, @StartDate)
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY c.object_id ) AS Nbr
FROM sys.columns c
) nbrs
WHERE nbr - 1 <= DATEDIFF(DAY, @StartDate, @EndDate)
如果您有一个计数表,请将子查询替换为表。没有递归。
答案 2 :(得分:11)
- 声明
DECLARE @dates TABLE(dt datetime)
DECLARE @dateFrom datetime
DECLARE @dateTo datetime
SET @dateFrom = '2001/01/01'
SET @dateTo = '2001/01/12'
- 查询:
WHILE(@dateFrom < @dateTo)
BEGIN
SELECT @dateFrom = DATEADD(day, 1,@dateFrom)
INSERT INTO @dates
SELECT @dateFrom
END
- 输出
SELECT * FROM @dates
答案 3 :(得分:2)
使用MVJ的F_TABLE_DATE函数,它非常棒:
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=61519
实现此功能后,只需传递开始日期和结束日期,即可插入所有日期。
答案 4 :(得分:2)
这是一个不需要递归的解决方案,同时,这个表值函数可以在许多查询中重用,而无需再次重复声明样板变量。对于那些不想要递归的人来说,这是唯一的选择。
创建这个简单的函数:
CREATE FUNCTION [dbo].[GenerateDateRange]
(@StartDate AS DATE,
@EndDate AS DATE,
@Interval AS INT
)
RETURNS @Dates TABLE(DateValue DATE)
AS
BEGIN
DECLARE @CUR_DATE DATE
SET @CUR_DATE = @StartDate
WHILE @CUR_DATE <= @EndDate BEGIN
INSERT INTO @Dates VALUES(@CUR_DATE)
SET @CUR_DATE = DATEADD(DAY, @Interval, @CUR_DATE)
END
RETURN;
END;
然后选择:
select *
from dbo.GenerateDateRange('2017-01-03', '2017-12-01', 1)
答案 5 :(得分:0)
使用@Abe Miesler的答案,为了方便起见,我将其构建到TVF for SQL Server 2008以后。它可能对其他人有所帮助 - 我必须找到一种方法将CTE纳入TVF!
--Generate a range of dates with interval option, courtesy of Abe Miessler for the core query here!
ALTER FUNCTION [dbo].[DateRange]
(@startDate AS DATE,
@EndDate AS DATE,
@interval AS INT
)
RETURNS @Dates TABLE(dateValue DATE)
AS
BEGIN
WITH Dates
AS (
SELECT [Date] = CONVERT( DATETIME, @startDate)
UNION ALL
SELECT [Date] = DATEADD(DAY, ISNULL(@interval, 1), [Date])
FROM Dates
WHERE Date < @EndDate)
INSERT INTO @Dates
SELECT [Date]
FROM Dates
OPTION(MAXRECURSION 900);
RETURN;
END;
答案 6 :(得分:0)
Declare @StartDate datetime = '2015-01-01'
Declare @EndDate datetime = '2016-12-01'
declare @DaysInMonth int
declare @tempDateRange Table
(
DateFrom datetime,
DateThru datetime
);
While @StartDate<=@EndDate
begin
SET @DaysInMonth=DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,@StartDate),0)))
IF DAY(@StartDate)=1
SET @EndDate=DATEADD(DAY,14,@StartDate)
ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=30
SET @EndDate=DATEADD(DAY,14,@StartDate)
ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=31
SET @EndDate=DATEADD(DAY,15,@StartDate)
ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=28
SET @EndDate=DATEADD(DAY,12,@StartDate)
ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=29
SET @EndDate=DATEADD(DAY,13,@StartDate)
INSERT INTO @tempDateRange (DateFrom,DateThru)
VALUES
(
@StartDate,
@EndDate
)
SET @StartDate=DATEADD(DAY,1,@EndDate)
IF @EndDate< '2016-12-31'
IF DAY(@StartDate)=1
SET @EndDate=DATEADD(DAY,14,@StartDate)
ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=30
SET @EndDate=DATEADD(DAY,14,@StartDate)
ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=31
SET @EndDate=DATEADD(DAY,15,@StartDate)
ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=28
SET @EndDate=DATEADD(DAY,12,@StartDate)
ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=29
SET @EndDate=DATEADD(DAY,13,@StartDate)
end ;
select * from @tempDateRange
+++++++++++++++++++++++++++++
Result:
DateFrom |DateThru
答案 7 :(得分:0)
如果由于某种原因您无法declare
变量,例如在derived tables中使用Looker时,您可以这样:
select
dateadd(day, nbr - 1, convert(date, '2017-01-01')) as d
from (
select row_number() over (order by c.object_id) as nbr from sys.columns c
) nbrs
where
nbr - 1 <= datediff(
day,
convert(date, '2017-01-01'),
convert(date, '2018-12-31')
)
顺便说一下,这就是你的日期系列视图在LookerML中的样子:
view: date_series {
derived_table: {
sql:
select
dateadd(day, nbr - 1, convert(date, '2017-01-01')) as d
from (
select row_number() over (order by c.object_id) as nbr from sys.columns c
) nbrs
where
nbr - 1 <= datediff(day, convert(date, '2017-01-01'), convert(date, '2018-12-31')) ;;
}
dimension: date {
primary_key: yes
type: date
sql: ${TABLE}.d ;;
}
}
答案 8 :(得分:0)
fn_uuid()
答案 9 :(得分:0)
我意识到这是一个旧线程,但是我不得不为这里给出的过多的递归和循环解决方案感到沮丧。我想知道有多少人意识到递归只不过是一个非常昂贵的循环?我了解创建表值函数的愿望,但是我建议以下代码要高效得多,因为它是基于集合的,没有循环,递归或重复的单个插入语句。
CREATE FUNCTION dbo.GenerateDateRange(@StartDate AS DATE, @EndDate AS DATE)
RETURNS TABLE WITH SCHEMABINDING AS
WITH e1(n) AS (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS x(n)) -- 16 records
,e2(n) AS (SELECT 1 FROM e1 a CROSS JOIN e1 b) -- 16^2 or 256 records (16*16)
,cteTally(n) AS (SELECT ROW_NUMBER() over (ORDER BY 1) AS n FROM e2 a CROSS JOIN e2 b) -- 16^4 or 65,536 records (256*256)
SELECT DATEADD(DAY, n-1, @StartDate)
FROM cteTally
WHERE n <= DATEDIFF(DAY, @StartDate, @EndDate) + 1;
GO
答案 10 :(得分:0)
这是一个旧线程,但是如果可以帮助任何人,这就是我在支持CTE的现代SQL Server版本中所使用的。这还可以为您提供星期几,您可以对其进行调整以提供您可能需要的其他值(例如,季度,月份等)。
fb(AppID)://