如果两个时间值之间的小时数,则将行转移到具有SUM的列

时间:2013-06-14 06:11:25

标签: sql-server tsql pivot

我正在使用MS SQL Server 2008
表名是 tblDateTimeLog

ID INT(AI)
RecordID INT
DateLog DATE  
TimeLog TIME
DetachmentCode INT
EntryDate DATETIME
IsDeleted BIT
UserID VARCHAR(50)  

我有一张包含这个的表:

RecordID | DateLog    | TimeLog
11       | 2013-06-01 | 07:59:00
11       | 2013-06-01 | 19:01:00
11       | 2013-06-02 | 07:57:00
11       | 2013-06-02 | 19:03:00
11       | 2013-06-03 | 07:49:00
11       | 2013-06-03 | 19:11:00
14       | 2013-06-04 | 08:01:00
14       | 2013-06-04 | 19:03:00
14       | 2013-06-05 | 07:52:00
14       | 2013-06-05 | 19:02:00

一个记录ID可以在同一个DateLog上有多个TimeLog

现在我希望它显示如下:
日期为列和MIN(TimeLog)和MAX(TimeLog)之间的总小时数

RecordID | 2013-06-01 | 2013-06-02 | 2013-06-03 | 2013-06-04 | 2013-06-05
11       | 11:02:00   | 11:06:00   | 11:22:00   | NULL       | NULL  
14       | NULL       | NULL       | NULL       | 11:02:00   | 11:10:00  

根据Mikael的答案,这有效,但据我了解他的查询,这会返回MIN(TimeLog):

DECLARE @SQL NVARCHAR(MAX)
DECLARE @ColumnList NVARCHAR(MAX)

SELECT @ColumnList = 
STUFF
    (
        (
            SELECT DISTINCT ','+QUOTENAME(DateLog)
            FROM TESTPIS.dbo.tblDateTimeLog
            WHERE IsDeleted=0 AND DateLog >= '2013-06-15' AND DateLog <= '2013-06-30'
            ORDER BY 1
            FOR XML PATH('')
        ), 1, 1, ''
    )

SET @SQL = 'SELECT P.RecordID, '+@ColumnList+'
                FROM
                    (
                        SELECT RecordID, TimeLog, DateLog FROM TESTPIS.dbo.tblDateTimeLog WHERE isDeleted=0
                    ) AS T
                PIVOT
                    (
                        MIN(TimeLog) FOR DateLog IN ('+@ColumnList+')
                    ) as P'
EXEC (@SQL)

