Postgres: запрашивает последние 2 записи для пользователя, время создания которого отличается на <1 секунду? - PullRequest
0 голосов
/ 30 июня 2018

у меня есть стол

create table Account(
  userId: INT NOT NULL,
  status: TEXT NOT NULL,
  created_at: TIMESTAMP NOT NULL
)

A userId может иметь несколько учетных записей и может иметь статус ACTIVE или CANCELLED. Я хочу, чтобы самая последняя учетная запись была ACTIVE, а пользователь - только 1 ACTIVE account. В настоящее время есть userIds, которые имеют учетную запись ACTIVE, но последняя учетная запись для пользователя - CANCELLED, и это те, которые я хочу идентифицировать.

Есть ли запрос для поиска двух самых последних учетных записей (по created_at, где одна является АКТИВНОЙ, а другая ОТМЕНЕНА (или любым другим текстом на самом деле).

Ответы [ 2 ]

0 голосов
/ 30 июня 2018

Я бы использовал lag() и distinct on, чтобы получить самый последний статус:

select distinct on (user_id) a.*
from (select a.*,
             lag(status) over (partition by user_id order by created_at) as prev_status
      from account a
     ) a
order by user_id, created_at desc;

Если вы хотите, чтобы те, которые были отменены, но активны непосредственно перед этим, используйте подзапрос:

select a.*
from (select distinct on (user_id) a.*
      from (select a.*,
                   lag(status) over (partition by user_id order by created_at) as prev_status
            from account a
           ) a
      order by user_id, created_at desc
     ) a
where status = 'CANCELLED' and prev_status = 'ACTIVE'
0 голосов
/ 30 июня 2018

Вы можете получить последние два аккаунта, используя row_number().

SELECT *
       FROM (SELECT *,
                    row_number() OVER (PARTITION BY a1.userid
                                       ORDER BY a1.created_at DESC) rn
                    FROM account a1) a2
       WHERE a2.rn <= 2;

Но при этом также будут возвращаться отдельные учетные записи (на пользователя). Если вы не хотите, чтобы присоединиться к подзапросу, получая количество учетных записей для каждого пользователя и проверьте, является ли это число> = 2.

SELECT *
       FROM (SELECT *,
                    row_number() OVER (PARTITION BY a1.userid
                                       ORDER BY a1.created_at DESC) rn
                    FROM account a1) a2
            INNER JOIN (SELECT a3.userid,
                               count(*) c
                               FROM account a3
                               GROUP BY a3.userid) a4
                       ON a4.userid = a2.userid                
       WHERE a2.rn <= 2
             AND a4.c >= 2;

Но вы также можете напрямую идентифицировать эти учетные записи. Используйте подзапрос с GROUP BY userid, чтобы получить max(created_at) для каждого пользователя. INNER JOIN, которые приводят к счетам и фильтруют WHERE status = 'CANCELLED'. Используйте EXISTS, чтобы проверить, имел ли этот пользователь когда-либо учетную запись 'ACTIVE'. Присоединитесь снова, чтобы получить все учетные записи для таких пользователей.

SELECT *
       FROM account a1
            INNER JOIN (SELECT a2.userid
                               FROM account a2
                                    INNER JOIN (SELECT a3.user_id,
                                                       max(a3.created_at) created_at
                                                       FROM account a3
                                                       GROUP BY a3.userid) a4
                                               ON a4.userid = a2.user_id
                                                  AND a4.created_at = a3.created_at
                               WHERE a1.status = 'CANCELLED'
                                     AND EXISTS (SELECT *
                                                        FROM account a5
                                                        WHERE a5.userid = a1.userid
                                                              AND a5.status = 'ACTIVE')) a6
                       ON a6.userid = a1.userid;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...