SQL - 确定特定审计表中值增加和减少的位置
Posted
技术标签:
【中文标题】SQL - 确定特定审计表中值增加和减少的位置【英文标题】:SQL - Identify where values have increased and decreased in a specific audit table 【发布时间】:2018-03-29 14:05:31 【问题描述】:我有两张表,基本上记录了用户可以存储在三个不同容器中的最大重量(KG):
dbo.Storage 包含用户的最新值(第一个屏幕截图) dbo.AuditStorage 基本上审计这些值的变化(第二个截图)dbo.AuditStorage 的工作方式如下(截图如下):
表格最初是空的,当它第一次被填充时,将自动插入 3 行(这是由触发器完成的):
-
第一行已插入,但仅填充 Max_Storage1,而
剩余的存储空间保持为 NULL。
毫秒后,插入另一行。 Max_Storage1 值
被持久化并且 Max_Storage2 被填充,而 Max_Storage3
保持为 NULL。
毫秒后,插入另一行。 Max_Storage1 和
Max_Storage2 值被持久化,最后是 Max_Storage3 值
已填充。
在上面的截图中,我们可以看到一个月后用户决定将他的 Max_Storage1 从 50 增加到 100 并将他的 Max_Storage2 从 500 减少到 400。 此处应用相同的逻辑:
-
首先插入一行并更新 Max_Storage1 而其他 Max_Storage_X 保持不变
然后插入另一行并更新 Max_Storage2
因为 Max_Storage3 保持不变,所以没有插入任何行。
我的目标是能够编写一个查询,返回一个用户列表,其中一个 Max_Storage_X 值增加而另一个减少。
请问我怎样才能做到这一点?
【问题讨论】:
请阅读this,了解一些改进问题的技巧。 请不要破坏您的帖子。 【参考方案1】:你可以试试这样的:
DECLARE @DataSource TABLE
(
[UserID] BIGINT
,[Max_Storage1] INT
,[Max_Storage2] INT
,[Max_Storage3] INT
,[UpdateTime] DATETIME2
);
INSERT INTO @DataSource ([UserID], [Max_Storage1], [Max_Storage2], [Max_Storage3], [UpdateTime])
VALUES (1, 50, NULL, NULL, DATEADD(DAY, 1, GETUTCDATE()))
,(1, 50, 500, NULL, DATEADD(DAY, 2, GETUTCDATE()))
,(1, 50, 500, 900, DATEADD(DAY, 3, GETUTCDATE()))
,(1, 100, 500, 900, DATEADD(DAY, 4, GETUTCDATE()))
,(1, 100, 400, 900, DATEADD(DAY, 5, GETUTCDATE()))
,(2, 50, NULL, NULL, DATEADD(DAY, 6, GETUTCDATE()))
,(2, 50, 500, NULL, DATEADD(DAY, 7, GETUTCDATE()));
WITH DataSource AS
(
SELECT ROW_NUMBER() OVER(PARTITION BY [UserID] ORDER BY [UpdateTime]) AS [RowID]
,*
FROM @DataSource
),
DataSourcePrecalc AS
(
SELECT DS1.*
,ISNULL(DS1.[Max_Storage1] - DS2.[Max_Storage1], 0) + ISNULL(DS1.[Max_Storage2] - DS2.[Max_Storage2], 0) + ISNULL(DS1.[Max_Storage3] - DS2.[Max_Storage3], 0) AS [CurrDirection]
,LAG(ISNULL(DS1.[Max_Storage1] - DS2.[Max_Storage1], 0) + ISNULL(DS1.[Max_Storage2] - DS2.[Max_Storage2], 0) + ISNULL(DS1.[Max_Storage3] - DS2.[Max_Storage3], 0), 1, 0) OVER (PARTITION BY DS1.[UserID] ORDER BY DS1.[RowID]) AS [PrevDirection]
FROM DataSource DS1
INNER JOIN DataSource DS2
ON DS1.[UserID] = DS2.[UserID]
AND DS1.[RowID] = DS2.[RowID] + 1
)
SELECT *
FROM DataSourcePrecalc
WHERE [CurrDirection] < 0 AND [PrevDirection] > 0;
这个想法是为特定用户插入的每条记录计算RowID
。然后在第二个CTE
中我们得到这个结果:
我们有当前值(上或下)和上一个值(上或下)。所以我们只需要使用这一行,当前值为负,而上一个为正。
【讨论】:
【参考方案2】:我看到的问题是,您没有任何字段可供分组,以便进行比较所需的自联接。
这里是一些示例代码。您需要添加另一个 OR 条件来比较 Max_storage1 和 maxstorage3,以及 Max_storage2 和 maxstorage3
SELECT IDENTITY(int,1,1) AS rownum, *
INTO #temp_audit
FROM dbo.Auditstorage
ORDER BY UPDATE_time
SELECT * FROM #temp_audit a
INNER JOIN #temp_audit b
ON a.rownum = b.rownum -2
AND a.userid = b.userid
WHERE
(
(a.Max_storage1 < b.Max_storage1 AND a.Max_storage2 > b.Max_storage2)
OR
(a.Max_storage1 > b.Max_storage1 AND a.Max_storage2 < b.Max_storage2)
)
【讨论】:
以上是关于SQL - 确定特定审计表中值增加和减少的位置的主要内容,如果未能解决你的问题,请参考以下文章