与日期约束的字段相关性
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
,因此您可能需要使用 limit
或 top
或任何适合您的数据库的标准。
- 使用'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
我们在这里遇到了巨大的挑战。让我们假设一个数据库的 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
,因此您可能需要使用 limit
或 top
或任何适合您的数据库的标准。
- 使用'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