Sql server SQL Server:检测清单更改
我有一个简单的库存表:Sql server SQL Server:检测清单更改,sql-server,sql-server-2012,inventory,stock,Sql Server,Sql Server 2012,Inventory,Stock,我有一个简单的库存表: IF OBJECT_ID('tempdb.dbo.#t') IS NOT NULL DROP TABLE #t GO CREATE TABLE #t ( [date] DATE, Item VARCHAR(1), [Location] INT, Qty INT ) INSERT INTO #t ([date], [Item], [Location], [Qty]) VALUES ('2017-11-16', 'A', 1, 5
IF OBJECT_ID('tempdb.dbo.#t') IS NOT NULL
DROP TABLE #t
GO
CREATE TABLE #t
(
[date] DATE,
Item VARCHAR(1),
[Location] INT,
Qty INT
)
INSERT INTO #t ([date], [Item], [Location], [Qty])
VALUES ('2017-11-16', 'A', 1, 5),
('2017-11-16', 'B', 1, 5),
('2017-11-16', 'B', 2, 10),
('2017-11-16', 'A', 3, 1),
('2017-11-16', 'C', 3, 2),
('2017-11-16', 'A', 4, 20),
('2017-11-15', 'A', 1, 5),
('2017-11-15', 'B', 1, 5),
('2017-11-15', 'B', 2, 10),
('2017-11-15', 'A', 3, 1),
('2017-11-15', 'C', 3, 8),
('2017-11-14', 'A', 1, 10),
('2017-11-14', 'B', 1, 1),
('2017-11-14', 'B', 2, 10),
('2017-11-14', 'A', 3, 1),
('2017-11-14', 'C', 3, 8)
我想找出where子句中的日期,以及过去位置项目级别的数量差异
因此,结果应如下所示:
+------------+------+----------+-----+------------+---------+
| Date | Item | Location | Qty | LastChange | LastQty |
+------------+------+----------+-----+------------+---------+
| 16.11.2017 | A | 1 | 5 | 14.11.2017 | 10 |
| 16.11.2017 | B | 1 | 5 | 14.11.2017 | 1 |
| 16.11.2017 | B | 2 | 10 | | |
| 16.11.2017 | A | 3 | 1 | | |
| 16.11.2017 | C | 3 | 2 | 15.11.2017 | 8 |
| 16.11.2017 | A | 4 | 20 | | |
+------------+------+----------+-----+------------+---------+
由于库存表相当大,如果可能的话,我希望避免使用窗口函数
我已自行加入库存表。但是,我很难找到一个子句来消除不相关的数据集
SELECT
a.[date],
a.Item,
a.Location,
a.qty,
b.[date] LastChange,
b.qty LastQty
FROM
#t a
LEFT JOIN
#t b ON a.Item = b.Item
AND a.location = b.location
AND b.date < a.date
WHERE
a.date = '2017-11-16'
您需要额外的左联接以消除冗余记录:
SELECT a.[date], a.Item, a.Location, a.qty,
b.[date] LastChange, b.qty LastQty
FROM t AS a
LEFT JOIN t AS b
ON a.Item = b.Item AND a.location = b.location AND b.date < a.date AND a.qty != b.qty
LEFT JOIN t AS c
ON c.Item = b.Item AND c.location = b.location AND c.date < b.date
WHERE
a.[date] = '2017-11-16' AND c.Item IS NULL
就像说:给我那些没有其他记录的b记录,c记录,日期更早的记录
使用第一个值窗口函数:
;WITH CTE AS (
SELECT [date], [Item], [Location], [Qty],
FIRST_VALUE([date]) OVER (PARTITION BY [Item], [Location]
ORDER BY [date]) AS LastChange,
FIRST_VALUE([Qty]) OVER (PARTITION BY [Item], [Location]
ORDER BY [date]) AS LastQty
FROM t
)
SELECT [date], [Item], [Location], [Qty],
IIF([Qty] != [LastQty], LastChange, NULL) AS LastChange,
IIF([Qty] != [LastQty], LastQty, NULL) AS LastQty
FROM CTE
WHERE [date] = '2017-11-16'
请尝试此查询
DECLARE @ReportDate date='20171116'
SELECT
curData.[date],
curData.Item,
curData.Location,
curData.Qty,
lastData.[date] LastChange,
lastData.Qty LastQty
FROM
(
SELECT *
FROM #t
WHERE [date]=@ReportDate
) curData
OUTER APPLY
(
SELECT TOP 1 *
FROM #t lastData
WHERE lastData.Item=curData.Item
AND lastData.Location=curData.Location
AND lastData.[date]<curData.[date]
AND lastData.Qty<>curData.Qty
ORDER BY lastData.[date] DESC
) lastData
窗口函数可以比使用子查询更有效。请查找pivot以执行此操作。您使用的是哪个版本的SQL Server?另外,窗口函数的引入是为了提高这种情况下的性能,那么为什么不使用窗口函数呢?如果这样做有积极的影响,那么我很乐意使用窗口函数。服务器版本为11.0.6598.0。谢谢:-@JeanDoux:你是说在MSSQL中使用pivot函数?这不是只在一个专栏上起作用吗?我改变了答案。在我的第一个版本中,我忘记使用条件lastData.QtycurData.QtyHi,到目前为止,我从未真正使用过apply这个概念。我可能想进一步探讨这个问题。谢谢大家!@rasenkantenstein-SQL是一种了不起的语言。祝你在这条路上成功!非常感谢。在这里学到了很多。窗口功能确实必须更快!谢谢。但是使用第一个值时有一个问题。没有检测到中间变化。在您的演示中,您可以在C文章中看到这一点。最后一个变化应该是15.11。不是14.11。@rasenkantenstein所以你想在这种情况下检测最新的记录?如果您有多个更改,如“2017-11-16”、“C”、“3、2”、“2017-11-16”、“C”、“3、8”、“2017-11-16”、“C”、“3、5”,该怎么办。上次变更的日期和变更金额。这是一个每天创建一次的快照表,主键是日期+位置+项目。只有一种状态是可能的。然而,窗口函数确实非常快。
;WITH CTE AS (
SELECT [date], [Item], [Location], [Qty],
FIRST_VALUE([date]) OVER (PARTITION BY [Item], [Location]
ORDER BY [date]) AS LastChange,
FIRST_VALUE([Qty]) OVER (PARTITION BY [Item], [Location]
ORDER BY [date]) AS LastQty
FROM t
)
SELECT [date], [Item], [Location], [Qty],
IIF([Qty] != [LastQty], LastChange, NULL) AS LastChange,
IIF([Qty] != [LastQty], LastQty, NULL) AS LastQty
FROM CTE
WHERE [date] = '2017-11-16'
DECLARE @ReportDate date='20171116'
SELECT
curData.[date],
curData.Item,
curData.Location,
curData.Qty,
lastData.[date] LastChange,
lastData.Qty LastQty
FROM
(
SELECT *
FROM #t
WHERE [date]=@ReportDate
) curData
OUTER APPLY
(
SELECT TOP 1 *
FROM #t lastData
WHERE lastData.Item=curData.Item
AND lastData.Location=curData.Location
AND lastData.[date]<curData.[date]
AND lastData.Qty<>curData.Qty
ORDER BY lastData.[date] DESC
) lastData