5

我有一张交易表。每个事务都有一个事务 ID、会计期间 (AP)、过帐值 (PV) 以及其他字段。某些 ID 重复,通常是因为交易错误完成。举个例子,表格的一部分可能如下所示:

ID    PV    AP  
123   100   2  
123   -100  5  

在这种情况下,事务在 AP2 中添加,然后在 AP5 中删除。

另一个例子是:

ID    PV    AP  
456   100   2  
456   -100  5  
456   100   8

在第一个示例中,问题是如果我正在分析在 AP2 中花费的内容,其中有一笔交易实际上不应该被考虑在内,因为它在 AP5 中再次被取出。在第二个示例中,不应考虑后两个交易,因为它们相互抵消。

我想尽可能多地标记不应被视为错误的交易。为了识别这些事务,我想找到具有重复 ID 且 PV 总和为零的事务(如上面的 ID 123)或最早的 PV 等于 sum(PV) 的事务,如第二个示例所示。这第二个条件是让我悲伤的原因。

到目前为止我有

SELECT *
FROM table
WHERE table.ID IN (SELECT table.ID
                    FROM table
                    GROUP BY table.ID
                    HAVING COUNT(*) > 1
                    AND (SUM(table.PV) = 0
                    OR SUM(table.PV) = <PV of first transaction in each group>))
ORDER BY table.ID;

人字形中的那一点是我想要做的,我被困住了。我可以这样做还是可以在 SQL 中使用其他方法来做到这一点?

编辑 1:顺便说一句,我忘了说我正在使用 SQL Compact 3.5,以防万一。

编辑2:我认为上面的代码片段有点误导。我仍然想用重复 ID 标记 sum(PV) = 0 的事务,如第一个示例所示。但是最早交易的 PV = sum(PV),如第二个例子,我真正想要的是保留最早的交易,并用相同的 ID 标记所有其他交易。抱歉,如果这引起了混乱。

编辑 3:我一直在使用 Clodoaldo 的解决方案并取得了一些进展,但仍然无法得到我想要的。我试图让我知道肯定是错误的交易。假设表中还有以下事务:

ID     PV    AP  
789    100   2  
789    200   5  
789   -100   8

在这个例子中 sum(PV) <> 0 和最早的 PV <> sum(PV) 所以我不想标记任何这些。

如果我修改 Clodoaldo 的查询如下:

    select t.*
    from 
    t
    left join (
        select id, min(ap) as ap, sum(pv) as sum_pv
        from t
        group by id
        having sum(pv) <> 0
    ) s on t.id = s.id and t.ap = s.ap and t.pv = s.sum_pv
     where s.id is null

这给出了结果

 ID      PV     AP
123      100    2
123     -100    5
456     -100    5
456      100    8
789      100    3
789      200    5
789     -100    8

虽然前 4 笔交易没问题(它们会被标记出来),但 789 笔交易也在那里,我不想要它们。但我不知道如何修改查询以便不包括在内。有任何想法吗?

4

2 回答 2

2

SQL小提琴

select t.* 
from 
    t
    inner join (
        select id, min(ap) as ap
        from t
        group by id
        having sum(pv) <> 0
    ) s on t.id = s.id and t.ap = s.ap

以上获取有效交易。如果你想要无效的使用这个:

select t.*
from 
    t
    left join (
        select id, min(ap) as ap
        from t
        group by id
        having sum(pv) <> 0
    ) s on t.id = s.id and t.ap = s.ap
where s.id is null

SQL小提琴

于 2012-10-09T15:49:00.127 回答
0

尝试这样的事情:

UPDATE
    Transactions
SET
    IsError = true
WHERE
    EXISTS
    (SELECT
        NULL
    FROM 
        Transactions SubsequentTransactions
    WHERE
        Transactions.ID = SubsequentTransactions.ID
    AND Transactions.AP < SubsequentTransactions.AP
    AND Transactions.PV = -1 * SubsequentTransactions.PV)

我认为这会奏效。我根本没有测试过,所以我建议您首先在 select 语句中使用 WHERE 子句,以确保它只会影响您想要的行。

这不会将负面交易标记为错误(您可能需要也可能不需要),除了在您的第二个示例中。在您的第二个示例中,如果将第二个记录单独获取,则第三个记录会取消第二个记录。您可能会发现您需要扩展逻辑以完全获得所需的内容,但它应该可以帮助您入门。

于 2012-10-09T15:43:34.417 回答