Левое соединение для разделения запросов из одного и того же представления

#sql #postgresql #count #sum #aggregate-functions

#sql #PostgreSQL #количество #Сумма #агрегатные функции

Вопрос:

Я все еще новичок в изучении PSQL и задавался вопросом, как соединить по ЛЕВОМУ КРАЮ два отдельных запроса, которые я извлекаю из одного и того же материализованного представления.

Вот мой первый запрос:

 select rep_name, Count(enroll_date) new_orders, Sum(invoice_total) contract_total, Avg(invoice_total) avg_contract_total
from recent_billing_mat_view
where
    enroll_date <= current_date
    AND enroll_date > (current_date - '30 days'::interval)
    AND product_type = 'CTF'
    AND pay_type <> 'Credit'
group by rep_name
  

И он возвращает следующее:

 rep_name   new_orders  contract_total avg_contract_total
"Alyssa"    9               2515       279.444444444444
"Carlos"    24              6585       274.375
"Cheryle"   14              4871       347.928571428571
"Nicholas"  19              4775       251.315789473684
"Piero"     13              4405.5     338.884615384615
"Susan"     15              4450.5     296.7
"Valerie"   16              4640       290
"Yelitza"   12              3607       300.583333333333
  

Вот мой второй запрос:

 select rep_name,  Count(enroll_date) orders_paid
from recent_billing_mat_view
where
    enroll_date <= current_date
    AND enroll_date > (current_date - '30 days'::interval)
    AND product_type = 'CTF'
    AND pay_type <> 'Credit'
    AND amount_paid > 0
group by rep_name
  

И он возвращает следующее:

 rep_name    orders_paid
"Alyssa"        6
"Carlos"        16
"Cheryle"       8
"Nicholas"      14
"Piero"         9
"Susan"         8
"Valerie"       10
"Yelitza"       9
  

Я использую 2-й запрос, чтобы получить количество всех заказов, которые были оплачены за каждого представителя, и я хочу присоединиться к нему в первом запросе. В настоящее время я получаю сообщение об ошибке: ОШИБКА: синтаксическая ошибка на или рядом с «LEFT».

Вот с чем я работаю:

 select r.rep_name, Count(enroll_date) new_orders, Sum(invoice_total) contract_total, Avg(invoice_total) avg_contract_total
from recent_billing_mat_view r
where
    r.enroll_date <= current_date
    AND r.enroll_date > (current_date - '30 days'::interval)
    AND r.product_type = 'CTF'
    AND r.pay_type <> 'Credit'
group by r.rep_name
LEFT JOIN (
select Count(enroll_date) orders_paid
from recent_billing_mat_view p
where
    p.enroll_date <= current_date
    AND p.enroll_date > (current_date - '30 days'::interval)
    AND p.product_type = 'CTF'
    AND p.pay_type <> 'Credit'
    AND p.amount_paid > 0
group by rep_name
) as p On r.rep_name = p.rep_name
  

Как бы я хотел, чтобы результаты выглядели:

 rep_name   new_orders  contract_total avg_contract_total  orders_paid
"Alyssa"    9               2515       279.444444444444        6
"Carlos"    24              6585       274.375                 16
"Cheryle"   14              4871       347.928571428571        8
"Nicholas"  19              4775       251.315789473684        14
"Piero"     13              4405.5     338.884615384615        9
"Susan"     15              4450.5     296.7                   8
"Valerie"   16              4640       290                     10
"Yelitza"   12              3607       300.583333333333        9
  

Чего мне здесь не хватает? Есть ли лучший способ сделать это без ЛЕВОГО СОЕДИНЕНИЯ?

Спасибо!

Ответ №1:

Второй запрос полностью идентичен первому, за исключением одного условия в where предложении. Вы можете просто использовать условную агрегацию:

 select rep_name, 
    count(*) new_orders, 
    sum(invoice_total) contract_total, 
    avg(invoice_total) avg_contract_total,
    count(*) filter(where amount_paid > 0) orders_paid
from recent_billing_mat_view
where
    enroll_date <= current_date
    and enroll_date > current_date - '30 days'::interval
    and product_type = 'CTF'
    and pay_type <> 'Credit'
group by rep_name
  

Примечание: способ построения вашего enroll_date запроса никогда не может быть null (потому что он фильтруется в where предложении): so count(enroll_date) эквивалентно count(*) и более эффективно.