简体   繁体   English

使用SQL Server获取表中所有日期范围的所有日期

[英]Get all dates for all date ranges in table using SQL Server

I have table dbo.WorkSchedules(Id, From, To) where I store date ranges for work schedules. 我有表dbo.WorkSchedules(Id, From, To) ,其中存储工作计划的日期范围。 I want to create a view that will have all dates for all rows of WorkSchedules . 我想创建一个视图,其中将包含WorkSchedules所有行的所有日期。 Thanks to this I have 1 view with all dates for all schedules. 因此,我有1个视图,其中包含所有日程表的所有日期。

On web I only found solutions for 1 row like 2 parameters start and end. 在网络上,我仅找到1行的解决方案,例如2个参数start和end。 My issue is different where I have multiple rows with start and end range. 我的问题有所不同,我有多个行的起始和结束范围。

Example: 例:

WorkSchedules WorkSchedules

Id | From       | To
---+------------+-----------
1  | 2018-01-01 | 2018-01-05 
2  | 2018-01-08 | 2018-01-12

Desired result 所需结果

1 | 2018-01-01
2 | 2018-01-02
3 | 2018-01-03
4 | 2018-01-04
5 | 2018-01-05
6 | 2018-01-08
7 | 2018-01-09
8 | 2018-01-10
9 | 2018-01-11
10| 2018-01-12

Ok, I worked this out for you, thinking you mean that you meant 01/08/2018 as a From date in the second row. 好的,我为您解决了这个问题,认为您的意思是您将01/08/2018表示为第二行中的From date。

/*WorkSchedules
Id|    From    |     To
1 | 2018-01-01 | 2018-01-05 
2 | 2018-01-08 | 2018-01-12
*/

--DROP TABLE #WorkSchedules;

CREATE TABLE #WorkSchedules (
    ID int,
    [DateFrom] DATE,
    [DateTo] DATE
    )

INSERT INTO #WorkSchedules
SELECT 1, '2018-01-01', '2018-01-05'
UNION
SELECT 2, '2018-01-08', '2018-01-12'

;WITH CTEDATELIMITS AS (
    SELECT [DateFrom], [DateTo]
    FROM #WorkSchedules
    )
,CTEDATES AS
(
SELECT [DateFrom] as [DateResult] FROM CTEDATELIMITS
UNION ALL
SELECT DATEADD(Day, 1, [DateResult]) FROM CTEDATES
JOIN CTEDATELIMITS ON CTEDATES.[DateResult] >= CTEDATELIMITS.[DateFrom]
AND CTEDATES.dateResult < CTEDATELIMITS.[DateTo]
)
SELECT [DateResult] FROM CTEDATES
ORDER BY [DateResult]

You would use a recursive CTE: 您将使用递归CTE:

with dates as (
      select from, to, from as date
      from WorkSchedules
      union all
      select from, to, dateadd(day, 1, date)
      from dates
      where date < to
     )
select row_number() over (order by date), date
from dates;

Note that from and to are reserved words in SQL. 请注意, fromto是SQL中的保留字。 They are lousy names for identifiers. 它们是标识符的糟糕名称。 I have not escaped them because I assume they are not the actual names of the columns. 我没有逃脱它们,因为我认为它们不是列的实际名称。

If you are regularly dealing with "jobs" and "schedules" then I propose that you need a permanent calendar table (a table where each row is a unique date). 如果您定期处理“工作”和“计划”,那么我建议您需要一个永久日历表(该表中的每一行都是一个唯一的日期)。 You can create rows for dates dynamically but why do this many times when you can do it once and just re-use? 可以动态地为日期创建行,但是为什么一次只能重复使用却多次这样做呢?

A calendar table, even of several decades, isn't "big" and when indexed they can be very fast as well. 即使是几十年的日历表也不是很大,索引时它们也可以非常快。 You can also store information about holidays and/or fiscal periods etc. 您还可以存储有关假期和/或财政期间等的信息。

There are many scripts available to produce these tables, here's an answer with 2 scripts on this site: https://stackoverflow.com/a/5635628/2067753 有许多脚本可用于生成这些表,这是此网站上的2个脚本的答案: https : //stackoverflow.com/a/5635628/2067753

Assuming you use the second (more comprehensive) script, then you can exclude weekends, or other conditions such as holidays, from query results. 假设您使用第二个(更全面的)脚本,则可以从查询结果中排除周末或其他条件,例如假期。

Once you have a permanent Calendar table this style of query may be used: 一旦有了永久的Calendar表,就可以使用这种查询方式:

CREATE TABLE WorkSchedules(
   Id   INTEGER  NOT NULL PRIMARY KEY 
  ,[From] DATE  NOT NULL
  ,[To]   DATE  NOT NULL
);
INSERT INTO WorkSchedules(Id,[From],[To]) VALUES (1,'2018-01-01','2018-01-05');
INSERT INTO WorkSchedules(Id,[From],[To]) VALUES (2,'2018-01-12','2018-01-12');

with range as (
    select min(ws.[From]) as dt_from, max(ws.[To]) dt_to
    from WorkSchedules as ws
    )
