2016-09-26 2 views
1

У меня есть производная таблица со столбцами, как:Выясните первая запись, что выше определенного значения

  • электронной почты (основной идентификатор)
  • transaction_time
  • количество

Как смотреть для клиентов (идентифицированных по электронной почте) на основе amount > 500 для первой транзакции в PostgreSQL?

Примечание: Это используется в подзапросе, который используется для фильтрации основной таблицы.

+2

Можете ли вы добавить пример данных и ожидаемый результат. –

ответ

0

Это, вероятно, следует сделать это:

SELECT DISTINCT ON (email) * 
FROM t 
WHERE amount > 500 
ORDER BY email, transaction_time 

Она возвращает первую транзакцию (по отношению к transaction_time) для каждого сообщения электронной почты.

+3

Мэтт, пожалуйста, изучите DISTINCT ON. –

2

Ниже решение будет более портативным, чем DISTINCT ON, что является специфичным для Postgres. Используйте row_number() для перечисления строк и получить все различные клиентов (идентифицированный по электронной почте), которые имеют свою первую сумму сделки больше, чем 500.

Edit: Я включал три пути для достижения того же результата. Выберите то, что вы предпочитаете.

Первый подход - использование row_number()

select 
    distinct email 
from (
    select 
    email, 
    amount, 
    row_number() OVER (PARTITION BY email ORDER BY transaction_time) AS rn 
    from <derived_table_here> 
) t 
where 
    rn = 1 
    and amount > 500 

Второй подход - использование DISTINCT ON

select 
    email 
from (
    select distinct on (email) 
    email, 
    amount 
    from <derived_table_here> 
    order by email, transaction_time 
) t 
where amount > 500 

Третий подход - использование NOT EXISTS

select 
    email 
from <derived_table_here> t1 
where 
    amount > 500 
    and not exists(
    select 1 
    from <derived_table_here> t2 
    where 
     t1.email = t2.email 
     and t1.transaction_time > t2.transaction_time 
    ) 

Я нахожу третий метод наиболее переносимым, поскольку MySQL, например, не поддерживает функции окна AFAIK. Это просто в случае переключения между базами данных в будущем - меньше работы для вас.


Проверено на образце ниже:

 email  |  transaction_time  | amount 
-----------------+----------------------------+-------- 
[email protected] | 2016-09-26 19:01:15.297251 | 400 -- 1st, amount < 500 
[email protected] | 2016-09-26 19:01:19.160095 | 500 
[email protected] | 2016-09-26 19:01:21.526307 | 550 
[email protected] | 2016-09-26 19:01:28.659847 | 600 -- 1st, amount > 500 
[email protected] | 2016-09-26 19:01:30.292691 | 200 
[email protected] | 2016-09-26 19:01:31.748649 | 300 
[email protected] | 2016-09-26 19:01:38.59275 | 200 -- 1st, amount < 500 
[email protected] | 2016-09-26 19:01:40.833897 | 100 
[email protected] | 2016-09-26 19:01:51.593279 | 501 -- 1st, amount > 500 
+0

Насколько я понимаю, применение предложения where может дисквалифицировать первые транзакции, тогда как мы не можем дисквалифицировать первые транзакции, независимо от их количества в начале, но вместо этого отметьте их как первые. –

+0

@Matt на самом деле я проверил это, и вы ошибаетесь. –

+0

Да, я пропустил то, что вы делали сначала, и интерпретировал его по-разному. но есть еще лучший способ в 1 запросе – Matt

0

другой вариант:

select * from t t1 
where amount > 500 
and not exists 
(select 1 from t t2 where t1.email=t2.email and t1.transaction_time>t2.transaction_time) 
0

ЛЕВЫЙ автообъединение МЕТОД

SELECT t1.* 
    FROM 
     ExmapleTable t1 
     LEFT JOIN ExmapleTable t2 
     ON t1.Email = t2.Email 
     AND t2.transaction_time < t1.transaction_time 
    WHERE 
     t1.Amount >= 500 
     AND t2.Email IS NULL 
    ; 

http://rextester.com/XRQTX2627