在日期范围之间生成日期

2mbi3lxu  于 2021-07-24  发布在  Java
关注(0)|答案(11)|浏览(443)

我需要填充一个表来存储两个给定日期之间的日期范围:09/01/11-10/10/11
因此,在本例中,表将从2011年1月9日开始每天存储,直到2011年10月10日,我想知道在sql server中是否有一种巧妙的方法来实现这一点—我目前正在使用sql server 2008。谢谢

qcuzuvrc

qcuzuvrc1#

易用sql 2005+;如果你有一个数字或计数表就容易了。我在下面伪造了它:

  1. DECLARE @StartDate DATE = '20110901'
  2. , @EndDate DATE = '20111001'
  3. SELECT DATEADD(DAY, nbr - 1, @StartDate)
  4. FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY c.object_id ) AS Nbr
  5. FROM sys.columns c
  6. ) nbrs
  7. WHERE nbr - 1 <= DATEDIFF(DAY, @StartDate, @EndDate)

如果您有一个tally表,请用该表替换子查询。没有递归。

vfh0ocws

vfh0ocws2#

如果您使用的是sql server 2005或更新版本,请尝试以下操作:

  1. WITH Dates AS (
  2. SELECT
  3. [Date] = CONVERT(DATETIME,'09/01/2011')
  4. UNION ALL SELECT
  5. [Date] = DATEADD(DAY, 1, [Date])
  6. FROM
  7. Dates
  8. WHERE
  9. Date < '10/10/2011'
  10. ) SELECT
  11. [Date]
  12. FROM
  13. Dates
  14. OPTION (MAXRECURSION 45)

一个很好的例子酷的东西,你可以做一个cte。

展开查看全部
disbfnqx

disbfnqx3#

--声明

  1. DECLARE @dates TABLE(dt datetime)
  2. DECLARE @dateFrom datetime
  3. DECLARE @dateTo datetime
  4. SET @dateFrom = '2001/01/01'
  5. SET @dateTo = '2001/01/12'

--查询:

  1. WHILE(@dateFrom < @dateTo)
  2. BEGIN
  3. SELECT @dateFrom = DATEADD(day, 1,@dateFrom)
  4. INSERT INTO @dates
  5. SELECT @dateFrom
  6. END

--输出

  1. SELECT * FROM @dates
展开查看全部
xqnpmsa8

xqnpmsa84#

这是一个不需要递归的解决方案,同时,这个表值函数可以在许多查询中重用,而无需再次重复样板变量的声明。对于那些不希望递归的人来说,这是唯一的选择。
创建以下简单函数:

  1. CREATE FUNCTION [dbo].[GenerateDateRange]
  2. (@StartDate AS DATE,
  3. @EndDate AS DATE,
  4. @Interval AS INT
  5. )
  6. RETURNS @Dates TABLE(DateValue DATE)
  7. AS
  8. BEGIN
  9. DECLARE @CUR_DATE DATE
  10. SET @CUR_DATE = @StartDate
  11. WHILE @CUR_DATE <= @EndDate BEGIN
  12. INSERT INTO @Dates VALUES(@CUR_DATE)
  13. SET @CUR_DATE = DATEADD(DAY, @Interval, @CUR_DATE)
  14. END
  15. RETURN;
  16. END;

然后选择:

  1. select *
  2. from dbo.GenerateDateRange('2017-01-03', '2017-12-01', 1)
展开查看全部
lnlaulya

lnlaulya5#

我知道这是一个旧的线程,但我不得不承认我的沮丧,在这里给出的递归和循环解决方案过多。我想知道有多少人意识到递归只不过是一个非常昂贵的循环?我理解创建表值函数的愿望,但我建议以下方法更有效,因为它是基于集合的,没有循环、递归或重复的单insert语句:

  1. CREATE FUNCTION dbo.GenerateDateRange(@StartDate AS DATE, @EndDate AS DATE)
  2. RETURNS TABLE WITH SCHEMABINDING AS
  3. 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
  4. ,e2(n) AS (SELECT 1 FROM e1 a CROSS JOIN e1 b) -- 16^2 or 256 records (16*16)
  5. ,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)
  6. SELECT DATEADD(DAY, n-1, @StartDate)
  7. FROM cteTally
  8. WHERE n <= DATEDIFF(DAY, @StartDate, @EndDate) + 1;
  9. GO
7uzetpgm

7uzetpgm6#

使用mvj的f_table_date函数,它非常棒:
http://www.sqlteam.com/forums/topic.asp?topic_id=61519
一旦你实现了这一点,只需传入开始和结束日期,你就可以插入所有的日期之间。

w8rqjzmb

w8rqjzmb7#

使用@abe miesler的答案,为了其他人的方便,我将它构建到一个tvf中,用于sqlserver2008以后的版本。它可能会帮助其他人-我必须找到一种方法,包括在tvf的cte!

  1. --Generate a range of dates with interval option, courtesy of Abe Miessler for the core query here!
  2. ALTER FUNCTION [dbo].[DateRange]
  3. (@startDate AS DATE,
  4. @EndDate AS DATE,
  5. @interval AS INT
  6. )
  7. RETURNS @Dates TABLE(dateValue DATE)
  8. AS
  9. BEGIN
  10. WITH Dates
  11. AS (
  12. SELECT [Date] = CONVERT( DATETIME, @startDate)
  13. UNION ALL
  14. SELECT [Date] = DATEADD(DAY, ISNULL(@interval, 1), [Date])
  15. FROM Dates
  16. WHERE Date < @EndDate)
  17. INSERT INTO @Dates
  18. SELECT [Date]
  19. FROM Dates
  20. OPTION(MAXRECURSION 900);
  21. RETURN;
  22. END;
