查询以过滤掉具有确切抵消金额的交易
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)
- 笑(一个重要但被忽视的步骤)
- 然后做对(参见上面的版本 2)
- 现在让它变得更好。 (索引、调整连接拼写、布局注释、在 CTE2 中的 row_number 逻辑上使用正确的顺序)
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
下面的查询是一个草稿,其中包含我要编写的查询中的相关列,因此请不要将其视为解决方案。将其用作 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)
- 笑(一个重要但被忽视的步骤)
- 然后做对(参见上面的版本 2)
- 现在让它变得更好。 (索引、调整连接拼写、布局注释、在 CTE2 中的 row_number 逻辑上使用正确的顺序)
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