与日期约束的字段相关性

Field correlation with date constraint

我们在这里遇到了巨大的挑战。让我们假设一个数据库的 table 没有第一手正确规划。就是这样,我需要一个解决方案。

有一个包含 2 个字段的 table A。假设我有一个每天支持我工作的助手,但我是在 he/she 开始帮助我时才注册的。这意味着每个助手的'Stop Date'(table中不存在)是下一个助手开始日期的前一天。

Assistant | Start Date
James     | 07/01/17
Frank     | 01/03/18
Erika     | 01/06/18

第二个 table B 记录了我的助手工作了多少小时:

Date      | Worked Hours
12/31/17  | 7.5    
01/01/18  | 7.5     
01/02/18  | 9        
01/03/18  | 8       
01/04/18  | 9        
01/05/18  | 7.5 
01/06/18  | 9 
01/07/18  | 10

鉴于以上信息,我需要写一个 SQL 到 return 一个 table,如下所示,考虑到每个人的开始日期:

Assistant | Date     | Worked Hours 

基本上我需要以某种方式将日期和开始日期关联到 return 助手,但它涉及我不知道如何做的日期比较。

有什么解决办法吗?

您可以使用相关子查询:

select b.*,
       (select a.assistant
        from a
        where a.date <= b.date
        order by a.date desc
        fetch first 1 row only
       ) as assistant
from b;

注意所有数据库都支持 ANSI 标准 fetch first 1 row only,因此您可能需要使用 limittop 或任何适合您的数据库的标准。

  • 使用'lead()'查找下一条记录
  • 使用infinity保持最后的区间未闭合

CREATE TABLE a
        ( assistant text primary key
        , startdate date
        );

SET datestyle = 'mdy';

insert into a(assistant,startdate) VALUES
 ('James', '07/01/17' )
,('Frank', '01/03/18' )
,('Erika', '01/06/18' )
        ;
CREATE TABLE b
        ( ddate      DATE NOT NULL primary key
        , workedhours DECIMAL(4,1)
        );
insert into b(ddate,workedhours) VALUES
('12/31/17', 7.5)
,('01/01/18', 7.5)
,('01/02/18', 9)
,('01/03/18', 8)
,('01/04/18', 9)
,('01/05/18', 7.5)
,('01/06/18', 9)
,('01/07/18', 10)
        ;

WITH aa AS (
        SELECT a.assistant
        , a.startdate
        , lead(a.startdate, 1, 'infinity'::date) OVER (ORDER BY a.startdate)
                 AS enddate
        FROM a
        )
-- SELECT * FROM a ; 
SELECT aa.startdate, aa.enddate, aa.assistant
        , SUM(b.workedhours) AS workedhours
FROM aa
LEFT JOIN b ON b.ddate >= aa.startdate
                AND b.ddate < aa.enddate
GROUP BY 1,2,3
        ;

输出:


CREATE TABLE
SET
INSERT 0 3
CREATE TABLE
INSERT 0 8
 startdate  |  enddate   | assistant | workedhours 
------------+------------+-----------+-------------
 2017-07-01 | 2018-01-03 | James     |        24.0
 2018-01-03 | 2018-01-06 | Frank     |        24.5
 2018-01-06 | infinity   | Erika     |        19.0
(3 rows)

你可以试试这个。

DECLARE @TableA TABLE (Assistant VARCHAR(10), [Start Date] DATE)
INSERT INTO @TableA VALUES
('James','07/01/17'),
('Frank','01/03/18'),
('Erika','01/06/18')

DECLARE @TableB TABLE ([Date] DATE, [Worked Hours] DECIMAL(18,2))
INSERT INTO @TableB VALUES
('12/31/17', 7.5),   
('01/01/18', 7.5),    
('01/02/18', 9  ),     
('01/03/18', 8  ),    
('01/04/18', 9  ),     
('01/05/18', 7.5),
('01/06/18', 9  ),
('01/07/18', 10 )


;WITH CTE AS (
SELECT *, RN = ROW_NUMBER() OVER( PARTITION BY [Date] ORDER BY [Start Date] DESC)
FROM 
    @TableA A
    INNER JOIN @TableB B ON A.[Start Date] <= B.Date
)
select Assistant, Date,  [Worked Hours] FROM CTE WHERE RN = 1

结果:

Assistant  Date       Worked Hours
---------- ---------- ---------------------------------------
James      2017-12-31 7.50
James      2018-01-01 7.50
James      2018-01-02 9.00
Frank      2018-01-03 8.00
Frank      2018-01-04 9.00
Frank      2018-01-05 7.50
Erika      2018-01-06 9.00
Erika      2018-01-07 10.00