我想要返回的内容就像DATEDIFF(MINUTES,MIN(TimeLog),MAX(TimeLog)

我尝试用此替换查询中的MIN(TimeLog) SUM(DATEDIFF(MINUTES,MIN(TimeLog),MAX(TimeLog))

但是,我收到了这个错误 Incorrect syntax near '('.

2 个答案:

答案 0 :(得分:2)

select P.RecordID,
       P.[2013-06-01],
       P.[2013-06-02],
       P.[2013-06-03],
       P.[2013-06-04],
       P.[2013-06-05]
from (
     select RecordID,
            TimeLog,
            DateLog
     from YourTable
     ) as T
pivot(min(TimeLog) for DateLog in ([2013-06-01],
                                   [2013-06-02],
                                   [2013-06-03],
                                   [2013-06-04],
                                   [2013-06-05])) as P

要动态构建查询,您必须首先弄清楚列列表应包含的内容。

select distinct DateLog
from YourTable
order by 1

该查询的结果必须转换为以逗号分隔的列表,因为这样的数字是无效的列名,您可以使用quotename()将值括在[]中。

要构建以逗号分隔的列列表,您可以使用for xml path('')

select stuff((select distinct ','+quotename(DateLog)
              from YourTable
              order by 1
              for xml path('')), 1, 1, '')

stuff()可以删除第一个逗号。

然后你只需要将它们放在一起并执行你构建的查询。

declare @SQL nvarchar(max)
declare @ColumnList nvarchar(max)

select @ColumnList = stuff((select distinct ','+quotename(DateLog)
                            from YourTable
                            order by 1
                            for xml path('')), 1, 1, '')

set @SQL = '
select P.RecordID, '+@ColumnList+'
from (
     select RecordID,
            TimeLog,
            DateLog
     from YourTable
     ) as T
pivot(min(TimeLog) for DateLog in ('+@ColumnList+')) as P'

exec (@SQL)

SQL Fiddle

<强>更新

要获取每天最大和最小时间记录值之间的差异,您可以在派生表中的RecordIDDateLog上执行分组,并计算min和max之间的差异,并使用使用dateadd计算新时间值的值。

select P.RecordID,
       P.[2013-06-01],
       P.[2013-06-02],
       P.[2013-06-03],
       P.[2013-06-04],
       P.[2013-06-05]
from (
     select RecordID,
            dateadd(second, datediff(second, min(TimeLog), max(TimeLog)), convert(time(0), '00:00')) as TimeDiff,
            DateLog
     from YourTable
     group by RecordID,
              DateLog
     ) as T
pivot(min(TimeDiff) for DateLog in ([2013-06-01],
                                    [2013-06-02],
                                    [2013-06-03],
                                    [2013-06-04],
                                    [2013-06-05])) as P

动态版本:

declare @SQL nvarchar(max)
declare @ColumnList nvarchar(max)

select @ColumnList = stuff((select distinct ','+quotename(DateLog)
                            from YourTable
                            order by 1
                            for xml path('')), 1, 1, '')

set @SQL = '
select P.RecordID, '+@ColumnList+'
from (
     select RecordID,
            dateadd(second, datediff(second, min(TimeLog), max(TimeLog)), convert(time(0), ''00:00'')) as TimeDiff,
            DateLog
     from YourTable
     group by RecordID,
              DateLog
     ) as T
pivot(min(TimeDiff) for DateLog in ('+@ColumnList+')) as P'

exec (@SQL)

SQL Fiddle

答案 1 :(得分:2)

试试这个 -

<强>查询:

IF OBJECT_ID (N'tempdb.dbo.#temp') IS NOT NULL
   DROP TABLE #temp

CREATE TABLE #temp
(
        RecordID INT
      , DateLog DATETIME
      , TimeLog TIME
)

INSERT INTO #temp (RecordID, DateLog, TimeLog)
VALUES 
    (11, '2013-06-01', '08:00:00'), (11, '2013-06-02', '09:00:00'),
    (11, '2013-06-03', '10:00:00'), (11, '2013-06-04', '11:00:00'),
    (11, '2013-06-05', '12:00:00'), (14, '2013-06-01', '13:00:00'),
    (14, '2013-06-02', '14:00:00'), (14, '2013-06-03', '15:00:00'),
    (14, '2013-06-04', '16:00:00')

DECLARE @SQL NVARCHAR(MAX)
SELECT @SQL = 'SELECT *
FROM (
    SELECT DateLog, RecordID, tt = CAST(TimeLog AS VARCHAR(8)) 
    FROM #temp
) src
PIVOT (
    MAX(tt) 
    FOR DateLog IN (' + STUFF((
    SELECT ', [' + CONVERT(VARCHAR(10), DateLog, 120) + ']'
    FROM #temp
    GROUP BY DateLog
    ORDER BY DateLog
    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') + ')
) p'

PRINT @SQL

EXEC sys.sp_executesql @SQL

<强>输出:

SELECT *
FROM (
    SELECT DateLog, RecordID, tt = CAST(TimeLog AS VARCHAR(8)) 
    FROM #temp
) src
PIVOT (
    MAX(tt) 
    FOR DateLog IN ([2013-06-01], [2013-06-02], [2013-06-03], [2013-06-04], [2013-06-05])
) p

<强>结果:

RecordID    2013-06-01 2013-06-02 2013-06-03 2013-06-04 2013-06-05
----------- ---------- ---------- ---------- ---------- ----------
11          08:00:00   09:00:00   10:00:00   11:00:00   12:00:00
14          13:00:00   14:00:00   15:00:00   16:00:00   NULL

更新结果:

proff