使用SQL删除反转对

时间:2012-05-01 17:09:03

标签: sql sql-server oracle

我有一个与此问题密切相关的SQL问题 - SQL - Need to find duplicate records but EXCLUDE reversed transactions

我需要使用(如果可能的话)非过程SQL删除记录集的所有反转“对”。特定的rdbms是Oracle 11g,但我希望SQL尽可能通用,因此可以在SQL Server 2008中使用相同的策略。示例记录集如下所示:


 ROW     |    DATE    |    QTY    |    FUEL_TYPE    |    REVERSAL    |
1        | 01-MAY-12  |    23.3   |    DSL          |    N           |
2        | 01-MAY-12  |   -23.3   |    DSL          |    Y           |
3        | 01-MAY-12  |    23.3   |    DSL          |    N           |
4        | 01-MAY-12  |    23.3   |    DSL          |    N           |
5        | 01-MAY-12  |    23.3   |    DSL          |    N           |
6        | 01-MAY-12  |    18.6   |    DSL          |    N           |
7        | 01-MAY-12  |   -18.6   |    DSL          |    Y           |
8        | 01-MAY-12  |    14.9   |    GAS          |    N           |

查询的预期结果会将此记录集减少为:


 ROW     |    DATE    |    QTY    |    FUEL_TYPE    |    REVERSAL    |
3        | 01-MAY-12  |    23.3   |    DSL          |    N           |
4        | 01-MAY-12  |    23.3   |    DSL          |    N           |
5        | 01-MAY-12  |    23.3   |    DSL          |    N           |
8        | 01-MAY-12  |    14.9   |    GAS          |    N           |

请注意,重复是可能的,但总是需要删除反转“对”。

修改的 行和行号无关紧要,仅用于说明。删除哪些记录并不重要,只是总是存在“对” - 正数和负数。因此,例如,第2行可以与1,3,4或5配对并删除。

此外,填充表和表结构本身的逻辑由供应商软件控制,并且不包括在反转记录中被反转的记录的原始ID。我真的无法控制这个。 /编辑

顺便说一下,如果更改MINUS关键字以使其功能类似于UNION和UNION ALL,我会喜欢它,因为MINUS只删除与第二个记录集匹配的单个行集,但MINUS ALL删除每个< / em>与第二个记录集中的值匹配的行。如果是这样的话,这个问题就会变得微不足道(至少对于我大脑的想法)。

2 个答案:

答案 0 :(得分:0)

您遇到的问题是撤消并未直接分配给他们正在撤销的交易。

假设逆转是完全逆转,您可以采取以下方法。对于给定的一组交易信息,枚举逆转和非逆转。然后,采取所有不匹配的非逆转。

以下是执行此操作的SQL示例:

with t as 
(
  select row, date, qty, fuel_type, reversal,
    ROW_NUMBER() over (partition by row, date, qty, fuel_type, reversal) as rownum
  from table
)
select *
from 
(
   select *
   from t
   where t.reversal = 'N'
 ) n 
 left outer join
 (
   select *
   from t
   where t.reversal = 'Y'
 ) y
    on n.date = y.date 
    and n.qty = y.qty 
    and n.fuel_type = y.fuel_type 
    and n.rownum = y.rownum 
where n.row is null

这应该在SQL和Oracle中都有效,因为它们都支持row_number窗口/分析函数。

请注意,此解决方案不保证撤消是正确的。它还假设在原始交易的同一天发生了逆转。

答案 1 :(得分:0)

事实证明我正以一种非常可怕的方式看待这个问题。我没有找到精确反转对,而只是用GROUP BY做了一个SUM,所以只有我关心的值保持不变。

最终结果是交易最终会有所不同 - 尤其是在我的情况下,真正的交易表实际上是日期时间值而不是日期。

SELECT SUM(QTY) AS newQTY, DATE, FUEL_TYPE
FROM fuel_transactions
GROUP BY DATE, FUEL_TYPE

如果您需要维护事务的id,或者如果您遇到多个事务发生在 exact 同一时间。