сравнить две даты между разными записями - PullRequest
0 голосов
/ 17 января 2019

У меня проблема с запросом SQL, который я пытаюсь построить на базе данных Oracle. Мне нужно выяснить случаи, когда некоторые записи были созданы раньше других записей. это звучит просто, но у меня проблемы с этим, я не могу сказать, почему.

есть таблица, содержащая подробные пользовательские события, которая называется "USER_EVENTS". мы обнаружили определенную ошибку, которая связана с удалением пользователей до их активации. Я хочу получить всех пользователей, у которых была эта ошибка, поэтому, если я посмотрю на таблицу, я увижу что-то вроде этого:

TABLE USER_EVENTS

ID  EVENT_TYPE      EVENT_DATE  USER_ID
1   USER_DELETED    10/1/2019   5301
2   USER_ACTIVATED  9/1/2019    5301
3   USER_DELETED    5/1/2019    5302
4   USER_ACTIVATED  11/1/2019   5302
5   USER_DELETED    1/1/2019    5288
6   USER_DELETED    2/1/2019    5287
7   USER_CREATED    1/12/2018   5211
8   USER_NOTE       1/12/2018   5211

пробовал различные запросы, которые, кажется, не соответствуют этим двум, я знаю, что это глупо, я прошу прощения.

Глядя на таблицу выше, я хочу получить USERID тех посылок, которые имели событие DELETED до события ACTIVATED. из изображения я должен получить взамен «5302», который был удален 01.05.2009, но активирован 1.11.2017.

Заранее спасибо!

P.S. - пожалуйста, не связывайтесь с проблемой проектирования с соглашениями об именах или с тем, как этого не делать, и т. д. ', выше приведен лишь общий пример.

Ответы [ 8 ]

0 голосов
/ 17 января 2019

спасибо всем за помощь! вы, ребята, потрясающие !! я пошел со 2-м запросом из первого ответа на этот пост:

SELECT USER_ID
FROM   USER_EVENTS
GROUP BY USER_ID
HAVING MIN( CASE EVENT_TYPE WHEN 'USER_DELETED' THEN EVENT_DATE END )
         < MIN( CASE EVENT_TYPE WHEN 'USER_ACTIVATED' THEN EVENT_DATE END )

работает как шарм, спасибо @ MTO

0 голосов
/ 17 января 2019

Я не могу решить, если это взломать, но просто для удовольствия:

select user_id
from   user_events
group by user_id
having listagg(event_type, ',') within group (order by event_date) like '%DELETED,%ACTIVATED%';
0 голосов
/ 17 января 2019

Почему бы не использовать могучий LEAD / LAG?

SELECT * FROM (
SELECT id,
       event_type,
       event_date,
       user_id,
       CASE
         WHEN event_type = 'USER_DELETED' THEN LEAD(EVENT_DATE) OVER (PARTITION BY useR_id ORDER BY event_type DESC) 
         ELSE NULL
       END  AS CREATED
FROM   user_events
WHERE event_type IN ('USER_ACTIVATED','USER_DELETED')
)
WHERE created > event_date
0 голосов
/ 17 января 2019

Вы можете использовать аналитическую функцию COUNT, которая не потребует от вас самостоятельного объединения на вашем столе.

Установка Oracle :

CREATE TABLE USER_EVENTS ( ID, EVENT_TYPE, EVENT_DATE, USER_ID ) AS
SELECT 1, 'USER_DELETED',    DATE '2019-01-10', 5301 FROM DUAL UNION ALL
SELECT 2, 'USER_ACTIVATED',  DATE '2019-01-09', 5301 FROM DUAL UNION ALL
SELECT 3, 'USER_DELETED',    DATE '2019-01-05', 5302 FROM DUAL UNION ALL
SELECT 4, 'USER_ACTIVATED',  DATE '2019-01-11', 5302 FROM DUAL UNION ALL
SELECT 5, 'USER_DELETED',    DATE '2019-01-01', 5288 FROM DUAL UNION ALL
SELECT 6, 'USER_DELETED',    DATE '2019-01-02', 5287 FROM DUAL UNION ALL
SELECT 7, 'USER_CREATED',    DATE '2018-12-01', 5211 FROM DUAL UNION ALL
SELECT 8, 'USER_NOTE',       DATE '2018-12-01', 5211 FROM DUAL;

