मुझे पता है कि यह एक पुराना सवाल है और यह मूल पोस्टर के काम नहीं आएगा, लेकिन मैं इस पर एक स्टैब लेना चाहता था क्योंकि यह एक दिलचस्प सवाल था। मैंने इसका पर्याप्त परीक्षण नहीं किया, इसलिए मुझे उम्मीद है कि इसे अभी भी ठीक करने और ट्यून करने की आवश्यकता है। लेकिन मेरा मानना है कि दृष्टिकोण वैध है। मैं किसी उत्पाद में इस तरह की क्वेरी का उपयोग करने की अनुशंसा नहीं करता क्योंकि इसे बनाए रखना या समझना मुश्किल होगा (और मुझे विश्वास नहीं है कि यह वास्तव में स्केलेबल है)। आप कुछ वैकल्पिक डेटा संरचनाएँ बनाने से बहुत बेहतर होंगे। ऐसा कहने के बाद, मैंने Postgresql 9.1 में यही चलाया:
WITH x AS (
SELECT round, action
,ABS(shares) AS shares
,profitpershare
,COALESCE( SUM(shares) OVER(ORDER BY round, action
ROWS BETWEEN UNBOUNDED PRECEDING
AND 1 PRECEDING)
, 0) AS previous_net_shares
,COALESCE( ABS( SUM(CASE WHEN action = 'SELL' THEN shares ELSE 0 END)
OVER(ORDER BY round, action
ROWS BETWEEN UNBOUNDED PRECEDING
AND 1 PRECEDING) ), 0 ) AS previous_sells
FROM AuctionResults
ORDER BY 1,2
)
SELECT round, shares * profitpershare - deduction AS net
FROM (
SELECT buy.round, buy.shares, buy.profitpershare
,SUM( LEAST( LEAST( sell.shares, GREATEST(buy.shares - (sell.previous_sells - buy.previous_sells), 0)
,GREATEST(sell.shares + (sell.previous_sells - buy.previous_sells) - buy.previous_net_shares, 0)
)
) * sell.profitpershare ) AS deduction
FROM x buy
,x sell
WHERE sell.round > buy.round
AND buy.action = 'BUY'
AND sell.action = 'SELL'
GROUP BY buy.round, buy.shares, buy.profitpershare
) AS y
और परिणाम:
round | net
-------+-----
1 | 780
2 | 420
(2 rows)
इसे टुकड़ों में बांटने के लिए, मैंने इस डेटा सेट के साथ शुरुआत की:
CREATE TABLE AuctionResults( round int, action varchar(4), shares int, profitpershare int);
INSERT INTO AuctionResults VALUES(1, 'BUY', 6, 200);
INSERT INTO AuctionResults VALUES(2, 'BUY', 5, 100);
INSERT INTO AuctionResults VALUES(2, 'SELL',-2, 50);
INSERT INTO AuctionResults VALUES(3, 'SELL',-5, 80);
INSERT INTO AuctionResults VALUES(4, 'SELL', -4, 150);
select * from auctionresults;
round | action | shares | profitpershare
-------+--------+--------+----------------
1 | BUY | 6 | 200
2 | BUY | 5 | 100
2 | SELL | -2 | 50
3 | SELL | -5 | 80
4 | SELL | -4 | 150
(5 rows)
"WITH" क्लॉज में क्वेरी टेबल में कुछ रनिंग टोटल जोड़ती है।
- "पिछला_नेट_शेयर" इंगित करता है कि वर्तमान रिकॉर्ड से पहले कितने शेयर बेचने के लिए उपलब्ध हैं। यह मुझे यह भी बताता है कि इस 'खरीद' को आवंटित करने से पहले मुझे कितने 'सेल' शेयरों को छोड़ना होगा।
-
"previous_sells" सामने आए "SELL" शेयरों की संख्या की एक चालू गणना है, इसलिए दो "previous_sells" के बीच का अंतर उस समय में उपयोग किए गए 'SELL' शेयरों की संख्या को दर्शाता है।
round | action | shares | profitpershare | previous_net_shares | previous_sells -------+--------+--------+----------------+---------------------+---------------- 1 | BUY | 6 | 200 | 0 | 0 2 | BUY | 5 | 100 | 6 | 0 2 | SELL | 2 | 50 | 11 | 0 3 | SELL | 5 | 80 | 9 | 2 4 | SELL | 4 | 150 | 4 | 7 (5 rows)
इस तालिका के साथ, हम एक स्व-जुड़ना कर सकते हैं जहां प्रत्येक "खरीदें" रिकॉर्ड प्रत्येक भविष्य के "सेल" रिकॉर्ड से जुड़ा होता है। परिणाम इस तरह दिखेगा:
SELECT buy.round, buy.shares, buy.profitpershare
,sell.round AS sellRound, sell.shares AS sellShares, sell.profitpershare AS sellProfitpershare
FROM x buy
,x sell
WHERE sell.round > buy.round
AND buy.action = 'BUY'
AND sell.action = 'SELL'
round | shares | profitpershare | sellround | sellshares | sellprofitpershare
-------+--------+----------------+-----------+------------+--------------------
1 | 6 | 200 | 2 | 2 | 50
1 | 6 | 200 | 3 | 5 | 80
1 | 6 | 200 | 4 | 4 | 150
2 | 5 | 100 | 3 | 5 | 80
2 | 5 | 100 | 4 | 4 | 150
(5 rows)
और फिर पागल हिस्सा आता है जो ऑर्डर में बेचने के लिए उपलब्ध शेयरों की संख्या की गणना करने की कोशिश करता है बनाम शेयर की संख्या जो अभी तक एक खरीद के लिए नहीं बेची गई है। इसका पालन करने में सहायता के लिए यहां कुछ नोट्स दिए गए हैं। "0" के साथ "सबसे बड़ी" कॉल केवल यह कह रही हैं कि अगर हम नकारात्मक हैं तो हम कोई शेयर आवंटित नहीं कर सकते।
-- allocated sells
sell.previous_sells - buy.previous_sells
-- shares yet to sell for this buy, if < 0 then 0
GREATEST(buy.shares - (sell.previous_sells - buy.previous_sells), 0)
-- number of sell shares that need to be skipped
buy.previous_net_shares
डेविड को उनके सहायता