我目前正在研究MS Project Server的一些报告,发现这个奇怪之处:</ p>
由于某些不明原因,每当您在连续几天内指定相同的任务时间时,应用程序会更新开始日期和结束时,而不是为每个约会创建条目数据库上的日期字段,只留下该任务的一个条目,但日期之间的范围。
如果连续几天指定给任务的时间不同,则每次约会将创建一个条目。
(是的,我知道,这有点令人困惑。我甚至不知道如何更好地解释这一点。)
我想知道在开始和结束日期之间存在差异时,是否有可能在SQL语句中生成更多行,范围内每天一个。
这是我现在的查询,我已经知道哪些行有这个日期差异,但我不知道接下来我能做什么。
select
r.WRES_ID, r.RES_NAME, PROJ_NAME, p.WPROJ_ID, TASK_NAME, WWORK_VALUE, WWORK_START, WWORK_FINISH,
datediff(d, WWORK_START, WWORK_FINISH) + 1 AS work_days
from MSP_WEB_RESOURCES r
join
MSP_WEB_ASSIGNMENTS a on a.WRES_ID = r.WRES_ID
join
MSP_WEB_PROJECTS p on p.WPROJ_ID = a.WPROJ_ID
join
MSP_WEB_WORK w on w.WASSN_ID = a.WASSN_ID
where RES_NAME = 'HenriqueBarcelos'
and WWORK_TYPE = 1
and WWORK_VALUE > 0
and WWORK_FINISH between '2014-01-27' and '2014-01-31'
order by WWORK_FINISH DESC
我知道我可以在应用程序级别执行此操作,但我想知道是否可以在数据库本身内执行此操作。
提前感谢。
这些是我目前的结果:
WRES_ID | RES_NAME | TASK_NAME | WWORK_VALUE | WWORK_START | WWORK_FINISH | work_days
--------+------------------+-------------------------+---------------+---------------------+---------------------+----------
382 | HenriqueBarcelos | Outsourcing Initiatives | 60000.000000 | 2014-01-30 00:00:00 | 2014-01-30 00:00:00 | 1
382 | HenriqueBarcelos | Internal Training | 289800.000000 | 2014-01-29 00:00:00 | 2014-01-29 00:00:00 | 1
382 | HenriqueBarcelos | Outsourcing Initiatives | 120000.000000 | 2014-01-29 00:00:00 | 2014-01-29 00:00:00 | 1
382 | HenriqueBarcelos | Outsourcing Initiatives | 60000.000000 | 2014-01-27 00:00:00 | 2014-01-28 00:00:00 | 2
382 | HenriqueBarcelos | Infrastructure (TI) | 120000.000000 | 2014-01-27 00:00:00 | 2014-01-27 00:00:00 | 1
请注意,倒数第二个寄存器的范围为2天。根据契约,有2个任命,一个在1月27日,另一个在28日。
我想要做的是扩展这个并在这种情况下每天返回一个条目。
答案 0 :(得分:0)
可以做到,但不是很优雅。首先,您需要一个将日期范围扩展为日期序列的函数:
CREATE FUNCTION ufn_Expand(@start DATE, @end DATE)
RETURNS TABLE
AS
RETURN
WITH cte AS
(
SELECT @start AS dt
UNION ALL
SELECT DATEADD(dd, 1, dt) FROM cte WHERE dt < @end
)
SELECT dt FROM cte
然后在CROSS APPLY
的查询中使用它:
SELECT /* your columns */, x.dt
FROM /* your joins */
CROSS APPLY ufn_Expand(WWORK_START, WWORK_FINISH) x
答案 1 :(得分:0)
我会使用数字表(很好,基于集合,yum!)
SELECT start_date
, end_date
, DateDiff(dd, start_date, end_date) + 1 As number_of_days --rows to display
FROM your_table
INNER
JOIN dbo.numbers
ON numbers.number BETWEEN 1 AND DateDiff(dd, start_date, end_date) + 1
使用您最喜欢的搜索引擎查找数字表脚本。 Here's one I made earlier
顺便说一句:如果删除+1
s,你只需将连接修改为零和DateDiff()之间 - 我添加了+ 1s,因为我认为它可能更清晰!
答案 2 :(得分:0)
您可以从另一个角度看到这一点。你不是每个工作日都想要一排。您真正需要的是工作天数乘以报告的工作时间。像这样:
(dbo.MSP_WEB_WORK.WWORK_VALUE / 60000) * (DATEDIFF(day, dbo.MSP_WEB_WORK.WWORK_START, dbo.MSP_WEB_WORK.WWORK_FINISH) + 1)
然而,这会产生一个问题。让我们说你想要一个特定的时期。如果您使用WWORK_START和WWORK_FINISH日期作为报告,则需要小心将所有工作包含在该期间内的某些日期。这样的事情会做到:
DECLARE @InitDate DATETIME;
DECLARE @EndDate DATETIME;
SET @InitDate = '2016/06/01';
SET @EndDate = '2016/07/01';
--Full list of tasks
SELECT dbo.MSP_WEB_RESOURCES.RES_NAME AS Name, dbo.MSP_WEB_PROJECTS.PROJ_NAME AS Project,
dbo.MSP_WEB_WORK.WWORK_VALUE / 60000 AS ReportedWork,
CASE
WHEN WWORK_START < @InitDate THEN DATEDIFF(day, @InitDate, dbo.MSP_WEB_WORK.WWORK_FINISH) + 1 --If the task started before the start of the period
WHEN WWORK_FINISH > DATEDIFF(day,-1,@EndDate) THEN DATEDIFF(day, WWORK_START, DATEDIFF(day,-1,@EndDate)) + 1 --if the task ended after the end of the period
ELSE DATEDIFF(day, dbo.MSP_WEB_WORK.WWORK_START, dbo.MSP_WEB_WORK.WWORK_FINISH) + 1 --All tasks with start and end date inside the period
END AS RepeatedDays,
CASE
WHEN WWORK_START < @InitDate THEN (dbo.MSP_WEB_WORK.WWORK_VALUE / 60000) * (DATEDIFF(day, @InitDate, dbo.MSP_WEB_WORK.WWORK_FINISH) + 1)
WHEN WWORK_FINISH > DATEDIFF(day,-1,@EndDate) THEN (dbo.MSP_WEB_WORK.WWORK_VALUE / 60000) * (DATEDIFF(day, WWORK_START, DATEDIFF(day,-1,@EndDate)) + 1)
ELSE (dbo.MSP_WEB_WORK.WWORK_VALUE / 60000) * (DATEDIFF(day, dbo.MSP_WEB_WORK.WWORK_START, dbo.MSP_WEB_WORK.WWORK_FINISH) + 1)
END AS ActualWork,
dbo.MSP_WEB_WORK.WWORK_START,
dbo.MSP_WEB_WORK.WWORK_FINISH
FROM dbo.MSP_WEB_RESOURCES INNER JOIN
dbo.MSP_WEB_ASSIGNMENTS INNER JOIN
dbo.MSP_WEB_PROJECTS ON dbo.MSP_WEB_ASSIGNMENTS.WPROJ_ID = dbo.MSP_WEB_PROJECTS.WPROJ_ID INNER JOIN
dbo.MSP_WEB_WORK ON dbo.MSP_WEB_ASSIGNMENTS.WASSN_ID = dbo.MSP_WEB_WORK.WASSN_ID ON
dbo.MSP_WEB_RESOURCES.WRES_ID = dbo.MSP_WEB_ASSIGNMENTS.WRES_ID
WHERE (dbo.MSP_WEB_WORK.WWORK_TYPE = 1) AND
(
@InitDate BETWEEN dbo.MSP_WEB_WORK.WWORK_START and dbo.MSP_WEB_WORK.WWORK_FINISH OR
DATEADD(day,-1,@EndDate) BETWEEN dbo.MSP_WEB_WORK.WWORK_START and dbo.MSP_WEB_WORK.WWORK_FINISH OR
(dbo.MSP_WEB_WORK.WWORK_START >= @InitDate) AND
(dbo.MSP_WEB_WORK.WWORK_FINISH < @EndDate)
)
ORDER BY dbo.MSP_WEB_WORK.WWORK_START;