#sql #postgresql
#sql #postgresql
Вопрос:
Мне трудно заставить работать следующее:
У меня есть список транзакций, состоящий из Sender
, Recipient
, Amount
и Date
.
Table: Transactions
Sender Recipient Amount Date
--------------------------------------------------
Jack Bob 52 2019-04-21 11:06:32
Bob Jack 12 2019-03-29 12:08:11
Bob Jill 50 2019-04-19 24:50:26
Jill Bob 90 2019-03-20 16:34:35
Jill Jack 81 2019-03-25 12:26:54
Bob Jenny 53 2019-04-20 09:07:02
Jack Jenny 5 2019-03-29 06:15:35
Теперь я хочу перечислить людей, которые участвовали в транзакциях, в скольких транзакциях они участвовали, и даты первой и последней транзакции, в которой они участвовали :
Result
Person NUM_TX First_active last_active
------------------------------------------------------------------
Jack 4 2019-03-25 12:26:54 2019-04-21 11:06:32
Bob 5 xxxx-xx-xx xx:xx:xx xxxx-xx-xx xx:xx:xx
Jill 3 xxxx-xx-xx xx:xx:xx xxxx-xx-xx xx:xx:xx
Jenny 2 xxxx-xx-xx xx:xx:xx xxxx-xx-xx xx:xx:xx
Использование group by
оператора кажется неправильным — каков правильный способ достижения моей цели? Кстати, я работаю на postgres.
Ответ №1:
Вам нужно ОБЪЕДИНЕНИЕ, чтобы получить 2 столбца как 1 столбец person
результирующего набора, а затем group by person
:
select
t.person Person,
count(*) NUM_TX,
min(t.date) First_active,
max(t.date) Last_active
from (
select sender person, date from transactions
union all
select recipient person, date from transactions
) t
group by t.person
Комментарии:
1. Этот ответ также работает — поскольку я обрабатываю очень огромные объемы данных, другой помечен как принятый
Ответ №2:
Это хорошее место для использования бокового соединения:
select v.person, count(*) as num_transactions,
min(t.date) as first_date,
max(t.date) as last_date
from transactions t cross join lateral
(values (sender), (recipient)) v(person)
group by v.person;
Комментарии:
1. Круто, никогда не слышал об этом! Является ли боковое объединение предпочтительнее объединения для большого объема данных или я должен придерживаться решения ОБЪЕДИНЕНИЯ?
2. @Crack_David . , , Боковое соединение, в частности, лучше работает с большими объемами данных, потому что оно сканирует таблицу только один раз.
3. Привет @GordonLinoff Мне удалось заменить боковое соединение
CROSS APPLY
на SQL Server и получить тот же результат. Однако я не уверен, что именно(values (sender), (recipient)) v(person)
делает. Я пыталсяSELECT * FROM (values (sender), (recipient)) v(person)
, но это не удалось. Я думаю, вы берете отправителей и получателей и помещаете их в один столбец (как и в другом ответе, но намного быстрее). Но я учусьCROSS APPLY
, поэтому я немного смущен. Здесь скрипка SQL; dbfiddle.uk /…4. @NicholasHumphrey . , , Если у вас есть вопрос, его следует задавать как вопрос, а не комментарий.
5. @GordonLinoff Конечно, извините за это. Позвольте мне перефразировать это в вопрос.