查询以过滤掉具有确切抵消金额的交易

Query to filter out transactions with exact offset amount

下面的查询是一个草稿,其中包含我要编写的查询中的相关列,因此请不要将其视为解决方案。将其用作 table 和列名称的指南。我正在尝试删除任何为相同 ORDER_ID 和 ACCOUNT_ID 相互抵消的交易。我不认为我可以使用 SUM 进行聚合,因为这会将分组的所有 TX_AMOUNT 值加在一起。参见 TX_ID 6 和 7。它们都需要显示在结果集中。我怎样才能从下面的 table 中输出 TX_ID,并过滤掉任何没有说 "SHOW THIS"?

的东西
SELECT 
T1.ACCOUNT_ID
T1.ORDER_ID,
T1.TX_ID
FROM TRANSACTION AS T1
WHERE
T1.ACCOUNT_ID IN (
SELECT T2.ACCOUNT_ID
FROM TRANSACTION AS T2
GROUP BY T2.ACCOUNT_ID, T2.ORDER_ID
HAVING SUM(T2.TX_AMOUNT) != 0 AND T2.ORDER_ID IS NOT NULL 
)
AND T1.ORDER_ID IN (
SELECT T3.ORDER_ID
FROM TRANSACTION AS T3
GROUP BY T3.ACCOUNT_ID, T3.ORDER_ID
HAVING SUM(T3.TX_AMOUNT) != 0 AND T3.ORDER_ID IS NOT NULL 
)

TX_ID   ORDER_ID ACCOUNT_ID  TX_AMOUNT
------------------------------------
1       A1       200         -3.00  <--------- DON'T SHOW THIS; OFFSET BY #2
2       A1       200         3.00   <--------- DON'T SHOW THIS; OFFSET BY #1
3       A1       200         3.00   <--------- SHOW THIS
4       A2       999         -10.01 <--------- DON'T SHOW THIS; OFFSET BY #5
5       A2       999         10.01  <--------- DON'T SHOW THIS; OFFSET BY #4
6       A2       999         10.01  <--------- SHOW THIS
7       A2       999         5.02   <--------- SHOW THIS

版本 2:MUCH 更清洁...Working DEMO with comments(您可能需要单击 运行 它!) 查看所需的结果(或者我有缓存问题)

  • CTE(通用 Table 表达式)只是您显示的数据设置
  • CTE2 只是添加一个由 tx_amount、order_Id、account_Id 分区的行号。这里的关键是,当这 3 个值发生变化时,我们为每个 order_ID、Account_ID 和 tax_Amount 重新启动,但当它们保持不变时递增。这稍后允许我们排除对面 tx_amounts 上的相似匹配,而不排除一方比另一方多的匹配(你的 $3.00 示例)
  • Select 只是从基集中提取记录,其中存在具有相同行号 order_id 和帐户的相反值。如果没有,那么我们知道它是一个值 w/o 一个匹配的相反值 tx_Amount,因此我们想要保留一个值。
  • 有问题就问!如果有不清楚的地方,很乐意提供帮助
  • 最后,如果我们更改 CTE2,则 rowNumber() 按 tx_ID asc 而不是 tx_Amount desc 排序(除了我需要按 row_nubmer 排序外,这实际上没有任何用处), 然后我们将按照 FIFO 方法首先摆脱最低数量的匹配)

.

With CTE (TX_ID,   ORDER_ID, ACCOUNT_ID,  TX_AMOUNT) as (

SELECT 1,       'A1',       200,         -3.00  UNION ALL
SELECT 2,       'A1',       200,         3.00   UNION ALL
SELECT 3,       'A1',       200,         3.00   UNION ALL
SELECT 4,       'A2',       999,         -10.01 UNION ALL
SELECT 5,       'A2',       999,         10.01  UNION ALL
SELECT 6,       'A2',       999,         10.01  UNION ALL
SELECT 7,       'A2',       999,         5.02 ),

cte2 as (
SELECT A.*, row_number() over (partition by order_ID, Account_ID, Tx_Amount order by tx_Amount desc) RN
FROM cte A)

SELECT * 
FROM cte2 A
WHERE NOT exists (SELECT * 
                  FROM cte2 B
                  WHERE A.Order_ID = B.Order_ID
                    and A.Account_ID = B.Account_Id
                    and A.tx_Amount*-1 = B.tx_Amount
                    and A.RN = B.RN)

给我们:(注意我们应该通过将 * 更改为所需的字段来消除 RN,但此时我太懒了)

+----+-------+----------+------------+-----------+----+
|    | TX_ID | ORDER_ID | ACCOUNT_ID | TX_AMOUNT | RN |
+----+-------+----------+------------+-----------+----+
|  1 |     2 | A1       |        200 |      3,00 |  2 |
|  2 |     7 | A2       |        999 |      5,02 |  1 |
|  3 |     5 | A2       |        999 |     10,01 |  2 |
+----+-------+----------+------------+-----------+----+

版本 1:(划掉这个丑陋的东西;我是认真的;谁会这样想?)我确实...

  1. 做点什么。 (版本 1)
  2. 笑(一个重要但被忽视的步骤)
  3. 然后做对(参见上面的版本 2)
  4. 现在让它变得更好。 (索引、调整连接拼写、布局注释、在 CTE2 中的 row_number 逻辑上使用正确的顺序)

DEMO

With CTE (TX_ID,   ORDER_ID, ACCOUNT_ID,  TX_AMOUNT) as (

SELECT 1,       'A1',       200,         -3.00  UNION ALL
SELECT 2,       'A1',       200,         3.00   UNION ALL
SELECT 3,       'A1',       200,         3.00   UNION ALL
SELECT 4,       'A2',       999,         -10.01 UNION ALL
SELECT 5,       'A2',       999,         10.01  UNION ALL
SELECT 6,       'A2',       999,         10.01  UNION ALL
SELECT 7,       'A2',       999,         5.02 ),
cte2 as (
SELECT * 
FROM (Select A.Tx_Id aTx_ID
           , A.order_ID as AOrderID
           , A.Account_ID as AAccount_ID
           , A.tx_Amount as ATx_Amount
           , Row_number() over (partition by Order_ID, Account_ID, tx_Amount order by tx_Amount asc) ARN

      from cte a 
      WHERE tx_Amount <=0) A
FULL OUTER JOIN (SELECT b.tx_Id
                      , b.order_Id
                      , b.Account_Id
                      , b.tx_Amount
                      ,  Row_number() over (partition by Order_ID, Account_ID, tx_Amount order by tx_Amount desc) BRN 
                 FROM  CTE B 
                 WHERE  tx_Amount>0) B
  on A.AOrderID = B.Order_ID
 and A.AAccount_ID = B.Account_ID
 and A.ATx_Amount*-1 = B.tx_Amount
 and A.ARN=B.BRN
Where a.Atx_ID is null
  or B.tx_ID is null)

  Select ATX_ID, AORDERID, AAccount_ID, ATX_AMOUNT from cte2 where ATX_ID is not null
  UNION ALL
  Select TX_ID, ORDER_ID, Account_ID, TX_AMOUNT from cte2 where TX_ID is not null