कुल चल रहा है। अद्यतन अस्थायी तालिका बनाम सीटीई
create table Test(
OrderID int primary key,
Qty int not null
);
declare @i int = 1;
while @i <= 5000 begin
insert into Test(OrderID, Qty) values (@i * 2,rand() * 10);
set @i = @i + 1;
end;
पुनरावर्ती समाधान 9 सेकंड लगते हैं:
with T AS
(
select ROW_NUMBER() over(order by OrderID) as rn, * from test
)
,R(Rn, OrderId, Qty, RunningTotal) as
(
select Rn, OrderID, Qty, Qty
from t
where rn = 1
union all
select t.Rn, t.OrderId, t.Qty, p.RunningTotal + t.Qty
from t t
join r p on t.rn = p.rn + 1
)
select R.OrderId, R.Qty, R.RunningTotal from r
option(maxrecursion 0);
अद्यतन तालिका 0 सेकंड लेता है:
create function TestRunningTotal()
returns @ReturnTable table(
OrderId int, Qty int, RunningTotal int
)
as begin
insert into @ReturnTable(OrderID, Qty, RunningTotal)
select OrderID, Qty, 0 from Test
order by OrderID;
declare @RunningTotal int = 0;
update @ReturnTable set
RunningTotal = @RunningTotal,
@RunningTotal = @RunningTotal + Qty;
return;
end;
वे दो दृष्टिकोण कम से कम आपको अपनी क्वेरी बनाने के लिए एक ढांचा दे सकते हैं।
SQL सर्वर में BTW, MySQL के विपरीत, चर असाइनमेंट का क्रम मायने नहीं रखता। यह:
update @ReturnTable set
RunningTotal = @RunningTotal,
@RunningTotal = @RunningTotal + Qty;
और निम्नलिखित:
update @ReturnTable set
@RunningTotal = @RunningTotal + Qty,
RunningTotal = @RunningTotal;
वे दोनों एक ही तरह से निष्पादित करते हैं, यानी वैरिएबल असाइनमेंट पहले होते हैं, स्टेटमेंट में वेरिएबल असाइनमेंट की स्थिति की परवाह किए बिना। दोनों प्रश्नों का एक ही आउटपुट है:
OrderId Qty RunningTotal
----------- ----------- ------------
2 4 4
4 8 12
6 4 16
8 5 21
10 3 24
12 8 32
14 2 34
16 9 43
18 1 44
20 2 46
22 0 46
24 2 48
26 6 54
अपनी सटीक तालिका पर, बस खरीदें/बेचना का पता लगाएं, आप या तो इसे क्रमशः 1 और -1 से गुणा कर सकते हैं, या आप केवल फ़ील्ड पर हस्ताक्षर कर सकते हैं, उदा। :
update @ReturnTable set
@RunningTotal = @RunningTotal +
CASE WHEN BuySell = 'Buy' THEN Qty ELSE -Qty END,
RunningTotal = @RunningTotal;
यदि आप SQL Server 2012 में अपग्रेड करते हैं, तो यहां कुल रनिंग का सीधा कार्यान्वयन है:
select OrderID, Qty, sum(Qty) over(order by OrderID) as RunningTotal
from Test
आपकी सटीक समस्या पर:
select OrderID, Qty,
sum(CASE WHEN BuySell = 'Buy' THEN Qty ELSE -Qty END)
over(order by OrderID) as RunningTotal
from Test;
अपडेट करें
अगर आप से असहज महसूस करते हैं। विचित्र अपडेट , आप यह जांचने के लिए एक गार्ड क्लॉज लगा सकते हैं कि क्या अद्यतन की जाने वाली पंक्तियों का क्रम मूल क्रम से मेल खाता है (पहचान द्वारा सहायता प्राप्त (1,1)):
create function TestRunningTotalGuarded()
returns @ReturnTable table(
OrderId int, Qty int,
RunningTotal int not null,
RN int identity(1,1) not null
)
as begin
insert into @ReturnTable(OrderID, Qty, RunningTotal)
select OrderID, Qty, 0 from Test
order by OrderID;
declare @RunningTotal int = 0;
declare @RN_check INT = 0;
update @ReturnTable set
@RN_check = @RN_check + 1,
@RunningTotal =
(case when RN = @RN_check then @RunningTotal + Qty else 1/0 end),
RunningTotal = @RunningTotal;
return;
end;
यदि UPDATE वास्तव में अप्रत्याशित क्रम में पंक्तियों को अपडेट करता है (या किसी भी तरह से यह होगा), तो @RN_Check अब RN (पहचान आदेश) के बराबर नहीं होगा, कोड एक डिवाइड-बाय-जीरो एरर बढ़ाएगा। फिर। गार्ड क्लॉज का उपयोग करते हुए, अप्रत्याशित अपडेट ऑर्डर तेजी से विफल हो जाएगा।; अगर ऐसा होता है, तो यह समय एक <स्ट्राइक>बगस्ट्राइक> दर्ज करने का होगा Microsoft से अनुरोध करें कि इस विचित्र अद्यतन को इतना विचित्र न बनाया जाए :-)
स्वाभाविक रूप से अनिवार्य संचालन (चर असाइनमेंट) पर गार्ड क्लॉज हेज वास्तव में अनुक्रमिक है।