用于计算时间的SQL查询

时间:2012-02-04 13:46:07

标签: sql sql-server sql-server-2008

鉴于这些表格:

Item
-----
Id
Description
Status
CreatedBy

ItemLog
--------
Id
ItemId
NewStatus
TimeStamp
ChangedBy

Itemlog.ItemId = Item.IdStatus = { "Created", "Pended", "Cancelled", "Completed" } ...

的位置

如何编写SQL查询以生成以下结果:

Item     Description     ChangeDate       NewStatus     ChangedBy
  1          Test1          2012-01-01    Created    User1
  1          Test1          2012-01-02    Pended     User2
  1          Test1          2012-01-03    Completed  User2
  2          Test2          2012-01-01    Created    User2
  2          Test2          2012-01-02    Pended     User3
  2          Test2          2012-01-09    Cancelled  User1
  3          Test3          2012-01-01    Created    User1
  3          Test3          2012-01-02    Pended     User1

Item   CurrentUser CurrentStatus CreatedOn     TotalTime    TimePended CompletedDate CancelledDate
Test1  User2        Completed     2012-01-01     3 days      1 day      2012-01-03   (null)
Test2  User1        Completed     2012-01-01     9 days      7 days     (null)       2012-01-09
Test3  User1        Pended        2012-01-01     35 days     34 days    (null)       (null)

我希望在我的应用程序中显示为master-detail报告。

第一个结果集是一个带有几个连接的简单查询(我没有包含UserId-UserName表等。)

困难的部分是计算总时间......

TimeToComplete是最后TimeStamp的{​​{1}}减去第一个ItemLog的{​​{1}}(其中TimeStamp按日期排序)。

ItemLog是每次更改状态之间ItemLog之差的总和 - >东西。

2 个答案:

答案 0 :(得分:2)

<强>快变!

create table Item(ID int, Description varchar(200),createdby varchar(20))
create table ItemLog(ID int, ItemID int, NewStatus varchar(200), [TimeStamp] datetime, ChangedBy varchar(20))

insert into Item(ID,Description,CreatedBy) values(1, 'Test 1', 'User1')
insert into Item(ID,Description,CreatedBy) values(2, 'Test 2', 'User1')
insert into Item(ID,Description,CreatedBy) values(3, 'Test 3', 'User1')

insert into ItemLog(ID, ItemID, NewStatus, TimeStamp, ChangedBy) 
    values(1,1,'Created','1/1/2012','User1')
insert into ItemLog(ID, ItemID, NewStatus, TimeStamp, ChangedBy) 
    values(2,1,'Pended','1/2/2012','User2')
insert into ItemLog(ID, ItemID, NewStatus, TimeStamp, ChangedBy) 
    values(3,1,'Completed','1/3/2012','User2')
insert into ItemLog(ID, ItemID, NewStatus, TimeStamp, ChangedBy) 
    values(4,2,'Created','1/1/2012','User2')
insert into ItemLog(ID, ItemID, NewStatus, TimeStamp, ChangedBy) 
    values(5,2,'Pended','1/2/2012','User3')
insert into ItemLog(ID, ItemID, NewStatus, TimeStamp, ChangedBy) 
    values(6,3,'Cancelled','1/9/2012','User1')
insert into ItemLog(ID, ItemID, NewStatus, TimeStamp, ChangedBy) 
    values(7,3,'Created','1/2/2012','User1')
insert into ItemLog(ID, ItemID, NewStatus, TimeStamp, ChangedBy) 
    values(8,3,'Pended','1/2/2012','User1')

select * from item i left outer join itemlog il on il.ItemID = i.ID

select 
    i.Description,
    FirstStatusDate=minIL.TimeStamp,
    CurrentStatus=maxIL.NewStatus,
    CurrentStatusDate=maxIL.TimeStamp,
    CurrentUser=maxIL.ChangedBy,
    CompletedDate=(select max(TimeStamp) from ItemLog where ItemID=i.ID and NewStatus='Completed'),
    [TotalTime (in days)]=case 
        when 
            minIL.TimeStamp is not null and maxIL.TimeStamp is not null
            then datediff(day,minIL.TimeStamp,maxIL.TimeStamp)
        else
            convert(int,null)
        end,
    TimePending=sum(c.Days)
from
    Item i
    left outer join 
    (
        select 
            y.ItemID,
            y.MinDate,MinItemLogID=min(mn.id),
            y.MaxDate,MaxItemLogID=max(mx.id)
        from
            (
                select 
                    ItemID,MinDate=min(timestamp), MaxDate=max(timestamp)
                from 
                    ItemLog il group by ItemID
            ) as y
            left outer join ItemLog mn on mn.ItemID=y.ItemID and mn.TimeStamp=y.MinDate
            left outer join ItemLog mx on mx.ItemID=y.ItemID and mx.TimeStamp=y.MaxDate
        group by
            y.ItemID, y.MinDate, y.MaxDate
    )
    z on z.ItemID = i.ID
    left outer join ItemLog minIL on minIL.ID = z.MinItemLogID
    left outer join ItemLog maxIL on maxIL.ID = z.MaxItemLogID
    left outer join 
    (
        select
            p.ItemId,
            PendTime=p.TimeStamp,
            PendID=p.ID,
            Days=datediff(day,p.TimeStamp,
                coalesce(
                    (select min(TimeStamp) 
                    from 
                        ItemLog b 
                    where 
                        b.ItemID = P.ItemID and TimeStamp > p.TimeStamp )
                    ,
                    getdate()
                )
            )
        from
            ItemLog p 
        where
            p.NewStatus='Pended'
    ) c on c.ItemID = i.ID
group by
    i.ID,
    i.Description,
    minIL.TimeStamp,
    maxIL.NewStatus,
    maxIL.TimeStamp,
    maxIL.ChangedBy

enter image description here

答案 1 :(得分:0)

Geez ......这是否比以下内容提供了巨大的性能优势?

ALTER FUNCTION [dbo].[GetItemPendedTime] 
(
    -- Add the parameters for the function here
    @ItemId uniqueidentifier
)
RETURNS INT
AS
BEGIN
    -- Declare the return variable here
    DECLARE @status INT
    DECLARE @timespan datetime
    DECLARE @pendTimeMinutes INT = 0
    DECLARE @ispend bit = 0
    DECLARE @lastTimespan datetime  

    DECLARE itemlog_queue CURSOR FOR 
        SELECT Status, Timestamp FROM ItemLog WHERE ItemId = @ItemId

    OPEN itemlog_queue;
    FETCH NEXT FROM itemlog_queue INTO @status, @timespan

    WHILE @@FETCH_STATUS = 0
    BEGIN       
        IF @ispend = 1
            BEGIN
                SET @pendTimeMinutes += DATEDIFF(minute, @lastTimespan, @timespan)
            END
        IF @status = 13
            BEGIN
                SET @ispend = 1
            END
        ELSE
            BEGIN
                SET @ispend = 0         
            END
        SET @lastTimespan = @timespan
        FETCH NEXT FROM itemlog_queue INTO @status, @timespan
    END

    CLOSE itemlog_queue 
    DEALLOCATE itemlog_queue 

    IF @ispend = 1
    BEGIN
        SET @pendTimeMinutes = @pendTimeMinutes + DATEDIFF(minute, @lastTimespan, GETDATE())
    END

    -- Return the result of the function
    RETURN @pendTimeMinutes

END

然后将其称为

SELECT Description, Status as CurrentStatus, dbo.GetItemPendedTime(ItemId) FROM Items