展开查看全部
b09cbbtk

b09cbbtk8#

这是一个旧的线程,但如果它对任何人都有帮助,这就是我在支持cte的sqlserver的现代版本中使用的。这还提供了一周中的某一天,可以对其进行调整,以提供可能需要的其他值(即季度、月份等)。

  1. DECLARE @StartDate datetime
  2. DECLARE @EndDate datetime
  3. SET @StartDate = '1/1/2020'
  4. SET @EndDate = '12/31/2020'
  5. DECLARE @DayTable Table(theDate date, theDayOfWeek nvarchar(50));
  6. WITH DayTable AS (SELECT CAST(@StartDate AS DATETIME) theDate, DATENAME(dw, @StartDate) theDayOfWeek UNION ALL SELECT DATEADD(dd, 1, theDate), DATENAME(dw,DATEADD(dd, 1, theDate)) FROM DayTable s WHERE DATEADD(dd, 1, theDate) <= CAST(@EndDate AS DATETIME))
  7. INSERT INTO @DayTable(theDate, theDayOfWeek) SELECT theDate, theDayOfWeek FROM DayTable OPTION (MAXRECURSION 365);
  8. SELECT * FROM @DayTable
ybzsozfc

ybzsozfc9#

  1. Declare @StartDate datetime = '2015-01-01'
  2. Declare @EndDate datetime = '2016-12-01'
  3. declare @DaysInMonth int
  4. declare @tempDateRange Table
  5. (
  6. DateFrom datetime,
  7. DateThru datetime
  8. );
  9. While @StartDate<=@EndDate
  10. begin
  11. SET @DaysInMonth=DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,@StartDate),0)))
  12. IF DAY(@StartDate)=1
  13. SET @EndDate=DATEADD(DAY,14,@StartDate)
  14. ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=30
  15. SET @EndDate=DATEADD(DAY,14,@StartDate)
  16. ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=31
  17. SET @EndDate=DATEADD(DAY,15,@StartDate)
  18. ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=28
  19. SET @EndDate=DATEADD(DAY,12,@StartDate)
  20. ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=29
  21. SET @EndDate=DATEADD(DAY,13,@StartDate)
  22. INSERT INTO @tempDateRange (DateFrom,DateThru)
  23. VALUES
  24. (
  25. @StartDate,
  26. @EndDate
  27. )
  28. SET @StartDate=DATEADD(DAY,1,@EndDate)
  29. IF @EndDate< '2016-12-31'
  30. IF DAY(@StartDate)=1
  31. SET @EndDate=DATEADD(DAY,14,@StartDate)
  32. ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=30
  33. SET @EndDate=DATEADD(DAY,14,@StartDate)
  34. ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=31
  35. SET @EndDate=DATEADD(DAY,15,@StartDate)
  36. ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=28
  37. SET @EndDate=DATEADD(DAY,12,@StartDate)
  38. ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=29
  39. SET @EndDate=DATEADD(DAY,13,@StartDate)
  40. end ;
  41. select * from @tempDateRange
  42. +++++++++++++++++++++++++++++
  43. Result:
  44. DateFrom |DateThru
展开查看全部
bz4sfanl

bz4sfanl10#

如果因为某种原因你不能 declare 变量,例如在looker中使用派生表时,可以如下所示:

  1. select
  2. dateadd(day, nbr - 1, convert(date, '2017-01-01')) as d
  3. from (
  4. select row_number() over (order by c.object_id) as nbr from sys.columns c
  5. ) nbrs
  6. where
  7. nbr - 1 <= datediff(
  8. day,
  9. convert(date, '2017-01-01'),
  10. convert(date, '2018-12-31')
  11. )

顺便说一句,在lookerml中,日期序列视图可能是这样的:

  1. view: date_series {
  2. derived_table: {
  3. sql:
  4. select
  5. dateadd(day, nbr - 1, convert(date, '2017-01-01')) as d
  6. from (
  7. select row_number() over (order by c.object_id) as nbr from sys.columns c
  8. ) nbrs
  9. where
  10. nbr - 1 <= datediff(day, convert(date, '2017-01-01'), convert(date, '2018-12-31')) ;;
  11. }
  12. dimension: date {
  13. primary_key: yes
  14. type: date
  15. sql: ${TABLE}.d ;;
  16. }
  17. }
展开查看全部
arknldoa

arknldoa11#

  1. CREATE table #ProductSales (ProjectID Int, ProjectName varchar(100), TotalBillableFees Money, StartDate Date, EndDate Date, DataDate Date)
  2. Insert into #ProductSales
  3. Values
  4. (373104,'Product Sales - Flex Creation Test',40000.00,'2019-04-01','2020-06-01','2019-08-01'),
  5. (375111,'Product Sales - SMART',40000.00,'2019-04-01','2019-09-01','2019-08-01')
  6. ;WITH Dates AS (
  7. SELECT ProjectiD
  8. ,Convert(decimal(10,2),TotalBillableFees/IIF(DATEDIFF(MONTH,StartDate,EndDate)=0,1,DATEDIFF(MONTH,StartDate,EndDate))) AS BillableFeesPerMonths,EndDate
  9. ,[Date] = CONVERT(DATETIME,EOMONTH(StartDate))
  10. FROM #ProductSales
  11. UNION ALL SELECT ProjectiD,BillableFeesPerMonths,EndDate,
  12. [Date] = DATEADD(MONTH, 1, [Date])
  13. FROM
  14. Dates
  15. WHERE
  16. Date < EOMONTH(EndDate)
  17. ) SELECT ProjectID,BillableFeesPerMonths,
  18. CAST([Date] as Date) Date
  19. FROM
  20. Dates
  21. OPTION (MAXRECURSION 45)
展开查看全部

相关问题