Как удалить последующие совпадающие строки? - PullRequest
2 голосов
/ 25 мая 2020

У меня есть тип данных jsonb, где каждая строка имеет имя last_updated среди других ключей. Как мне go создать запрос, который оставит только 1 строку на имя в день?

т.е. это:

id | data
1  | {"name": "foo1", "last_updated": "2019-10-06T09:29:30.000Z"}
2  | {"name": "foo1", "last_updated": "2019-10-06T01:29:30.000Z"}
3  | {"name": "foo1", "last_updated": "2019-10-07T01:29:30.000Z"}
4  | {"name": "foo2", "last_updated": "2019-10-06T09:29:30.000Z"}
5  | {"name": "foo2", "last_updated": "2019-10-06T01:29:30.000Z"}
6  | {"name": "foo2", "last_updated": "2019-10-06T02:29:30.000Z"}

становится:

id | data
1  | {"name": "foo1", "last_updated": "2019-10-06T09:29:30.000Z"}
3  | {"name": "foo1", "last_updated": "2019-10-07T01:29:30.000Z"}
4  | {"name": "foo2", "last_updated": "2019-10-06T09:29:30.000Z"}

Этот запрос будет выполняться примерно для 9 миллионов строк примерно с 300 именами.

1 Ответ

2 голосов
/ 25 мая 2020

Попробуйте что-то вроде этого:

Таблица

create table test (
  id serial,
  data jsonb
);

Данные

insert into test (data) values
('{"name": "foo1", "last_updated": "2019-10-06T09:29:30.000Z"}'),
('{"name": "foo1", "last_updated": "2019-10-06T01:29:30.000Z"}'),
('{"name": "foo1", "last_updated": "2019-10-07T01:29:30.000Z"}'),
('{"name": "foo2", "last_updated": "2019-10-06T09:29:30.000Z"}'),
('{"name": "foo2", "last_updated": "2019-10-06T01:29:30.000Z"}'),
('{"name": "foo2", "last_updated": "2019-10-06T02:29:30.000Z"}');

Запрос

with latest as (
  select data->>'name' as name, max(data->>'last_updated') as last_updated
  from test
  group by data->>'name'
)
delete from test t
where not exists (
  select 1 from latest
  where t.data->>'name' = name
    and t.data->>'last_updated' = last_updated
);

select * from test;

Пример

https://dbfiddle.uk/?rdbms=postgres_10&fiddle=2415e6f2c9c7980e69d178a331120dcd

Возможно, вам придется проиндексировать свой столбец jsonb, например create index on test((data->>'name'));; вы можете сделать это и для last_updated.

Я предполагаю, что у пользователя нет идентичного last_updated.

Если это предположение неверно, вы можете попробовать следующее:

with ranking as (
  select 
    row_number() over (partition by data->>'name' order by data->>'last_updated' desc) as sr,
    x.*
  from test x
)
delete from test t
where not exists (
  select 1 from ranking
  where sr = 1
    and id = t.id
);

В этом случае мы сначала даем серийный номер записям пользователей. Время latest_updated каждого пользователя получает sr 1.

Затем мы просим базу данных удалить все записи, которые не соответствуют идентификатору sr 1.

Пример: https://dbfiddle.uk/?rdbms=postgres_10&fiddle=dba1879a755ed0ec90580352f82554ee

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...