2012-02-28 19 views
5

मैं लेनदेन के साथ एक मेज है:एसक्यूएल: चयन लेनदेन जहां पंक्तियों में एक ही तालिका के अंदर मानदंडों में से नहीं हैं

Transactions 
------------ 
id | account | type | date_time    | amount 
---------------------------------------------------- 
1 | 001  | 'R' | '2012-01-01 10:01:00' | 1000 
2 | 003  | 'R' | '2012-01-02 12:53:10' | 1500 
3 | 003  | 'A' | '2012-01-03 13:10:01' | -1500 
4 | 002  | 'R' | '2012-01-03 17:56:00' | 2000 
5 | 001  | 'R' | '2012-01-04 12:30:01' | 1000 
6 | 002  | 'A' | '2012-01-04 13:23:01' | -2000 
7 | 003  | 'R' | '2012-01-04 15:13:10' | 3000 
8 | 003  | 'R' | '2012-01-05 12:12:00' | 1250 
9 | 003  | 'A' | '2012-01-06 17:24:01' | -1250 

और मैं निश्चित प्रकार ('आर') का चयन करना चाहते हैं, लेकिन उन नहीं है कि immediatly दायर एक ही खाते के लिए एक और प्रकार ('ए') का एक और लेन-देन है (DATE_TIME क्षेत्र के क्रम में) ...

तो, क्वेरी निम्न पंक्तियों फेंक चाहिए, पिछले उदाहरण दिया:

id | account |type | date     | amount 
---------------------------------------------------- 
1 | 001  | 'R' | '2012-01-01 10:01:00' | 1000 
5 | 001  | 'R' | '2012-01-04 12:30:01' | 1000 
7 | 003  | 'R' | '2012-01-04 15:13:10' | 3000 

(जैसा कि आप देख सकते हैं, पंक्ति 2 प्रदर्शित नहीं होती है क्योंकि पंक्ति 3 'इसे रद्द करता है' ... पंक्ति 4 द्वारा पंक्ति 4 'रद्द' भी होती है; पंक्ति 7 प्रकट होता है (भले ही खाता 003 रद्द पंक्ति # 2 से संबंधित है, इस बार पंक्ति 7 में यह किसी भी 'ए' पंक्ति द्वारा रद्द नहीं किया गया है); और पंक्ति 8 दिखाई नहीं देगी (यह 003 खाते के लिए भी है क्योंकि अब यह 9 तक रद्द कर दिया गया है, जो 7 को भी रद्द नहीं करता है, केवल पूर्ववर्ती व्यक्ति: 8 ...

मैंने जॉइन, सबक्वायरीज़ में शामिल होने का प्रयास किया है कहाँ खंड लेकिन मैं सच में यकीन है कि कैसे मैं अपने प्रश्न करना चाहिए नहीं हूँ ...

मैं क्या कोशिश की है:

कोशिश कर रहा मिलती है:

SELECT trans.type as type, 
      trans.amount as amount, 
      trans.date_time as dt, 
      trans.account as acct, 
    FROM Transactions trans 
INNER JOIN (SELECT t.type AS type, t.acct AS acct, t.date_time AS date_time 
       FROM Transactions t 
       WHERE t.date_time > trans.date_time 
      ORDER BY t.date_time DESC 
     ) AS nextTrans 
     ON nextTrans.acct = trans.acct 
    WHERE trans.type IN ('R') 
     AND nextTrans.type NOT IN ('A') 
ORDER BY DATE(trans.date_time) ASC 

यह एक त्रुटि फेंकता है, के बाद से मैं यह कर सकते हैं MySQL में जॉइन को बाहरी मान लागू नहीं करें।

जहां में

कोशिश कर रहा सबक्वेरी:

SELECT trans.type as type, 
      trans.amount as amount, 
      trans.date_time as dt, 
      trans.account as acct, 
    FROM Transactions trans 
    WHERE trans.type IN ('R') 
     AND trans.datetime < 
      (SELECT t.date_time AS date_time 
       FROM Transactions t 
       WHERE t.account = trans.account 
      ORDER BY t.date_time DESC 
     ) AS nextTrans 
     ON nextTrans.acct = trans.acct 

ORDER BY DATE(trans.date_time) ASC 

यह गलत है, मैं MySQL में कहां के लिए बाहरी मान लागू करने के लिए प्राप्त कर सकते हैं, लेकिन मैं जिस तरह से मैं क्या जरूरत के लिए सही ढंग से फिल्टर करने के लिए खोजने के लिए प्रबंधित नहीं कर सकते ...

महत्वपूर्ण संपादन:

मैं एक समाधान प्राप्त करने में कामयाब रहा, लेकिन अब इसे गंभीर अनुकूलन की आवश्यकता है। संदेश यह है:

SELECT * 
    FROM (SELECT t1.*, tFlagged.id AS cancId, tFlagged.type AS cancFlag 
      FROM transactions t1 
    LEFT JOIN (SELECT t2.* 
        FROM transactions t2 
       ORDER BY t2.date_time ASC) tFlagged 
      ON (t1.account=tFlagged.account 
        AND 
       t1.date_time < tFlagged.date_time) 
     WHERE t1.type = 'R' 
     GROUP BY t1.id) tCanc 
WHERE tCanc.cancFlag IS NULL 
    OR tCanc.cancFlag <> 'A' 

मैं खुद के साथ तालिका में शामिल हो गए, बस एक ही खाते और महान DATE_TIME पर विचार। जॉइन डेटटाइम द्वारा आदेश दिया जाता है। आईडी द्वारा ग्रुपिंग मैं केवल शामिल होने का पहला परिणाम प्राप्त करने में कामयाब रहा, जो एक ही खाते के लिए अगला लेनदेन होता है।

फिर बाहरी चयन पर, मैं उन लोगों को फ़िल्टर करता हूं जिनके पास 'ए' है, क्योंकि इसका मतलब है कि अगला लेनदेन प्रभावी रूप से इसके लिए रद्द कर दिया गया था। दूसरे शब्दों में, यदि एक ही खाते के लिए कोई अगला लेनदेन नहीं है या यदि अगला लेनदेन 'आर' है, तो इसे रद्द नहीं किया गया है और इसे परिणाम में दिखाया जाना चाहिए ...

मुझे यह मिला:

+----+---------+------+---------------------+--------+--------+----------+ 
| id | account | type | date_time   | amount | cancId | cancFlag | 
+----+---------+------+---------------------+--------+--------+----------+ 
| 1 | 001  | R | 2012-01-01 10:01:00 | 1000 |  5 | R  | 
| 5 | 001  | R | 2012-01-04 12:30:01 | 1000 | NULL | NULL  | 
| 7 | 003  | R | 2012-01-04 15:13:10 | 3000 |  8 | R  | 
+----+---------+------+---------------------+--------+--------+----------+ 

यह प्रत्येक लेनदेन को एक ही खाते के लिए अगली बार संबंधित करता है और फिर रद्द कर दिया गया है ... सफलता !!

जैसा कि मैंने कहा, समस्या अब अनुकूलन है। मेरे वास्तविक डेटा में बहुत सारी पंक्तियां हैं (जैसे समय के साथ लेन-देन वाले लेन-देन की मेजबानी की उम्मीद है), और अभी ~ 10,000 पंक्तियों की एक तालिका के लिए, मुझे 1min.44sec में इस क्वेरी के साथ सकारात्मक परिणाम मिला। मुझे लगता है कि इसमें शामिल होने वाली बात है ... (उन लोगों के लिए जो यहां प्रोटोकॉल को जानते हैं, मुझे क्या करना चाहिए? यहां एक नया प्रश्न लॉन्च करें और इसे इस समाधान के रूप में पोस्ट करें?? या बस यहाँ और अधिक जवाब के लिए इंतजार)

+0

जो आपने कोशिश की है उसे पोस्ट करें। –

+0

वहाँ है ... –

+0

देखें: http://meta.stackexchange.com/questions/2950/should-hi-thanks-taglines-and-salutations-be-removed-from-posts –

उत्तर

1

यहाँ एक समाधान नेस्टेड सबक्वेरी पर आधारित है। सबसे पहले, मैंने कुछ और मामलों को पकड़ने के लिए कुछ पंक्तियां जोड़ दीं। लेनदेन 10, उदाहरण के लिए, लेनदेन 12 द्वारा रद्द नहीं किया जाना चाहिए, क्योंकि लेनदेन 11 के बीच आता है।

> select * from transactions order by date_time; 
+----+---------+------+---------------------+--------+ 
| id | account | type | date_time   | amount | 
+----+---------+------+---------------------+--------+ 
| 1 |  1 | R | 2012-01-01 10:01:00 | 1000 | 
| 2 |  3 | R | 2012-01-02 12:53:10 | 1500 | 
| 3 |  3 | A | 2012-01-03 13:10:01 | -1500 | 
| 4 |  2 | R | 2012-01-03 17:56:00 | 2000 | 
| 5 |  1 | R | 2012-01-04 12:30:01 | 1000 | 
| 6 |  2 | A | 2012-01-04 13:23:01 | -2000 | 
| 7 |  3 | R | 2012-01-04 15:13:10 | 3000 | 
| 8 |  3 | R | 2012-01-05 12:12:00 | 1250 | 
| 9 |  3 | A | 2012-01-06 17:24:01 | -1250 | 
| 10 |  3 | R | 2012-01-07 00:00:00 | 1250 | 
| 11 |  3 | R | 2012-01-07 05:00:00 | 4000 | 
| 12 |  3 | A | 2012-01-08 00:00:00 | -1250 | 
| 14 |  2 | R | 2012-01-09 00:00:00 | 2000 | 
| 13 |  3 | A | 2012-01-10 00:00:00 | -1500 | 
| 15 |  2 | A | 2012-01-11 04:00:00 | -2000 | 
| 16 |  2 | R | 2012-01-12 00:00:00 | 5000 | 
+----+---------+------+---------------------+--------+ 
16 rows in set (0.00 sec) 

सबसे पहले, प्रत्येक लेन-देन, "हाल ही में लेन-देन की तारीख से पहले एक ही खाते में है कि एक" के लिए आकर्षित करने के लिए, एक प्रश्न बनाने के लिए:

SELECT t2.*, 
     MAX(t1.date_time) AS prev_date 
FROM transactions t1 
JOIN transactions t2 
ON (t1.account = t2.account 
    AND t2.date_time > t1.date_time) 
GROUP BY t2.account,t2.date_time 
ORDER BY t2.date_time; 

+----+---------+------+---------------------+--------+---------------------+ 
| id | account | type | date_time   | amount | prev_date   | 
+----+---------+------+---------------------+--------+---------------------+ 
| 3 |  3 | A | 2012-01-03 13:10:01 | -1500 | 2012-01-02 12:53:10 | 
| 5 |  1 | R | 2012-01-04 12:30:01 | 1000 | 2012-01-01 10:01:00 | 
| 6 |  2 | A | 2012-01-04 13:23:01 | -2000 | 2012-01-03 17:56:00 | 
| 7 |  3 | R | 2012-01-04 15:13:10 | 3000 | 2012-01-03 13:10:01 | 
| 8 |  3 | R | 2012-01-05 12:12:00 | 1250 | 2012-01-04 15:13:10 | 
| 9 |  3 | A | 2012-01-06 17:24:01 | -1250 | 2012-01-05 12:12:00 | 
| 10 |  3 | R | 2012-01-07 00:00:00 | 1250 | 2012-01-06 17:24:01 | 
| 11 |  3 | R | 2012-01-07 05:00:00 | 4000 | 2012-01-07 00:00:00 | 
| 12 |  3 | A | 2012-01-08 00:00:00 | -1250 | 2012-01-07 05:00:00 | 
| 14 |  2 | R | 2012-01-09 00:00:00 | 2000 | 2012-01-04 13:23:01 | 
| 13 |  3 | A | 2012-01-10 00:00:00 | -1500 | 2012-01-08 00:00:00 | 
| 15 |  2 | A | 2012-01-11 04:00:00 | -2000 | 2012-01-09 00:00:00 | 
| 16 |  2 | R | 2012-01-12 00:00:00 | 5000 | 2012-01-11 04:00:00 | 
+----+---------+------+---------------------+--------+---------------------+ 
13 rows in set (0.00 sec) 

उपयोग है कि एक सबक्वेरी के रूप में प्राप्त करने के लिए प्रत्येक लेनदेन और उसके पूर्ववर्ती एक ही पंक्ति पर। लेनदेन हम में रुचि रखते हैं बाहर निकलने के लिए कुछ फ़िल्टरिंग का उपयोग करें - अर्थात्, 'ए' लेन-देन जिसका पूर्ववर्तियों हैं 'आर' लेनदेन है कि वे वास्तव में रद्द हो - परिणाम से

SELECT 
    t3.*,transactions.* 
FROM 
    transactions 
    JOIN 
    (SELECT t2.*, 
      MAX(t1.date_time) AS prev_date 
    FROM transactions t1 
    JOIN transactions t2 
    ON (t1.account = t2.account 
     AND t2.date_time > t1.date_time) 
    GROUP BY t2.account,t2.date_time) t3 
    ON t3.account = transactions.account 
    AND t3.prev_date = transactions.date_time 
    AND t3.type='A' 
    AND transactions.type='R' 
    AND t3.amount + transactions.amount = 0 
    ORDER BY t3.date_time; 


+----+---------+------+---------------------+--------+---------------------+----+---------+------+---------------------+--------+ 
| id | account | type | date_time   | amount | prev_date   | id | account | type | date_time   | amount | 
+----+---------+------+---------------------+--------+---------------------+----+---------+------+---------------------+--------+ 
| 3 |  3 | A | 2012-01-03 13:10:01 | -1500 | 2012-01-02 12:53:10 | 2 |  3 | R | 2012-01-02 12:53:10 | 1500 | 
| 6 |  2 | A | 2012-01-04 13:23:01 | -2000 | 2012-01-03 17:56:00 | 4 |  2 | R | 2012-01-03 17:56:00 | 2000 | 
| 9 |  3 | A | 2012-01-06 17:24:01 | -1250 | 2012-01-05 12:12:00 | 8 |  3 | R | 2012-01-05 12:12:00 | 1250 | 
| 15 |  2 | A | 2012-01-11 04:00:00 | -2000 | 2012-01-09 00:00:00 | 14 |  2 | R | 2012-01-09 00:00:00 | 2000 | 
+----+---------+------+---------------------+--------+---------------------+----+---------+------+---------------------+--------+ 
4 rows in set (0.00 sec) 

ऊपर यह स्पष्ट है कि हम लगभग समाप्त हो गई वहां - हमने अवांछित लेन-देन की पहचान की है। LEFT JOIN का उपयोग करके हम इन्हें पूरे लेनदेन सेट से फ़िल्टर कर सकते हैं:

SELECT 
    transactions.* 
FROM 
    transactions 
LEFT JOIN 
    (SELECT 
    transactions.id 
    FROM 
    transactions 
    JOIN 
    (SELECT t2.*, 
      MAX(t1.date_time) AS prev_date 
     FROM transactions t1 
     JOIN transactions t2 
     ON (t1.account = t2.account 
     AND t2.date_time > t1.date_time) 
     GROUP BY t2.account,t2.date_time) t3 
    ON t3.account = transactions.account 
     AND t3.prev_date = transactions.date_time 
     AND t3.type='A' 
     AND transactions.type='R' 
     AND t3.amount + transactions.amount = 0) t4 
    USING(id) 
    WHERE t4.id IS NULL 
    AND transactions.type = 'R' 
    ORDER BY transactions.date_time; 

+----+---------+------+---------------------+--------+ 
| id | account | type | date_time   | amount | 
+----+---------+------+---------------------+--------+ 
| 1 |  1 | R | 2012-01-01 10:01:00 | 1000 | 
| 5 |  1 | R | 2012-01-04 12:30:01 | 1000 | 
| 7 |  3 | R | 2012-01-04 15:13:10 | 3000 | 
| 10 |  3 | R | 2012-01-07 00:00:00 | 1250 | 
| 11 |  3 | R | 2012-01-07 05:00:00 | 4000 | 
| 16 |  2 | R | 2012-01-12 00:00:00 | 5000 | 
+----+---------+------+---------------------+--------+ 
+0

हाँ लगभग वहाँ! लेकिन 11, यदि इसे 12 तक रद्द किया गया है, तो अंतिम परिणाम पर क्यों दिखाई देता है? –

+0

ठीक है मैंने सवाल को गलत समझा; मैंने ए को रद्दीकरण के लिए सोचा था, इसकी 'राशि' फ़ील्ड को आर पंक्ति में राशि की अस्वीकृति होनी चाहिए थी। 'और t3.amount + redirect.amount = 0' खंड से छुटकारा पाने से इस बाधा को दूर करना चाहिए (और जो भी आप खोज रहे हैं) – gcbenison

+0

प्रतीक्षा करें! तुम मुझसे ज्यादा सही हो! मैंने उस विवरण को नहीं देखा, निश्चित रूप से वह है जो मैं ढूंढ रहा हूं :) मुझे और परीक्षण करने दो! मुझे लगता है कि यह आखिरकार सही है :) –

1

(संपादित 2) इस कोशिश:

SELECT trans.tp as type, 
trans.id as id, 
trans.amount as amount, 
trans.date_time as dt, 
trans.account as acct 
FROM Transactions trans 
WHERE trans.tp = 'R' 
AND trans.account NOT IN (SELECT t.account AS acct 
    FROM Transactions t 
WHERE t.date_time > trans.date_time 
AND t.tp = 'A' 
AND t.amount = (trans.amount)-((trans.amount)*2) 
    ORDER BY t.date_time DESC 
) ; 
+0

mmmm शायद ... बस एक शक ... क्यों <= डेट_टाइम में जहां खंड? 'ए' पंक्तियों को कुछ 'आर' पंक्ति के बाद मौजूद होना चाहिए, इसलिए किसी भी 'आर' को रद्द करने के लिए, तो वहां 'ए' पंक्ति हो सकती है लेकिन इसकी तिथि 'आर' के भविष्य पर होगी 'पंक्ति, अपने अतीत में नहीं ... –

+0

यदि आप इसे कहां से हटाते हैं, तो क्या यह आपको सही आउटपुट देगा? – prukuhkoo

+0

मुझे बस इसका परीक्षण करने की ज़रूरत है, मेरे पास बहुत सारे डेटा हैं इसलिए परीक्षण आसान नहीं हैं। मैंने केवल क्वेरी के निचले हिस्से में धारणाओं को देखने के लिए कहा (जिसे मैं अभी नहीं देखता हूं, शायद मुझे आराम की ज़रूरत है;), और फिर यह देखने के लिए कि क्या मैं इसे और अधिक जांच सकता हूं या अगर वे हैं तो इसे छोड़ दें गलत लोग .. –

1
यहाँ

मैं MSSQL में कोशिश की है। कृपया तर्क जांचें और mysql में आज़माएं। मुझे लगता है कि तर्क यह है कि पहले लेनदेन रद्द करने के बाद नया लेनदेन करना। आपके चित्रण में, आईडी = 7 आईडी = 3 रद्द होने के बाद बनाया गया है।

मैं mssql में जाँच की है

create table Transactions(id int,account varchar(5), tp char(1),date_time datetime,amount int) 

insert into Transactions values (1,'001','R','2012-01-01 10:01:00',1000) 
insert into Transactions values (2,'003','R','2012-01-02 12:53:10',1500) 
insert into Transactions values (3,'003','A','2012-01-03 13:10:01',-1500) 
insert into Transactions values (4,'002','R','2012-01-03 17:56:00',2000) 
insert into Transactions values (5,'001','R','2012-01-04 12:30:01',1000) 
insert into Transactions values (6,'002','A','2012-01-04 13:23:01',-2000) 
insert into Transactions values (7,'003','R','2012-01-04 15:13:10',3000) 


select t.id, t.account, t.date_time, t.amount 
from Transactions t 
where t.tp = 'R' 
and not exists 
(
    select account, date_time 
    from Transactions 
    where tp = 'A' 
    and account = t.account 
    and t.date_time < date_time 
) 
+0

जो तर्क आपने माना है वह सही है, आपके समय के लिए धन्यवाद :) असल में अगर कहीं पंक्ति 7 खाते 003 के लिए एक और 'आर' पंक्ति रही है, तो यह भी दिखाया जाना चाहिए। लेकिन अगर खाते 003 के लिए एक और 'ए' पंक्ति बनाई गई है, तो नई पंक्ति दिखाई नहीं देगी, लेकिन 7 अभी भी दिखाई देनी चाहिए। मुझे यह उदाहरण देने के लिए अपना उदाहरण संपादित करने दें। इस स्क्रिप्ट पर आपके द्वारा उपयोग किए जाने वाले तर्क के बारे में आप क्या जानते हैं, क्या आपको लगता है कि इसे इस तरह व्यवहार करना चाहिए? –

+1

ठीक है, यह बेहतर है कि आप जो भी चाहते हैं उसे पूरा करने के लिए पर्याप्त चित्रण डेटा प्रदान करें। दोबारा प्रयास करें। –

+0

आप सही हैं ... समस्या के बारे में सोचते हुए, और जहां तक ​​मैं कह सकता हूं, तब आखिरकार उपयोग के मामलों में मुझे शामिल करने की ज़रूरत है ... आपकी लिपि के साथ परीक्षण करना, पंक्ति 7 को बाहर रखा गया है, जिसे इसे ' टी, तो आगे के बदलाव की जरूरत है :) चलो इसके बारे में सोचें ... –

0

जब DATE_TIME को हल कर आईडी वास्तव में पंक्तियों के सूचकांक के अनुरूप है - के रूप में यह उदाहरण में करता है (और अगर ऐसा नहीं है, आप इस तरह बना सकते हैं एक आईडी क्षेत्र) - आप यह कर सकते हैं:

SELECT t1.* 
FROM transactions t1 JOIN transactions t2 ON(t2.id = t1.id + 1) 
WHERE t1.type = 'R' 
    AND NOT((t2.type = 'A') AND ((t1.amount + t2.amount) = 0)) 

यानी ID फ़ील्ड का उपयोग प्रत्येक पंक्ति और एक ही परिणाम पंक्ति में अपने उत्तराधिकारी पाने के लिए; फिर अपनी इच्छित संपत्तियों के लिए फ़िल्टर करें।

+0

मैं ' हमने कोशिश की लेकिन यह काम नहीं करता है। यहां तक ​​कि डेटा के साथ मैं एक उदाहरण के रूप में उपयोग करता हूं (और यह वही है, मैंने अपने मॉडल को सरल बनाने की कोशिश की ताकि केवल समस्या का सार यहां दिखाया जा सके), यह स्क्रिप्ट मुझे आईड्स 1,4,5,7 के साथ पंक्तियां दिखाती है लेकिन शुरुआत से, पंक्ति 4 दिखाई नहीं देनी चाहिए। जैसा कि आप देख सकते हैं, पंक्ति 4 पर पंक्ति 4 को 'रद्द' किया गया है, तुरंत 5 पंक्ति पर नहीं, इसलिए 1 से आईडी को बढ़ाना इस विशेष मामले के लिए काम नहीं कर रहा है ... किसी भी तरह, तथ्य यह है कि आईडी के शो के अनुसार इंडेक्सिंग सिर्फ मेरे उदाहरण का एक आर्टिफैक्ट ... –

+1

@ जेवियर ओके मैं अब देखता हूं - इस दृष्टिकोण को खरोंच करें और मेरा नया उत्तर देखें – gcbenison

0

सुधार करने के लिए आपकी क्वेरी इस प्रयास करें:

SELECT t1.*, tFlagged.id AS cancId, tFlagged.tp AS cancFlag FROM t t1 
LEFT JOIN t tFlagged 
ON t1.account = tFlagged.account AND t1.date_time < tFlagged.date_time 
WHERE t1.tp = 'R' 
GROUP BY t1.id 
HAVING tFlagged.tp is null or tFlagged.tp <> 'A' 

यह बहुत तेजी से चलाने के लिए ... उम्मीद है कि एक ही परिणाम उपलब्ध कराने के: पी

+0

समाधान के लिए क्वेरी में यह भी स्थिति नहीं है ... और इसी तरह की स्थितियों के साथ सही इसमें शामिल होने के डेटा को सही तरीके से फ़िल्टर करने की आवश्यकता है ... –

+1

अच्छी बात :) मैंने कहीं भी –

+1

से कॉपी किया है ठीक है ... मुझे अपने वास्तविक डेटा के साथ गहराई से परीक्षण करने दें। क्वेरी मेरे पास की तुलना में वास्तव में तेज़ है, लेकिन मुझे परिणाम पंक्तियों की अलग-अलग संख्या देता है, इसलिए मुझे इसे पहले समझा जाना है ... धन्यवाद! –

संबंधित मुद्दे