运行事务数据,如果行在另一行附近时删除行

时间:2015-07-27 02:58:53

标签: postgresql greenplum

我在PostGres数据库中有一系列交易(特定的Greenplum),其中包含date_ids:

+----+-----------+----------------+
| id | date_id   | desired result |
+----+-----------+----------------+
|  1 |        58 | keep           |
|  2 |        99 | discard        |
|  3 |       110 | keep           |
|  4 |       188 | keep           |
|  5 |       190 | discard        |
|  6 |       191 | discard        |
|  7 |       201 | discard        |
|  8 |       244 | keep           |
|  9 |       255 | discard        |
+----+-----------+----------------+

Date_id只是日期的替身(因此date_ids 58和59将是连续的日期;上表中的前两个交易相隔39天)。

我正在尝试实施以下规则:对于第一笔交易,保留它 - 但在50天内放弃任何其他交易。 50天后,保留下一笔交易。然后在50天内放弃任何其他交易。等等。结果,没有两个剩余(未丢弃)的交易在50天之内。

在这种情况下,事务id = 1是“保持”,因为它是第一个。交易ID = 2被丢弃(在第一次交易的50天内)。但是,尽管在第二次交易后仅11天,交易id = 3仍然是“保持”。

有没有人对如何实现这个有任何想法?我认为这可以通过简单地将表连接到自身来实现,但我无法找到满足这些规则的方法。

这没有用:

with intervals_between_transactions as 
(select t1.id transaction_id
, t1.date_id date_of_transaction
, max(t2.date_id) date_of_previous_transaction
from transactions t1
join transactions t2 on t2.date_id < t1.date_id
group by 1)
select *
from intervals_between_transactions 
where date_of_transaction - date_of_previous_transaction > 50

因为这会丢弃交易3,尽管它是“保持”。

这也不起作用:

select date_id::numeric / 50.0 fifty_day_window
, min(id)
from transactions group by 1

因为它会“保持”交易id = 8和id = 9,尽管它们只相隔11天。

谢谢!

2 个答案:

答案 0 :(得分:0)

就像Craig建议的那样,这可以通过使用CTE的迭代来解决,但是你需要几个级别的嵌套才能使它工作:

DELETE FROM mytable
WHERE id NOT IN (
  WITH RECURSIVE min_date AS (
    SELECT min(date_id) FROM mytable
  ), keep AS (
    SELECT id, date_id
    FROM mytable, min_date
    WHERE date_id = min_date.min
    UNION
    SELECT * FROM (
      SELECT m.id, m.date_id
      FROM mytable m, keep
      WHERE m.date_id - keep.date_id > 50
      ORDER BY 2 LIMIT 1
    ) sub
  )
  SELECT id FROM keep);

CTE的递归部分有许多限制,例如没有聚合函数,没有ORDER BY和没有LIMIT 1,其中任何一个都可以很好地将下一条记录添加到结果中组。但是,在子查询中包装递归术语将允许使用ORDER BY 2 LIMIT 1,因此可以使用额外的嵌套。

与任何DELETE语句一样,首先通过仅运行CTE来验证是否删除了正确的记录。请在此处查看fiddle

答案 1 :(得分:0)

如果您有50天,我认为您的任务不是全局性的,即您有另一个字段,完整的问题就像“每个客户每50天仅保留一笔交易”。这种方式在我看来最简单的方法是将事务及其日期分组为两个数组,并编写一个函数来处理实现逻辑的事务列表和日期

正如已经说过的那样,它是一个迭代逻辑。知道交易X在50天之前有5笔交易,不能让您决定是否应保留此交易。每个保留的决定取决于先前的决定。因此,您必须遵循我的建议并将事务分组到数组中并在函数中处理它们,或者编写一个pl / pgsql函数,该函数将逐行遍历表对数据进行迭代。我是afraied这些是Greenplum的唯一选择