我在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天。
谢谢!
答案 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的唯一选择