Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用SQL消除相等但相反数据的最优雅方法_Sql_Postgresql_Duplicates - Fatal编程技术网

使用SQL消除相等但相反数据的最优雅方法

使用SQL消除相等但相反数据的最优雅方法,sql,postgresql,duplicates,Sql,Postgresql,Duplicates,我有一组相对简单的数据,如下所示: invoice_id created_at amount_in_cents user_id 22348 2019-11-07 550 31773927 22349 2019-11-08 -550 31773927 22498 2019-11-10 -3400

我有一组相对简单的数据,如下所示:

invoice_id    created_at     amount_in_cents         user_id
  22348       2019-11-07         550                31773927
  22349       2019-11-08        -550                31773927
  22498       2019-11-10        -3400               2389483
  22499       2019-11-10         3400               2389483
  22500       2019-11-11         18000              93842938
如您所见,示例数据的前两行归属于同一个用户id,但数量与0成反比。与第3行和第4行相同。我想删除同一用户存在反向发票的所有发票,在相互之间的30天内,只留下第五行

我可以用python实现这一点,但它会大大扩展这个过程。有没有一种简单的方法可以使用SQL来实现这一点?

您可以将“不存在”与相关子查询一起使用:

select t.*
from mytable t
where not exists (
    select 1
    from mytable t1
    where 
        t1.user_id = t.user_id
        and greatest(t1.created_at, t.created_at) 
            <= least(t1.created_at, t.created_at) + interval '30 days'
        and t1.amount_in_cents = - t.amount_in_cents
)

not exists(不存在)条件可确保同一用户在30天内不存在其他记录,且记录量相反。

我认为没有简单的解决方案。如果要删除所有匹配对,则可以枚举并删除:

select min(invoice_id), min(created_at), user_id, max(amount_in_cents) as amount_in_cents
from (select t.*,
             row_number() over (partition by user_id, amount_in_cents order by created_at) as seqnum
      from t
     ) t
group by abs(amount_in_cents), user_id, seqnum
having count(*) = 1;  -- only one "matching" amount
然而,30天的限制是具有挑战性的,我认为您可能需要一个递归CTE

考虑以下数据:

1    jan 1     500
1    jan 15    500
1    feb 1     -500
1    feb 10    -500

您想要什么结果?

您使用的是MySQL还是Postgres?请仅标记相关数据库。抱歉,postgres,修复了如果有多个匹配项怎么办?例如,你可以有两个550的量。这是一个很好的问题。如果有两个,我想删除一个匹配集,留下额外的550。如果在550处有两次充电,在-550处有一次充电,这将不起作用。这个问题比听起来要难得多。这对我来说很有效,如果有两个在550,一个在-550,它会删除550和-550,留下550……对吗?@AshleyO:事实上不是,Gordon Linoff正确地指出,这对这个用例不起作用-如果在30天内,两个记录550记录都将被唯一的-550记录消除。你可能也想检查另一个答案,但它不处理30天的限制。或者,用代表这些边缘情况的样本数据,对您想要实现的内容进行更详细的描述。它仍然适用于我的特定用例,但这主要是因为我没有完美地概述我的用例。在你看来,我应该去掉复选标记吗?@AshleyO:你问了这个问题,因此你完全可以接受或不接受任何答案。但实际上,我的解决方案适用于您的示例数据。你也可以考虑问一个新的问题,样本数据覆盖了边缘情况,所以从一开始你就更清楚了。