SQL查询混合聚合结果和单个值

时间:2012-10-09 15:27:40

标签: sql select group-by subquery having

我有一张包含交易的表格。每个交易都有交易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等于总和(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;

V形臂章是我正在努力做的事情,而且我被卡住了。我可以这样做,还是我可以在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)&lt;&gt; 0和最早的PV&lt;&gt; 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交易也在那里,我不想要它们。但我无法弄清楚如何修改查询,以便它们不被包括在内。有什么想法吗?

2 个答案:

答案 0 :(得分:2)

SQL Fiddle

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 Fiddle

答案 1 :(得分: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子句,以确保它只影响你想要的行。

这不会将负面交易标记为错误(您可能需要也可能不需要),但在第二个示例中除外。在你的第二个例子中,有第三个记录,如果它们被孤立地取消,它将取消第二个记录。你可能会发现你需要扩展逻辑以完全得到你需要的东西,但它应该让你开始。