Sql 对于包含数据的每一行,我需要每个类别对应一行
我有时间表数据,需要为“按日期范围”创建报告。我需要为每个人每天和每种时间类型排一行。如果给定的一天中没有该时间类型的条目,则我需要空数据。我试过左键连接,但似乎不起作用。交叉连接将给出错误的数据 我拥有的表是Person表personID、Name、TimeLog表TimeLogID、StartDate、EndDate、TimeLogTypeID和TimeLogType表TimeLogTypeID、personID、Description、DeletedInd 我在结果集中只能得到包含数据的行,而不是每个TimeLogType的空行 以下是我目前掌握的情况:Sql 对于包含数据的每一行,我需要每个类别对应一行,sql,sql-server,sql-server-2012,Sql,Sql Server,Sql Server 2012,我有时间表数据,需要为“按日期范围”创建报告。我需要为每个人每天和每种时间类型排一行。如果给定的一天中没有该时间类型的条目,则我需要空数据。我试过左键连接,但似乎不起作用。交叉连接将给出错误的数据 我拥有的表是Person表personID、Name、TimeLog表TimeLogID、StartDate、EndDate、TimeLogTypeID和TimeLogType表TimeLogTypeID、personID、Description、DeletedInd 我在结果集中只能得到包含数据的行
DECLARE
@startDate DATE,
@endDate DATE
SET @startDate = '2014-05-01'
SET @endDate = '2014-05-30'
SELECT
CONVERT(DATE, TimeLog.StartDateTime, 101) AS TimeLogDay,
SUM(dbo.fnCalculateHoursAsDecimal(TimeLog.StartDateTime, TimeLog.EndDateTime)) AS Hours,
TimeLog.PersonID,
TimeLog.TimeLogTypeID
INTO #HourTable
FROM
TimeLog
WHERE
TimeLog.StartDateTime BETWEEN @startDate AND @endDate
GROUP BY
CONVERT(DATE, TimeLog.StartDateTime, 101),
TimeLog.TimeLogTypeID,
TimeLog.PersonID
SELECT
TimeLogType.Description,
#HourTable.*
FROM
TimeLogType LEFT JOIN
#HourTable ON TimeLogType.TimeLogTypeID = #HourTable.TimeLogTypeID
WHERE
ISNULL(TimeLogType.DeletedInd, 0) = 0
ORDER BY
PersonID, TimeLogDay, TimeLogType.TimeLogTypeID
数据如下所示:
with dates as (
select dateadd(day, number - 1, mind) as thedate
from (select min(StartDate) as mind, max(EndDate) as endd
from TimeLogType
) tlt join
master..spt_values v
on dateadd(day, v.number, mind) <= tlt.endd
)
select p.PersonId, tlt.TimeLogTypeId, d.thedate,
from Person p cross join
(select tlt.* from TimeLogType tlt where ISNULL(TimeLogType.DeletedInd, 0) = 0
) tlt cross join
date d left join
TimeLog tl
on tl.Person_id = p.PersonId and tl.TimeLogTypeId = tlt.TimeLogTypeId and
d.thedate >= tl.StartDate and d.thedate <= tl.EndDate
时间日志类型:
1、计费
2、不计费
人:
1,比利
2、汤姆
时间日志:
1, 1, 2014-05-01 08:00:00, 2014-05-01 09:00:00, 1, 0
2, 1, 2014-05-01 09:00:00, 2014-05-01 10:00:00, 1, 0
3, 2, 2014-05-01 08:00:00, 2014-05-01 08:30:00, 2, 0
4, 2, 2014-05-01 08:30:00, 2014-05-01 09:00:00, 1, 0
5,1,2014-05-02 08:00:00,2014-05-02 09:00:00,2,0
预期输出:按人员、日期、时间记录类型排序
天、人、账单类型、总小时数
2014-05-01,比利,可付费,2.0
2014-05-01,比利,不计费,无效
2014-05-02,比利,可付费,1.0
2014-05-02,比利,不可付费,无效
等
2014年5月1日,汤姆,应纳税,0.5
2014-05-01,汤姆,不收费,0.5
等等 您需要首先生成所有组合,然后使用left join输入所需的信息。我认为问题是这样的:
with dates as (
select dateadd(day, number - 1, mind) as thedate
from (select min(StartDate) as mind, max(EndDate) as endd
from TimeLogType
) tlt join
master..spt_values v
on dateadd(day, v.number, mind) <= tlt.endd
)
select p.PersonId, tlt.TimeLogTypeId, d.thedate,
from Person p cross join
(select tlt.* from TimeLogType tlt where ISNULL(TimeLogType.DeletedInd, 0) = 0
) tlt cross join
date d left join
TimeLog tl
on tl.Person_id = p.PersonId and tl.TimeLogTypeId = tlt.TimeLogTypeId and
d.thedate >= tl.StartDate and d.thedate <= tl.EndDate
在阅读了戈登的答案后,我想到了这一点。我一步一步地创建了它,这样我就可以看到发生了什么。我创建了没有主..spt_值表的日期。我还创建了一个临时人员表,这样我就可以只选择那些有TimeLogRecord的人员,然后重新使用它来获取最终选择的详细信息。让我知道是否有任何方法可以让这跑得更快
DECLARE
@startDate DATE,
@endDate DATE
SET @startDate = '2014-01-01'
SET @endDate = '2014-01-31'
-- create day rows --
;WITH dates(TimeLogDay) AS
(
SELECT @startDate AS TimeLogDay
UNION ALL
SELECT DATEADD(d, 1, TimeLogDay)
FROM dates
WHERE TimeLogDay < @enddate
)
-- create a type row for each day --
SELECT
dates.TimeLogDay,
tlt.TimeLogTypeID
INTO #TypeDate
FROM
dates CROSS JOIN
(SELECT
TimeLogType.TimeLogTypeID
FROM
TimeLogType
WHERE
ISNULL(TimeLogType.DeletedInd, 0) = 0
) AS TLT
-- create a temp person table for referance later ---
SELECT * INTO #person FROM Person WHERE Person.personID IN
(SELECT Timelog.PersonID FROM TimeLog WHERE TimeLog.StartDateTime BETWEEN @startDate AND @endDate)
-- sum up the log times and tie in the date/type rows --
SELECT
#TypeDate.TimeLogDay,
#TypeDate.TimeLogTypeID,
#person.PersonID,
SUM(dbo.fnCalculateHoursAsDecimal(TimeLog.StartDateTime, TimeLog.EndDateTime)) AS Hours
INTO #Hours
FROM
#person CROSS JOIN
#TypeDate LEFT JOIN
TimeLog ON
TimeLog.PersonID = #person.PersonID AND
TimeLog.TimeLogTypeID = #TypeDate.TimeLogTypeID AND
#TypeDate.TimeLogDay = CONVERT(DATE, TimeLog.StartDateTime, 101)
GROUP BY
#TypeDate.TimeLogDay,
#TypeDate.TimeLogTypeID,
#person.PersonID
-- now tie in the details to complete --
SELECT
#Hours.TimeLogDay,
TimeLogType.Description,
Person.LastName,
Person.FirstName,
#Hours.Hours
FROM
#Hours LEFT JOIN
Person ON #Hours.PersonID = Person.PersonID LEFT JOIN
TimeLogType ON #Hours.TimeLogTypeID = TimeLogType.TimeLogTypeID
ORDER BY
Person.FirstName,
Person.LastName,
#Hours.TimeLogDay,
TimeLogType.SortOrder
你能给出表格中的示例数据吗?还有一个简短但描述性的预期输出示例。我发现CTE有一些语法错误。我不得不把主人。。在spt_值表前面,在联接之前的子选择中将别名从“v”更改为“dte”,但行选择dateaddday,数字-1,mindate,因为该日期在mindate上给了我一个错误part@user3033282 . . . 很抱歉。现在试试看。