在 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]
但是它会把数据转换成秒我们需要把它转换成时间格式
我正在尝试找出一种方法来跟踪零件的数量大于 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]
但是它会把数据转换成秒我们需要把它转换成时间格式