我对SQL很陌生,所以请耐心等待。
我有一个包含各种活动的日期时间戳的数据集。
例如,我有一个包含以下字段的项目列表
start_project [datetime]
finish_project [datetime]
verify_project [datetime]
我想确定在项目生命周期的任何时候,工作是否跨越了多个月。
例如,start_project可以从1月1日上午9点开始,finish_project可以在2月3日中午12点开始,而verify_project则在2月12日下午3点开始。
我想确定每个月花在项目上的小时数,这样我就可以按月分组这些时间段。我确定如何实现逻辑。
答案 0 :(得分:0)
您应该创建一个包含工作日的dimDate表。
例如
Date isBusinessDay
1/1/2017 0
1/2/2017 1
...
然后查询它:
select Month(Date) Month,YEAR(Date) Year, WorkingHours = Count(*)*8 --Assuming 8 bus hours in a day
from DimDate
where Date between StartDate and EndDate
and isBusinessDay=1
group by Month(Date),YEAR(Date)
要将其添加到基本查询,您需要交叉申请:
select BaseTable.*, a.Month,a.Year, a.WorkingHours
from BaseTable
cross apply(
select Month(Date) Month,YEAR(Date) Year, WorkingHours = Count(*)*8 --Assuming 8 bus hours in a day
from DimDate
where Date between BaseTable.StartDate and BaseTable.EndDate
and isBusinessDay=1
group by Month(Date),YEAR(Date)) a
答案 1 :(得分:0)
使用数字表这是相对直接的......
https://www.mssqltips.com/sqlservertip/4176/the-sql-server-numbers-table-explained--part-1/
以下查询可以解决...
- 每个项目开始的月份
- 整个项目跨越多少个月
- 每个跨月返回一行
- 将月份开始的日期追加为新字段
SELECT
yourTable.*,
CASE
WHEN months_since_start.id = 0
THEN yourTable.start_project
ELSE DATEADD(month, months_since_start.id, first_month.start)
END
AS partial_month_start
FROM
yourTable
CROSS APPLY
(
VALUES( DATEADD(month, DATEDIFF(month, 0, yourTable.start_project)) )
)
first_month(start)
INNER JOIN
dbo.numbers AS months_since_start
ON months_since_start.id >= 0
AND months_since_start.id <= DATEDIFF(month, yourTable.start_project, yourTable.verify_project)
你可以在新的行/字段上使用DATEDIFF()
到你的心中。
答案 2 :(得分:0)
我应该使用数字表,但这也有效。
CREATE TABLE #myTable(ProjName VARCHAR(100), start_project DATETIME, finish_project DATETIME, verify_project DATETIME)
INSERT INTO #myTable SELECT 'proj1', '2017-01-01', '2017-04-15', '2017-04-15'
INSERT INTO #myTable SELECT 'proj2', '2017-01-02', '2017-01-11', '2017-01-11'
INSERT INTO #myTable SELECT 'proj3', '2017-06-06', '2017-06-06', '2017-06-06'
INSERT INTO #myTable SELECT 'proj4', '2017-03-01', '2017-08-15', '2017-08-15'
;with cte1 AS (
SELECT CASE
WHEN CAST(YEAR(t.start_project) AS VARCHAR) + CAST(MONTH(t.start_project) AS VARCHAR) <> CAST(YEAR(t.finish_project) AS VARCHAR) + CAST(MONTH(t.finish_project) AS VARCHAR)
THEN (DATEDIFF(DAY, start_project,EOMONTH(start_project, 0)) * 8) + 8
WHEN start_project = finish_project
THEN 8
ELSE (DATEDIFF(DAY, start_project,finish_project) * 8) + 8
END AS hours_this_month
, DATENAME(MONTH,start_project) AS month_name
, 0 AS month_level, start_project, finish_project, ProjName, verify_project
FROM #myTable t
UNION ALL
SELECT CASE
WHEN t.finish_project > EOMONTH(DATEADD(MONTH, t.month_level + 1, t.start_project))
AND ( CAST(YEAR(t.start_project) AS VARCHAR) + CAST(MONTH(t.start_project) AS VARCHAR) <> CAST(YEAR(t.finish_project) AS VARCHAR) + CAST(MONTH(t.finish_project) AS VARCHAR))
THEN
(DATEDIFF(DAY, CAST(CAST(YEAR(DATEADD(MONTH, t.month_level + 1, t.start_project)) AS VARCHAR) + '-' +
CAST(MONTH(DATEADD(MONTH, t.month_level + 1, t.start_project)) AS VARCHAR) + '-01' AS DATETIME)
, EOMONTH(DATEADD(MONTH, t.month_level + 1, t.start_project))) * 8) + 8
ELSE
(DATEDIFF(DAY, CAST(CAST(YEAR(DATEADD(MONTH, t.month_level + 1, t.start_project)) AS VARCHAR) + '-' +
CAST(MONTH(DATEADD(MONTH, t.month_level + 1, t.start_project)) AS VARCHAR) + '-01' AS DATETIME)
, t.finish_project) * 8) + 8
END
, DATENAME(MONTH,DATEADD(MONTH, t.month_level + 1, t.start_project))
, t.month_level + 1
, t.start_project
, t.finish_project, t.ProjName, t.verify_project
FROM cte1 t INNER JOIN
#myTable myT ON myT.ProjName = t.ProjName
WHERE CAST(CAST(YEAR(DATEADD(MONTH, t.month_level + 1, t.start_project)) AS VARCHAR) + '-' +
CAST(MONTH(DATEADD(MONTH, t.month_level + 1, t.start_project)) AS VARCHAR) + '-01' AS DATETIME)
<= t.finish_project )
SELECT ProjName
, month_name
, hours_this_month
, start_project
, finish_project
, verify_project
, month_level
FROM cte1
ORDER BY ProjName, month_level ASC
输出......
proj1 January 248 2017-01-01 00:00:00.000 2017-04-15 00:00:00.000 2017-04-15 00:00:00.000 0
proj1 February 224 2017-01-01 00:00:00.000 2017-04-15 00:00:00.000 2017-04-15 00:00:00.000 1
proj1 March 248 2017-01-01 00:00:00.000 2017-04-15 00:00:00.000 2017-04-15 00:00:00.000 2
proj1 April 120 2017-01-01 00:00:00.000 2017-04-15 00:00:00.000 2017-04-15 00:00:00.000 3
proj2 January 80 2017-01-02 00:00:00.000 2017-01-11 00:00:00.000 2017-01-11 00:00:00.000 0
proj3 June 8 2017-06-06 00:00:00.000 2017-06-06 00:00:00.000 2017-06-06 00:00:00.000 0
proj4 March 248 2017-03-01 00:00:00.000 2017-08-15 00:00:00.000 2017-08-15 00:00:00.000 0
proj4 April 240 2017-03-01 00:00:00.000 2017-08-15 00:00:00.000 2017-08-15 00:00:00.000 1
proj4 May 248 2017-03-01 00:00:00.000 2017-08-15 00:00:00.000 2017-08-15 00:00:00.000 2
proj4 June 240 2017-03-01 00:00:00.000 2017-08-15 00:00:00.000 2017-08-15 00:00:00.000 3
proj4 July 248 2017-03-01 00:00:00.000 2017-08-15 00:00:00.000 2017-08-15 00:00:00.000 4
proj4 August 120 2017-03-01 00:00:00.000 2017-08-15 00:00:00.000 2017-08-15 00:00:00.000 5