显示所有日期范围的数据,包括缺失日期

Display data for all date ranges including missing dates

我对日期有疑问。我有一个 table,其中包含员工的起止日期。为了进行评估,我想显示每月的每个日期以及第二个 sql table.

的相应值

SQL Table:

EmpNr | datefrom   | dateto     | hours
 0815 | 01.01.2019 | 03.01.2019 | 15
 0815 | 05.01.2019 | 15.01.2019 | 15
 0815 | 20.01.2019 | 31.12.9999 | 40

指定员工 (0815) 在 01.01.-15.01 期间工作。 15 小时,在 20.01.-31.01 期间。 40 小时

我想要以下结果:

0815 | 01.01.2019 | 15
0815 | 02.01.2019 | 15
0815 | 03.01.2019 | 15
0815 | 04.01.2019 | NULL
0815 | 05.01.2019 | 15
...
0815 | 15.01.2019 | 15
0815 | 16.01.2019 | NULL
0815 | 17.01.2019 | NULL
0815 | 18.01.2019 | NULL
0815 | 19.01.2019 | NULL
0815 | 20.01.2019 | 40
0815 | 21.01.2019 | 40
...
0815 | 31.01.2019 | 40

至于日期,我们有:

declare @year int = 2019, @month int = 1;
WITH numbers
as
(
    Select 1 as value
    UNion ALL
    Select value + 1 from numbers
    where value + 1 <= Day(EOMONTH(datefromparts(@year,@month,1)))
)
SELECT b.empnr, b.hours, datefromparts(@year,@month,numbers.value) Datum FROM numbers left outer join 
emptbl b  on b.empnr = '0815' and  (datefromparts(@year,@month,numbers.value) >=  b.datefrom and datefromparts(@year,@month,numbers.value) <= case b.dateto )

工作得很好,但我有一个奇怪的问题,这个代码只适用于 01.01.2019 和 03.01.2019 之间的日期

非常感谢您!

它可能在您的 select 中,试试:

SELECT b.empnr, b.hours, datefromparts(@year,@month,numbers.value) Datum
FROM numbers 
LEFT OUTER JOIN emptbl b ON b.empnr = '0815' AND 
datefromparts(@year,@month,numbers.value) BETWEEN b.datefrom AND b.dateto 

您的 CTE 只生成 31 个数字,因此它只显示 1 月的日期。

declare @year int = 2019, @month int = 1;

WITH numbers
as
(
    Select 1 as value
    UNion ALL
    Select value + 1 from numbers
    where value + 1 <= Day(EOMONTH(datefromparts(@year,@month,1)))
)
SELECT *
FROM numbers

https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=a24e58ef4ce522d3ec914f90907a0a9e

你可以试试下面的代码,

with t0 (i)    as (select 0  union all  select 0  union all  select 0),
     t1 (i)    as (select a.i from t0 a ,t0 b ),
     t2 (i)    as (select a.i from t1 a ,t1 b ),
     t3 (srno) as (select row_number()over(order by a.i) from t2 a ,t2 b ),
     tbldt(dt) as (select dateadd(day,t3.srno-1,'01/01/2019') from t3)   
select  tbldt.dt 
from tbldt
where tbldt.dt <= b.dateto -- put your condition here

https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=b16469908b323b8d1b98d77dd09bab3d

递归 CTE 需要以 MIN(datefrom)MAX(dateto):

开头
DECLARE @t TABLE (empnr INT, datefrom DATE, dateto DATE, hours INT);

INSERT INTO @t VALUES
(815, '2019-01-01', '2019-01-03', 15),
(815, '2019-01-05', '2019-01-15', 15),
(815, '2019-01-20', '9999-01-01', 40),
-- another employee
(999, '2018-01-01', '2018-01-31', 15),
(999, '2018-03-01', '2018-03-31', 15),
(999, '2018-12-01', '9999-01-01', 40);

WITH rcte AS (
    SELECT empnr
         , MIN(datefrom) AS refdate
         , ISNULL(NULLIF(MAX(dateto), '9999-01-01'), CURRENT_TIMESTAMP) AS maxdate -- clamp year 9999 to today
    FROM @t
    GROUP BY empnr

    UNION ALL

    SELECT empnr
         , DATEADD(DAY, 1, refdate)
         , maxdate
    FROM rcte
    WHERE refdate < maxdate
)
SELECT rcte.empnr
     , rcte.refdate
     , t.hours
FROM rcte
LEFT JOIN @t AS t ON rcte.empnr = t.empnr AND rcte.refdate BETWEEN t.datefrom AND t.dateto
ORDER BY rcte.empnr, rcte.refdate
OPTION (MAXRECURSION 1000) -- approx 3 years

Demo on db<>fiddle

您检查过 datefrom 和 dateto 是否在正确的范围内吗?

DateTime 字段的最小值为 1753-01-01,最大值为 9999-12-31。

查看您的来源 table 以检查初始值。