sql-server - 避免使用while循环来检查行“状态变化”
问题描述
我有一个存储 Id、日期时间和 int 新月值的表。该值会增加,直到它“中断”并返回到接近 0 的值。例如:...1000、1200、1350、8、10、25...我需要计算这种“溢出”发生了多少次,但是...我说的是每天存储 200k 行的表!我已经解决了!但是使用带有游标的过程,该游标通过while循环对其进行迭代。但我知道这不是更快的方法。
有人可以帮我找到另一种方法吗?谢谢!
->
表结构:Id Bigint Primary Key、CreatedAt DateTime、Value Not Null Int。
问题:如果两个连续行之间的 Delta-Value < 0,则增加一个计数器。表每天有 200k 新行。不允许触发。
[第一次编辑]
Table has the actual structure:
CREATE TABLE ValuesLog (
Id BIGINT PRIMARY KEY,
Machine BIGINT,
CreatedAt DATETIME,
Value INT
)
我需要:检查某些[Machine]的[Value]何时突然降低。
一些用户说使用了 LEAD/LAG。但它有一个问题......如果我选择了很多机器,LEAD/LAG 功能并不关心“它是什么机器”。因此,如果我找到机器 1 和机器 2,如果机器 1 增加但机器 2 减少,则 LEAD/LAG 会给我一个误报。
所以,我的表实际上看起来如何: 实际表的许多行
(上面的图像选择了 3 或 4 台机器。但是,在这个例子中,机器没有搞砸。但是可能会发生!在这种情况下,LEAD/LAG 不关心上面的行是 machine-1 还是机器-2)
我想要什么:在第 85 行,[value] 中断并重新启动。我想计算每一次发生时,选定的机器。所以:“机器 1 重启了 6 次……机器 9 重启了 10 次……”
我做过这样的事情:
CREATE PROCEDURE CountProduction @Machine INT_ARRAY READONLY, @Start DATETIME, @End DATETIME AS
SET NOCOUNT ON
-- Declare counter and insert start values
DECLARE @Counter TABLE(
machine INT PRIMARY KEY,
lastValue BIGINT DEFAULT 0,
count BIGINT DEFAULT 0
)
INSERT INTO @Counter(machine) SELECT n FROM @Machine
-- Declare cursor to iteract over results of values log
DECLARE valueCursor CURSOR LOCAL FOR
SELECT
Value,
Aux.LastValue,
Aux.count
FROM
ValueLog,
@Machine AS Machine,
@Counter AS Counter
WHERE
ValueLog.Machine = Machine.n
AND Counter.machine = ValueLog.Machine
AND ValueLog.DateCreate BETWEEN @Start AND @End;
-- Start iteration
OPEN valueCursor
DECLARE @RowMachine INT
DECLARE @RowValue BIGINT
DECLARE @RowLastValue BIGINT
DECLARE @RowCount BIGINT
FETCH NEXT FROM valueCursor INTO @RowMachine, @RowValue, @RowLastValue, @RowCount
-- Iteration
DECLARE @increment INT
WHILE @@FETCH_STATUS = 0
BEGIN
IF @RowValue < @RowLastValue
SET @increment = 1
ELSE
SET @increment = 0
-- Update counters
UPDATE
@Counter
SET
lastValue = @RowValue,
count = count + @increment
WHERE
inj = @RowMachine
-- Proceed to iteration
FETCH NEXT FROM valueCursor INTO @RowMachine, @RowValue, @RowLastValue, @RowCount
END
-- Closing iteration
CLOSE valueCursor
DEALLOCATE valueCursor
SELECT machine, count FROM @Counter
解决方案
建议使用@jeroen-mostert 解决
DECLARE @Start DATETIME
DECLARE @End DATETIME
SET @Start = '2019-01-01'
SET @End = GETDATE()
SELECT
Machine,
COUNT(DeltaValue) AS Prod
FROM
(SELECT
Log.Machine,
Log.Value - LAG(Log.Value) OVER (PARTITION BY Log.Machine ORDER BY Log.Id) AS DeltaValue
FROM
ValueLog AS Log,
(SELECT
Id,
Machine,
Value
FROM
ValueLog
) AS AuxLog
WHERE
AuxLog.Id = Log.Id
AND Proto.DateCreate BETWEEN @Start AND @End
AND Proto.Machine IN (1, 9, 10)
) as TB1
WHERE
DeltaValue < 0
GROUP BY
Machine
ORDER BY
Machine
在这种情况下,内部 LAG/LEAD 函数并没有弄乱内容(当我创建视图时出于某种原因发生了什么......我稍后会尝试理解)。
谢谢大家!我是 DB 的新手,这个问题让我疯狂了一整天。
推荐阅读
- python - 对数字列表进行分组/聚类,以使每个子集的最小-最大间隙始终小于 Python 中的截止值
- algorithm - 是否有已知的车辆路线覆盖算法?
- c# - unity 2d 网格三角形
- python - 使用 polyfit 函数后如何绘制信号的趋势线?
- python - 三元组损失 Tensorflow 的损失 nan
- typescript - 为什么我不能使这种类型通用?类型“x”不能用于索引类型“y”ts(2536)
- c# - 在 WPF 应用程序中使用 ComboBox 时出现错误“使用 ItemsSource 之前项目集合必须为空”
- java - 使用快速排序算法的 Arraylist 的第 K 个最小元素
- http - 从 http 重定向到 https 在 .htaccess 中不起作用
- java - 出现错误“无法找到 cfg.xml 资源 [hibernate.cfg.xml]”