Запрос 1 :

SELECT *
FROM   (
  SELECT u.*,
         COUNT( CASE event_type WHEN 'USER_ACTIVATED' THEN 1 END )
           OVER (
             PARTITION BY user_id
             ORDER BY event_date
             ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING
           ) AS num_activated
  FROM   USER_EVENTS u
)
WHERE  num_activated > 0
AND    event_type = 'USER_DELETED';

Результаты

ID | EVENT_TYPE   | EVENT_DATE | USER_ID | NUM_ACTIVATED
-: | :----------- | :--------- | ------: | ------------:
 3 | USER_DELETED | 05-JAN-19  |    5302 |             1

Запрос 2 :

Если вы просто хотите задействовать USER_ID s, тогда вы можете использовать GROUP BY и HAVING:

SELECT USER_ID
FROM   USER_EVENTS
GROUP BY USER_ID
HAVING MIN( CASE EVENT_TYPE WHEN 'USER_DELETED' THEN EVENT_DATE END )
         < MIN( CASE EVENT_TYPE WHEN 'USER_ACTIVATED' THEN EVENT_DATE END )

Результаты :

| USER_ID |
| ------: |
|    5302 |

дБ <> скрипка здесь

0 голосов
/ 17 января 2019

Вы можете использовать внутреннее соединение между набором буксирных строк, к которому присоединяются user_id и датой

select  user_id, event_date 
from USER_EVENTS  U
inner join  
(
select  user_id, event_date 
from USER_EVENTS 
where EVENT_TYPE ='USER_DELETED'
) T ON T.event_date < U.event_date 
    AND T.user_id= U.user_id  

WHERE EVENT_TYPE ='USER_ACTIVATED' 
0 голосов
/ 17 января 2019

Просто найдите удаления перед активацией:

With activations as
( select * from t where EVENT_TYPE="USER_ACTIVATED"
),
deletions as
( select * from t where EVENT_TYPE="USER_DELETED"
),
select *
from deletions d
left outer join activations a
on d.USER_ID = a.USER_ID and
   d.EVENT_DATE < a.EVENT_DATE   --here
0 голосов
/ 17 января 2019

вы можете попробовать, как показано ниже, используя объединение и подзапрос

select t1.USER_ID from 
(
select USER_ID,max(EVENT_DATE) as EVENT_DATE from 
USER_EVENTS where EVENT_TYPE='USER_ACTIVATED'
group by USER_ID
) t1 
join
select * from 
(
select USER_ID,max(EVENT_DATE) as EVENT_DATE from 
USER_EVENTS where EVENT_TYPE='USER_DELETED'
 group by USER_ID
) t2 on t1.=t2.USER_ID and t2.EVENT_DATE>t1.EVENT_DATE
0 голосов
/ 17 января 2019

Для одноразового упражнения (при условии, что базовая таблица не слишком велика), простым решением является подзапрос. Выберите всех удаленных пользователей, затем найдите все соответствующие активированные записи с более поздней датой события:

with del as ( 
 select user_id
        , event_date as date_deleted
 from user_events
 where event_type = 'USER_DELETED'
)
select del.user_id
      , del.date_deleted
      , act.event_date as date_activated
from del
     join user_events act
          on act.user_id = del.user_id
where act.event_type = 'USER_ACTIVATED'
and del.date_deleted < act.event_date
order by del.user_id
/

Как показывают другие ответы, есть много способов написать выше. Другое простое решение - самостоятельное соединение:

select del.user_id
      , del.date_deleted
      , act.event_date as date_activated
from user_events del
     join user_events act
          on act.user_id = del.user_id
where del.event_type = 'USER_DELETED'
and act.event_type = 'USER_ACTIVATED'
and del.date_deleted < act.event_date
order by del.user_id
/
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...