CREATE TABLE [Transaction](
[TransactionID] [bigint] IDENTITY(1,1) NOT NULL,
[LocationID] [int] NOT NULL,
[KioskID] [int] NOT NULL,
[TransactionDate] [datetime] NOT NULL,
[TransactionType] [varchar](7) NOT NULL,
[Credits] [int] NOT NULL,
[StartingBalance] [int] NULL,
[EndingBalance] [int] NULL,
[SessionID] [int] NULL
);
请参考这个小提琴获取样本数据: Link to SQL Fiddle
我正在试图弄清楚是否有办法在一次更新中为一系列交易分配会话编号。
“会话”被定义为以提款结束的多个存款和购买。会话具有包括以下内容的顺序事务:
使用相同的LocationID和KioskID。会话可以以0余额或提款结束。首次存款没有会话开始。只有P交易有余额。对于D和W,它们是NULL。
LocationID,KioskID,SessionID必须是唯一的。
我真的希望有一种SQL方法可以做到这一点。我不想在数以亿计的事务中循环来设置会话。
答案 0 :(得分:1)
这应该这样做:
;WITH markSessions as
(
SELECT *,
CASE
WHEN TransactionType='W' THEN 1
WHEN TransactionType='P' And EndingBalance=0 THEN 1
ELSE 0 END As SessionEnd
FROM Transactions
)
SELECT *,
SUM(SessionEnd) OVER(PARTITION BY LocationID, KioskID ORDER BY TransactionID)
+ 1 - SessionEnd As SessionID
FROM markSessions
不需要触发器,游标或客户端代码。
如果您确实想在表中设置SessionID,那么您将使用这样的UPDATE语句:
;WITH markSessions as
(
SELECT *,
CASE
WHEN TransactionType='W' THEN 1
WHEN TransactionType='P' And EndingBalance=0 THEN 1
ELSE 0 END As SessionEnd
FROM Transactions
)
UPDATE markSessions
SET SessionID = SUM(SessionEnd) OVER(PARTITION BY LocationID, KioskID ORDER BY TransactionID)
+ 1 - SessionEnd
我无法测试它,但以下内容应考虑预先存在的SessionID
;WITH markSessions as
(
SELECT *,
CASE
WHEN TransactionType='W' THEN 1
WHEN TransactionType='P' And EndingBalance=0 THEN 1
ELSE 0 END As SessionEnd
FROM Transactions
)
UPDATE markSessions
SET SessionID = SUM(SessionEnd) OVER(PARTITION BY LocationID, KioskID ORDER BY TransactionID)
+ 1 - SessionEnd
+ COALESCE(MAX(SessionID) OVER (PARTITION BY LocationID, KioskID), 0)
WHERE SessionID Is NULL
请注意,这仅适用于所有新行(没有SessionID的行)的事务ID高于预先存在的行(已有SessionID的行)。如果使用TransactionIDs添加新行,它肯定 NOT 工作,低于已分配SessionID的最高TransactionID。
如果您可能遇到这种情况,那么您可能需要重新分配旧的TransactionID。