基于日期的多个组通过T-SQL查询

时间:2011-08-22 11:47:51

标签: sql-server database tsql

首先,执行更长的问题,但我会尝试尽可能简单地说明......

我正在尝试编写一种报告查询,但是我遇到了获得所需结果的问题。问题:

员工表

Id   |   Name                   
---------------
1    |   John Smith
2    |   Alan Jones
3    |   James Jones

任务表

Id   |   Title   |   StartDate   |   EmployeeId  |  Estimate (integer - ticks)
----------------------------------------------------------------------------
1    |   task1   |   21.08.2011  |   1           |   90000000000
2    |   task2   |   21.08.2011  |   1           |   150000000
3    |   task3   |   22.08.2011  |   2           |   1230000000

问题:

如何获得估算摘要每天,分组,但是要包括所有员工?

像这样:

Date           |   EmployeeId   |   EmployeeName    |    SummaryEstimate
 -------------------------------------------------------------
19.08.2011     |   1            |   John Smith      |    NULL
19.08.2011     |   2            |   Alan Jones      |    NULL
19.08.2011     |   3            |   James Jones     |    NULL
20.08.2011     |   1            |   John Smith      |    NULL
20.08.2011     |   2            |   Alan Jones      |    NULL
20.08.2011     |   3            |   James Jones     |    NULL
21.08.2011     |   1            |   John Smith      |    90150000000
21.08.2011     |   2            |   Alan Jones      |    NULL
21.08.2011     |   3            |   James Jones     |    NULL
22.08.2011     |   1            |   John Smith      |    NULL
22.08.2011     |   2            |   Alan Jones      |    1230000000
22.08.2011     |   3            |   James Jones     |    NULL

我目前所做的是有一个30天的“日期”表。我离开了该表的加入和分组以获得其他日期。好吧,这是查询:

  SELECT  dates.value, employee.Id, employee.Name, sum(task.Estimate)

  FROM TableOfDates as dates
  left join Tasks as task on (dates.value = convert(varchar(10), task.StartTime, 101))
  left join Employees as employee on (employee.Id = task.EmployeeId)

  WHERE dates.value >= '2011-08-19' and dates.value < '2011-08-22'

  GROUP BY dates.value, employee.Id, employee.Name

  ORDER BY dates.value, employee.Id

转换调用是获取DateTime列的日期部分。

我得到的结果是:

Date           |   EmployeeId   |   EmployeeName    |    SummaryEstimate
 -------------------------------------------------------------
19.08.2011     |   NULL         |   NULL            |    NULL
20.08.2011     |   NULL         |   NULL            |    NULL
21.08.2011     |   1            |   John Smith      |    90150000000    
22.08.2011     |   2            |   Alan Jones      |    1230000000

我在那里的一半,我得到的日期不在两个基础联接表(员工和任务)中,但我不能像在此表之前所示的表中那样包括所有员工。

我尝试过交叉连接,然后是子查询,但那里运气不大。任何帮助将非常感谢!感谢您有时间完成所有这些,我希望我足够清楚......

3 个答案:

答案 0 :(得分:4)

SELECT DE.DateValue, DE.EmployeeId, DE.EmployeeName, sum(task.Estimate)

FROM 
(  SELECT
     D.value AS DateValue
   , E.Id AS EmployeeId
   , E.Name AS EmployeeName
   FROM
   TableOfDates D      
   CROSS JOIN Employees E ) DE
left join Tasks as task on DE.DateValue = convert(varchar(10), task.StartTime, 101)
  AND DE.EmployeeId = task.EmployeeId

WHERE DE.DateValue >= '2011-08-19' and DE.DateValue < '2011-08-22'

GROUP BY DE.DateValue, DE.EmployeeId, DE.EmployeeName

ORDER BY DE.DateValue, DE.EmployeeId

答案 1 :(得分:2)

请注意,此解决方案可以删除日表,因为您可以使用动态递归CTE。

其他CTE:s(员工和任务)可以用真实表格代替。

DECLARE @startDate DATETIME = '2011-08-01'
DECLARE @endDate DATETIME = '2011-09-01'

;WITH Employees(Id,Name)
AS
(
SELECT  1,  'John Smith'
UNION ALL
SELECT  2,  'Alan Jones'
UNION ALL
SELECT  3,  'James Jones'
)
,Tasks (Id, Title, StartDate, EmployeeId, Estimate)
AS
(
SELECT  1,  'task1',    '2011-08-21',   1,  90000000000
UNION ALL
SELECT  2,  'task2',    '2011-08-21',   1,  150000000
UNION ALL
SELECT  3,  'task3',    '2011-08-22',   2,  1230000000
)
,TableOfDates(value)
AS
(
    SELECT  DATEADD(DAY, DATEDIFF(DAY, 0, @startDate), 0)
    UNION ALL
    SELECT  DATEADD(DAY, 1, value)
    FROM    TableOfDates
    WHERE   value < @endDate
)

SELECT  dates.value
        ,employee.Id
        ,employee.Name
        ,SUM(task.Estimate) AS SummaryEstimate
FROM    TableOfDates dates
CROSS JOIN  Employees employee
LEFT JOIN Tasks task 
    ON dates.value = task.StartDate
    AND (employee.Id = task.EmployeeId)
WHERE   dates.value >= '2011-08-19' 
    AND dates.value < '2011-08-26'
GROUP BY 
    dates.value
    ,employee.Id
    ,employee.Name
ORDER BY 
    dates.value
    ,employee.Id

答案 2 :(得分:2)

使用此查询:

create table #T_dates (id_date int identity(1,1),inp_date datetime)
create table #T_tasks (id_task int identity(1,1),key_date int, key_emp int, est int)
create table #T_emp (id_emp int identity(1,1),name varchar(50))

insert #T_dates (inp_date) values ('08.19.2011')
insert #T_dates (inp_date) values ('08.20.2011')
insert #T_dates (inp_date) values ('08.21.2011')
insert #T_dates (inp_date) values ('08.22.2011')
insert #T_dates (inp_date) values ('08.23.2011')
insert #T_dates (inp_date) values ('08.24.2011')
--select * from #T_dates

insert #T_emp (name) values ('John Smith')
insert #T_emp (name) values ('Alan Jones')
insert #T_emp (name) values ('James Jones')
--select * from #T_emp

insert #T_tasks (key_date,key_emp,est) values (4,1,900000)
insert #T_tasks (key_date,key_emp,est) values (4,1,15000)
insert #T_tasks (key_date,key_emp,est) values (5,2,123000)
--select * from #T_tasks

select inp_date,id_emp,name,EST
from #T_emp
cross join #T_dates
left join
(
select key_date,key_emp,SUM(est) 'EST' from #T_tasks group by key_date,key_emp
) Gr
    ON Gr.key_emp = id_emp and Gr.key_date = id_date
where inp_date >= '2011-08-19' and inp_date <= '2011-08-22'
order by inp_date,id_emp