在 SQL 中跟踪数字大于 0 的时间量

Tracking the amount of time a number is greater than 0 in SQL

我正在尝试找出一种方法来跟踪零件的数量大于 0 的时间。我在 SQL 服务器中设置了一个 table 像这样。

CREATE TABLE [dbo].[Levels] (
    RecordID    INT IDENTITY(1,1) PRIMARY KEY NOT NULL,
    Timestamp   DATETIME DEFAULT(current_timestamp) NOT NULL,
    Part        VARCHAR(10) NOT NULL,
    QTY         INT NOT NULL
)

有了这个,我只需要在执行插入语句时使用 Part 和 QTY 列。我希望我跟踪的所有部分都从 0 开始,然后有一些数量然后回到 0。我现在使用以下查询来填充 table,每对之间有一个小延迟。

INSERT INTO [dbo].[Levels] (Part, QTY) VALUES('PART1234', 0)
INSERT INTO [dbo].[Levels] (Part, QTY) VALUES('ITEM5678', 0)

几秒钟后。

INSERT INTO [dbo].[Levels] (Part, QTY) VALUES('PART1234', 5)
INSERT INTO [dbo].[Levels] (Part, QTY) VALUES('ITEM5678', 19)

然后再过几秒钟。

INSERT INTO [dbo].[Levels] (Part, QTY) VALUES('PART1234', 0)
INSERT INTO [dbo].[Levels] (Part, QTY) VALUES('ITEM5678', 0)

现在我的 table 中有了这些数据。

  RecordID    Timestamp               Part       QTY
----------- ----------------------- ---------- -----------
1           2017-05-23 13:56:57.123 PART1234   0
2           2017-05-23 13:56:57.123 ITEM5678   0
3           2017-05-23 13:57:00.857 PART1234   5
4           2017-05-23 13:57:00.890 ITEM5678   19
5           2017-05-23 13:57:02.827 PART1234   0
6           2017-05-23 13:57:02.827 ITEM5678   0

现在我已经有了我需要的所有数据,我需要弄清楚如何查看一个项目的 QTY 大于 0 的时间。

例如,我可以计算出 PART1234 的存货时间为 1.97 秒,但我怎样才能从单个 SQL 查询中以下列格式得到这个,这样我就可以看到所有零件和总计库存时间,即使他们在 table?

中进出库存
Part     InStockPeriod
-------- ----------------
PART1234 00:00:01.9700000
ITEM5678 00:00:01.9366667

谢谢,

通过对 Kannan Kandasamy 的回答进行一些调整,我得出了这个结论。虽然它没有 return 时间格式,但它确实 return 商品正确入库的秒数,如果商品当前有货,它将根据 CURRENT_TIMESTAMP 更新。

WITH Thing as (
SELECT *,
        [TimeDiff] = CONVERT(TIME, 
            CASE
                WHEN LEAD(TIMESTAMP, 1, [TimeStamp]) OVER (PARTITION BY Part ORDER BY [TimeStamp]) <> [Timestamp] THEN
                    lead(TIMESTAMP, 1, [TimeStamp]) OVER (PARTITION BY Part ORDER BY [TimeStamp]) - [Timestamp]
                ELSE
                    CURRENT_TIMESTAMP - [TimeStamp]
            END)
    FROM [Levels])
SELECT   Part, 
         sum( DATEPART(SECOND, [TimeDiff]) + 60 * 
              DATEPART(MINUTE, [TimeDiff]) + 3600 * 
              DATEPART(HOUR, [TimeDiff] ) 
            ) as 'TotalTime' 
FROM Thing WHERE QTY > 0
GROUP BY Part

根据样本数据,return就是这个。

Part       TotalTime
---------- -----------
ITEM5678   1
PART1234   1

如果我添加一条记录说 ITEM5678 再次有货。

INSERT INTO [dbo].[Levels] (Part, QTY) VALUES('ITEM5678',1)

只要该项目的最新记录大于 0,查询就会开始以秒为单位计数。

Part       TotalTime
---------- -----------
ITEM5678   20
PART1234   1

非常感谢您的帮助!

我认为递归 CTE 会起作用。使用 SQL 服务器 2008R2 测试:

WITH levelsRanked AS 
(
    SELECT
                l.*
                ,levelRank = ROW_NUMBER() OVER (PARTITION BY l.Part ORDER BY l.RecordID DESC)
    FROM
                [dbo].[Levels]      l
),levelsCTE AS
(
    SELECT
                lr.RecordID
                ,lr.[Timestamp]
                ,lr.Part
                ,lr.QTY
                ,lr.levelRank
                ,TimeSinceChange    = 0
    FROM
                levelsRanked    lr
    WHERE
                lr.levelRank        = 1

    UNION ALL

    SELECT      
                lr.RecordID
                ,lr.[Timestamp]
                ,lr.Part
                ,lr.QTY
                ,lr.levelRank
                ,TimeSinceChange    = DATEDIFF(SECOND, lr.[Timestamp], lc.[Timestamp])
    FROM
                levelsRanked    lr
    INNER JOIN
                levelsCTE       lc
        ON
                lr.Part             = lc.part
            AND lr.levelRank        = lc.levelRank + 1
    WHERE
                lr.levelRank        > 1
)
SELECT
        *
FROM
        levelsCTE
WHERE
        qty > 0

然后您可以执行 GROUP BY 以获取某件商品的总库存时间(如果它要多次进出库存)。

请试试这个

with one as
(select a.* from
(
select Part,qty,Timestamp,ROW_NUMBER() over (partition by Part order by 
Timestamp desc) as RowNum from [Levels]
)a
where RowNum<=2)
select a.Part,DATEDIFF(SS,b.Timestamp,a.Timestamp) as InStockPeriod from one 
a inner join one b on a.RowNum+1=b.RowNum and a.Part=b.Part
where a.RowNum=1 and a.QTY=0

您可以使用提前获取时差如下:

select [Part], --sum(TimeDiff) as InStockPeriod 
    sum(datepart(ms,timediff)/60.00) InStockSeconds
 from (
    select *,
        [TimeDiff] = convert(time, lead(timestamp, 1, [TimeStamp]) over (partition by Part order by [TimeStamp])- [Timestamp])
        --, lead(timestamp) over (partition by Part order by [TimeStamp]) 
    from levels
) a
group by [part]

但是它会把数据转换成秒我们需要把它转换成时间格式