select c.*
from calendar as c
inner join range on c.date between range.dt_from and range.dt_to
where c.KindOfDay = 'BANKDAY'
order by c.date

and the result looks like this (note: "News Years Day" has been excluded) 结果看起来像这样(注意:“ New Year Years Day”已被排除)

              Date           Year   Quarter   Month   Week   Day   DayOfYear   Weekday   Fiscal_Year   Fiscal_Quarter   Fiscal_Month   KindOfDay   Description  
 ---- --------------------- ------ --------- ------- ------ ----- ----------- --------- ------------- ---------------- -------------- ----------- ------------- 
   1   02.01.2018 00:00:00   2018         1       1      1     2           2         2          2018                1              1   BANKDAY     NULL         
   2   03.01.2018 00:00:00   2018         1       1      1     3           3         3          2018                1              1   BANKDAY     NULL         
   3   04.01.2018 00:00:00   2018         1       1      1     4           4         4          2018                1              1   BANKDAY     NULL         
   4   05.01.2018 00:00:00   2018         1       1      1     5           5         5          2018                1              1   BANKDAY     NULL         
   5   08.01.2018 00:00:00   2018         1       1      2     8           8         1          2018                1              1   BANKDAY     NULL         
   6   09.01.2018 00:00:00   2018         1       1      2     9           9         2          2018                1              1   BANKDAY     NULL         
   7   10.01.2018 00:00:00   2018         1       1      2    10          10         3          2018                1              1   BANKDAY     NULL         
   8   11.01.2018 00:00:00   2018         1       1      2    11          11         4          2018                1              1   BANKDAY     NULL         
   9   12.01.2018 00:00:00   2018         1       1      2    12          12         5          2018                1              1   BANKDAY     NULL         

Without the where clause the full range is: 如果没有where子句,则整个范围是:

              Date           Year   Quarter   Month   Week   Day   DayOfYear   Weekday   Fiscal_Year   Fiscal_Quarter   Fiscal_Month   KindOfDay    Description    
 ---- --------------------- ------ --------- ------- ------ ----- ----------- --------- ------------- ---------------- -------------- ----------- ---------------- 
   1   01.01.2018 00:00:00   2018         1       1      1     1           1         1          2018                1              1   HOLIDAY     New Year's Day  
   2   02.01.2018 00:00:00   2018         1       1      1     2           2         2          2018                1              1   BANKDAY     NULL            
   3   03.01.2018 00:00:00   2018         1       1      1     3           3         3          2018                1              1   BANKDAY     NULL            
   4   04.01.2018 00:00:00   2018         1       1      1     4           4         4          2018                1              1   BANKDAY     NULL            
   5   05.01.2018 00:00:00   2018         1       1      1     5           5         5          2018                1              1   BANKDAY     NULL            
   6   06.01.2018 00:00:00   2018         1       1      1     6           6         6          2018                1              1   SATURDAY    NULL            
   7   07.01.2018 00:00:00   2018         1       1      1     7           7         7          2018                1              1   SUNDAY      NULL            
   8   08.01.2018 00:00:00   2018         1       1      2     8           8         1          2018                1              1   BANKDAY     NULL            
   9   09.01.2018 00:00:00   2018         1       1      2     9           9         2          2018                1              1   BANKDAY     NULL            
  10   10.01.2018 00:00:00   2018         1       1      2    10          10         3          2018                1              1   BANKDAY     NULL            
  11   11.01.2018 00:00:00   2018         1       1      2    11          11         4          2018                1              1   BANKDAY     NULL            
  12   12.01.2018 00:00:00   2018         1       1      2    12          12         5          2018                1              1   BANKDAY     NULL            

and weekends and holidays may be excluded using the column KindOfDay 周末和节假日可以使用KindOfDay列排除

See this as a demonstration (with build of calendar table) here: http://rextester.com/CTSW63441 在此处查看此示例(带有日历表的构建): http : //rextester.com/CTSW63441

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 获取SQL Server中日期范围内的所有日期 - Get all dates in date range in SQL Server 展开日期范围以获取具有排除日期的表格的日期范围系列之间的所有日期 - Expand date range to get all dates between series of date ranges from a table with excluded dates 使用日历表填写特定日期范围内的所有日期 - Fill in all dates in certain date ranges from another using calendar table SQL:如何使用表中的所有数据对某些日期范围进行计算 - SQL: How to do calculations for certain ranges of dates with all data in table 使用范围内的日期来加入和显示所有日期? - Using the dates in ranges to join and display all dates? 选择不在其中一个日期范围内的所有日期 - Select all dates which are not in one of the date ranges SQL从一个表中查询所有日期范围,而不是在另一个表的任何日期范围之间为给定外键 - SQL querying all date ranges from one table not between any date ranges of another for given foreign key 获取 SQL 中给定日期范围内的所有月份范围 - Get all month ranges in given date range in SQL sql获取两个表日期之间的所有日期 - sql get all dates between two table dates 获取SQL Server存储过程中2个日期之间的所有日期 - Get all dates between 2 dates in SQL Server stored procedure
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM