SQL: เลือกธุรกรรมที่แถวไม่อยู่ในเกณฑ์ภายในตารางเดียวกัน

ฉันมีตารางที่มีธุรกรรม:

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

และฉันต้องการเลือกประเภทบางประเภททั้งหมด ('R') แต่ไม่ใช่ประเภทที่ทันที (ตามลำดับช่อง date_time) มีธุรกรรมประเภทอื่น ('A') สำหรับบัญชีเดียวกันที่ยื่น...

ดังนั้น แบบสอบถามควรแสดงแถวต่อไปนี้ ตามตัวอย่างก่อนหน้านี้:

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 ก็ 'ยกเลิก' โดยแถวที่ 6' เช่นกัน แถวที่ 7 จะปรากฏขึ้น (แม้ว่าบัญชี 003 จะเป็นของแถวที่ยกเลิก #2 ครั้งนี้ในแถวที่ 7 จะไม่ถูกยกเลิกโดยแถว 'A' ใด ๆ ) และแถวที่ 8 จะไม่ปรากฏขึ้น (มันเกินไปสำหรับบัญชี 003 เนื่องจากตอนนี้อันนี้ถูกยกเลิกด้วย 9 ซึ่งไม่ได้ยกเลิก 7 เช่นกัน เพียงก่อนหน้านี้ หนึ่ง: 8...

ฉันได้ลองเข้าร่วมแล้ว แบบสอบถามย่อยใน Where clauses แต่ฉันไม่แน่ใจจริงๆ ว่าจะต้องค้นหาอย่างไร...

สิ่งที่ฉันได้ลอง:

กำลังพยายามเข้าร่วม:

   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

สิ่งนี้ทำให้เกิดข้อผิดพลาด เนื่องจากฉันไม่สามารถแนะนำค่าภายนอกให้กับ JOIN ใน 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

นี่เป็นสิ่งที่ผิด ฉันสามารถแนะนำค่าภายนอกให้กับ WHERE ใน 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 ที่ดี การเข้าร่วมจะเรียงลำดับตาม date_time การจัดกลุ่มตามรหัส ฉันจัดการเพื่อให้ได้เฉพาะผลลัพธ์แรกของการเข้าร่วม ซึ่งเป็นธุรกรรมถัดไปสำหรับบัญชีเดียวกัน

จากนั้นในการเลือกภายนอก ฉันจะกรองรายการที่มี 'A' ออก เนื่องจากนั่นหมายความว่าธุรกรรมถัดไปเป็นการยกเลิกอย่างมีประสิทธิภาพ กล่าวคือ หากไม่มีรายการถัดไปสำหรับบัญชีเดียวกัน หรือหากรายการถัดไปเป็น 'R' ก็จะไม่ถูกยกเลิกและจะต้องแสดงในผลลัพธ์...

ฉันได้รับสิ่งนี้:

+----+---------+------+---------------------+--------+--------+----------+
| 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 แถวในขณะนี้ ฉันได้ผลลัพธ์เชิงบวกกับข้อความค้นหานี้ใน 1 นาที 44 วินาที ฉันคิดว่านั่นคือเรื่องของการรวม... (สำหรับผู้ที่รู้โปรโตคอลในนี้ ฉันควรทำอย่างไร ตั้งคำถามใหม่ที่นี่ และโพสต์สิ่งนี้เพื่อเป็นวิธีแก้ปัญหาสำหรับคำถามนี้ หรือเพียงแค่รอคำตอบเพิ่มเติมที่นี่?)


person Javier Novoa C.    schedule 28.02.2012    source แหล่งที่มา
comment
ดู: meta.stackexchange.com/questions/2950/   -  person OMG Ponies    schedule 28.02.2012
comment
ขอบคุณสำหรับคำติชม... :P   -  person Javier Novoa C.    schedule 28.02.2012
comment
คอลัมน์ id เรียงตามเวลาเสมอหรือไม่ หากเป็นเช่นนั้นคุณสามารถเข้าร่วมได้ที่ id=id+1   -  person andrew cooke    schedule 28.02.2012
comment
ไม่ ขออภัย @andrewcooke นั่นเป็นเพียงเรื่องของการทำให้ตัวอย่างที่ฉันแสดงที่นี่ง่ายขึ้น... ฉันแสดงความคิดเห็นแบบเดียวกันกับคำตอบของ gcbenison ด้านล่างที่นี่...   -  person Javier Novoa C.    schedule 28.02.2012


คำตอบ (5)


นี่คือวิธีแก้ปัญหาตามแบบสอบถามย่อยที่ซ้อนกัน ขั้นแรก ฉันเพิ่มสองสามแถวเพื่อตรวจจับกรณีเพิ่มเติมอีกสองสามกรณี ตัวอย่างเช่น ธุรกรรม 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)

ใช้สิ่งนั้นเป็นแบบสอบถามย่อยเพื่อรับแต่ละรายการและรายการก่อนหน้าในแถวเดียวกัน ใช้การกรองเพื่อดึงธุรกรรมที่เราสนใจออกมา - กล่าวคือธุรกรรม 'A' ซึ่งมีธุรกรรมก่อนหน้าเป็นธุรกรรม 'R' ที่พวกเขายกเลิกอย่างแน่นอน -

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 |
+----+---------+------+---------------------+--------+
person gcbenison    schedule 28.02.2012
comment
ใช่ เกือบจะถึงแล้ว! แต่เหตุใด 11 หากถูกยกเลิกด้วย 12 จึงปรากฏในผลลัพธ์สุดท้าย - person Javier Novoa C.; 28.02.2012
comment
ตกลง ฉันเข้าใจคำถามผิด ฉันคิดว่า A จะเป็นการยกเลิก โดยฟิลด์ amount จะต้องเป็นค่าลบในแถว R การกำจัดส่วนคำสั่ง AND t3.amount + transactions.amount = 0 ควรกำจัดข้อจำกัดนี้ (และมอบสิ่งที่คุณกำลังมองหา) - person gcbenison; 28.02.2012
comment
รอ! คุณพูดถูกมากกว่าฉัน! ฉันไม่ได้สังเกตเห็นรายละเอียดนั้น แน่นอนว่านั่นคือสิ่งที่ฉันกำลังมองหา :) ให้ฉันทำการทดสอบเพิ่มเติม! ฉันคิดว่านี่เป็นสิ่งที่ถูกต้องในที่สุด :) - person Javier Novoa C.; 29.02.2012

ที่นี่ฉันได้ลองใน MSSQL แล้ว โปรดตรวจสอบตรรกะและลองใน mysql ฉันถือว่าตรรกะคือทำธุรกรรมใหม่หลังจากยกเลิกธุรกรรมครั้งแรก ในภาพประกอบของคุณ id = 7 ถูกสร้างขึ้นหลังจาก id=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
)
person Thit Lwin Oo    schedule 28.02.2012
comment
ตรรกะที่คุณคิดว่าถูกต้อง ขอบคุณสำหรับเวลาของคุณ :) ที่จริงแล้วถ้ามีแถว 'R' อีกแถวสำหรับบัญชี 003 หลังจากแถวที่ 7 ก็ต้องแสดงแถวนั้นด้วย แต่หากหลังจากนั้นมีการสร้างแถว 'A' สำหรับบัญชี 003 อีกแถวหนึ่ง แถวใหม่จะไม่ปรากฏขึ้น แต่ 7 ยังคงควรปรากฏขึ้น ให้ฉันแก้ไขตัวอย่างของฉันเพื่อแสดงให้เห็นว่า จากสิ่งที่คุณรู้เกี่ยวกับตรรกะที่คุณใช้กับสคริปต์นี้ คุณคิดว่ามันควรจะเป็นแบบนั้นหรือไม่? - person Javier Novoa C.; 28.02.2012
comment
โอเค คุณควรให้ข้อมูลภาพประกอบให้เพียงพอกับสิ่งที่คุณต้องการจะดีกว่า ให้ลองอีกครั้ง - person Thit Lwin Oo; 28.02.2012
comment
คุณพูดถูก... เมื่อคิดถึงปัญหา และเท่าที่ฉันสามารถบอกได้ นี่เป็นกรณีการใช้งานสุดท้ายที่ฉันจำเป็นต้องรวมไว้... การทดสอบกับสคริปต์ของคุณตามที่เป็นอยู่ แถวที่ 7 จะถูกแยกออก ซึ่งไม่ควร ดังนั้นจึงจำเป็นต้องมีการเปลี่ยนแปลงเพิ่มเติม :) ลองคิดดูสิ... - person Javier Novoa C.; 28.02.2012
comment
ฉันแก้ไขโพสต์ต้นฉบับด้วยวิธีแก้ปัญหาที่ฉันพบตัวเอง แต่ต้องดำเนินการเพิ่มเติมในกรณีที่คุณต้องการดู... - person Javier Novoa C.; 28.02.2012

(แก้ไข 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
 )  ;
person Community    schedule 28.02.2012
comment
อืมม์ บางที... แค่สงสัย... ทำไม ‹= ใน date_time โดยที่ส่วนคำสั่ง? แถว 'A' ควรจะมีอยู่หลังจากแถว 'R' บางแถว ดังนั้นสำหรับ 'R' ใดๆ ที่ควรยกเลิก อาจมีแถว 'A' แต่วันที่จะอยู่ในอนาคตของ 'R ' แถวไม่ใช่อดีต... - person Javier Novoa C.; 28.02.2012
comment
หากคุณลบมันออกจากคำสั่ง Where มันจะให้ผลลัพธ์ที่ถูกต้องหรือไม่? - person prukuhkoo; 28.02.2012
comment
ฉันแค่ต้องทดสอบ ฉันมีข้อมูลมากมาย ดังนั้นการทดสอบจึงไม่ง่าย ฉันขอเพียงแค่ดูสมมติฐานที่ด้านล่างของข้อความค้นหา (ซึ่งฉันยังไม่เห็นตอนนี้ บางทีฉันอาจต้องการพักผ่อน ;) จากนั้นเพื่อดูว่าฉันสามารถทดสอบเพิ่มเติมได้หรือไม่ หรือเพียงแค่ทิ้งมันไปหากเป็น ผิดคน.. - person Javier Novoa C.; 28.02.2012
comment
ตกลง ฉันทดสอบกับข้อมูลที่ฉันใช้ในตัวอย่างของฉันเท่านั้น แต่มันไม่แสดงแถว 7 โปรดดูความคิดเห็นในคำตอบก่อนหน้า ฉันเพิ่มแถว 8 และ 9 เพื่อแสดงตัวอย่างกรณีการใช้งานอื่น :) ขอขอบคุณที่สละเวลาเช่นกัน ! (BTW ‹= ผิด มันควรจะเป็น › ด้วยการทดสอบตอนนี้ฉันสามารถพูดได้ว่า :) - person Javier Novoa C.; 28.02.2012
comment
คุณได้ลองลบ t.date_time › trans.date_time ในส่วนคำสั่งย่อยของแบบสอบถามย่อยแล้วหรือยัง ฉันคิดว่านี่คือสิ่งที่ทำให้คุณเกิดปัญหา .. - person prukuhkoo; 28.02.2012
comment
ลองลบมันออกจากแบบสอบถามก่อนหน้าของฉัน .. ฉันคิดว่ามันควรจะใช้งานได้จริง .. - person prukuhkoo; 28.02.2012
comment
ใช่ แต่อันที่จริงแล้ว มันให้ผลลัพธ์เดียวกันกับประโยคนั้นทุกประการ! อย่างน้อยก็ด้วยข้อมูลตัวอย่าง... - person Javier Novoa C.; 28.02.2012
comment
ฉันแก้ไขแบบสอบถามด้านบน ฉันลองใช้กับข้อมูลตัวอย่างที่ได้รับในคำตอบก่อนหน้าและใช้งานได้ .. มันแสดงเฉพาะแถวที่มี 001 เป็นบัญชีเท่านั้น - person prukuhkoo; 28.02.2012
comment
ขอบคุณ แต่ไม่ใช่ความจริงที่ว่าต้องแสดงเฉพาะแถวที่มี 001 แต่เป็นแถวที่ไม่ถูกยกเลิก... ฉันได้ลองแก้ไขนี้กับข้อมูลตัวอย่างของฉันแล้ว แต่แถวที่มี id 7 (acct 003) ก็ไม่แสดง ปรากฏขึ้น ซึ่งควร... :-/ บางทีฉันอธิบายตรรกะที่ฉันต้องการได้ไม่ดีนัก - person Javier Novoa C.; 28.02.2012
comment
เกือบ! ฉันสังเกตเห็นว่าคุณใช้ข้อเท็จจริงที่ว่าจำนวนเงินเป็นลบสำหรับการยกเลิกแต่ละครั้ง แต่จะเกิดอะไรขึ้นเมื่อจำนวนเงินในแถว 'R' สองแถวสำหรับบัญชีเดียวกันเท่ากัน สมมติว่าจำนวนแถวที่ 8 เท่ากับ 3,000 เช่นเดียวกับแถวที่ 7 (และแน่นอนว่าจำนวนการยกเลิกของแถวที่ 9 คือ -3000) จากนั้น เนื่องจากเงื่อนไขในสคริปต์ของคุณ แถวที่ 7 จะถูกละทิ้งไปด้วย แต่ต้องไม่... อย่างที่ฉันบอกไปแล้ว เกือบแล้ว! ขอบคุณอีกครั้ง! - person Javier Novoa C.; 28.02.2012
comment
ฉันแก้ไขโพสต์ต้นฉบับด้วยวิธีแก้ปัญหาที่ฉันพบตัวเอง แต่ต้องดำเนินการเพิ่มเติมในกรณีที่คุณต้องการดู... - person Javier Novoa C.; 28.02.2012

หาก ID สอดคล้องกับดัชนีของแถวจริงๆ เมื่อจัดเรียงตาม date_time เช่นเดียวกับในตัวอย่าง (และหากไม่สอดคล้องกับดัชนีของแถว คุณสามารถสร้างฟิลด์ ID ดังกล่าวได้) - คุณสามารถทำได้:

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 เพื่อรับแต่ละแถวและผู้สืบทอดในแถวผลลัพธ์เดียวกัน จากนั้นกรองคุณสมบัติที่คุณต้องการ

person gcbenison    schedule 28.02.2012
comment
ฉันได้ลองสิ่งนี้แล้ว แต่มันใช้งานไม่ได้ แม้ว่าข้อมูลที่ฉันใช้เป็นตัวอย่าง (และเพียงเท่านั้น ฉันพยายามทำให้โมเดลของฉันง่ายขึ้นมากเพื่อให้แสดงเฉพาะแก่นแท้ของปัญหาที่นี่) สคริปต์นี้แสดงแถวที่มีรหัส 1,4,5,7 ให้ฉันเห็น แต่ตั้งแต่ต้นแถวที่ 4 ไม่น่าจะแสดงขึ้นมา อย่างที่คุณเห็น แถวที่ 4 ถูก 'ยกเลิก' ที่แถวที่ 6 ไม่ใช่ทันทีที่แถวที่ 5 ดังนั้นการเพิ่ม id ด้วย 1 จะไม่ทำงานสำหรับกรณีนี้โดยเฉพาะ... อย่างไรก็ตาม ความจริงที่ว่า id แสดงราวกับว่าการจัดทำดัชนีตามวันที่คือ เป็นเพียงสิ่งประดิษฐ์ตัวอย่างของฉัน ... - person Javier Novoa C.; 28.02.2012
comment
@javier ตกลงฉันเข้าใจแล้ว - เกาแนวทางนี้และดูคำตอบใหม่ของฉัน - person gcbenison; 28.02.2012

เพื่อปรับปรุงการค้นหาของคุณให้ลองสิ่งนี้:

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'

มันจะทำงานเร็วขึ้นมาก ... หวังว่าจะได้ผลลัพธ์เหมือนเดิม :P

person Mosty Mostacho    schedule 28.02.2012
comment
แบบสอบถามสำหรับการแก้ปัญหาไม่มีเงื่อนไขนั้นด้วยซ้ำ... และแบบสอบถามที่ถูกต้องที่มีเงื่อนไขคล้ายกันจำเป็นต้องกรองข้อมูลในการรวมอย่างถูกต้อง... - person Javier Novoa C.; 28.02.2012
comment
โอเค... ขอผมทดสอบแบบเจาะลึกด้วยข้อมูลจริงของผมก่อน ข้อความค้นหานั้นรวดเร็วมากเมื่อเทียบกับสิ่งที่ฉันมี แต่ให้จำนวนแถวผลลัพธ์ที่แตกต่างกัน ดังนั้นฉันจึงต้องวิเคราะห์ก่อน... ขอบคุณ! - person Javier Novoa C.; 28.02.2012