SQL LEFT JOIN не возвращает нулевые значения

#postgresql

#postgresql

Вопрос:

Кажется, что это должно быть просто, но мне не хватает некоторых знаний о соединениях.

Предположим, у меня есть две таблицы:

 bi_view_in_invoices            payments 
id     due_date                id      payment_system_paid_date
1      2020-01-15              1       2020-01-16
2      2020-02-13              2       2020-01-10
3      2020-03-01              2       2020-02-19
4      2020-03-02              3       2020-02-11
                               3       2020-03-03
                               4       2020-02-11
 

Я хочу объединить эти две таблицы по id: чтобы вернуть due_date из Table1 и вернуть payment_system_paid_date из Table2 только в том случае, если он находится между одним днем до due_date и тремя днями позже. Иначе он должен возвращать значение null.
Это должно выглядеть так:

 Result:                
id     due_date      payment_system_paid_date
1      2020-01-15    2020-01-16
2      2020-02-13    null  
3      2020-03-01    2020-03-03        
4      2020-03-02    null         
 

Я попробовал этот SQL:

 select bvii.id, bvii.due_date, h1.pd, *
from bi_view_in_invoices bvii 
left join payments p 
    on bvii.id = p.id
inner join (
    select bvii.number, min(p.payment_system_paid_date) as pd
    from bi_view_in_invoices bvii 
    left join payments p 
    on bvii.id = p.id
    where p.payment_system_paid_date >= (bvii.due_date - 1)
    and p.payment_system_paid_date <= (bvii.due_date   3)
    group by bvii.number
) h1
    on bvii.number = h1.number 
    and p.payment_system_paid_date = h1.pd
 

Он возвращает мне только эти идентификаторы, которые имеют дату, и не возвращает нулевые значения.
Мой результат выглядит так:

 id     due_date      payment_system_paid_date
1      2020-01-15    2020-01-16
3      2020-03-01    2020-03-03               
 

Не могли бы вы посоветовать мне, что я делаю не так?

Я также пытался добавить:

или p.payment_system_paid_date не равен нулю, а h1.pd равен нулю

но, похоже, это тоже не работает.

Спасибо!

Комментарии:

1. Должно быть ... left join payments p on (bvii.id = p.id and p.payment_system_paid_date >= (bvii.due_date - 1) and p.payment_system_paid_date <= (bvii.due_date 3)) group by bvii.number ...

2. кажется, это работает! еще одна проблема: мне действительно нужно использовать еще несколько столбцов из моих таблиц, и я не могу использовать group by, так как тогда все столбцы в select должны использоваться в агрегатной функции. Есть ли способ решить эту проблему?

3. Это еще один, другой вопрос.

Ответ №1:

 with t1(x,y) as (values(1,10),(2,20)), t2(x,y) as (values(1,12),(2,18))
select *
from t1 left join t2 on (t1.x = t2.x)
where t1.y < t2.y;

┌───┬────┬───┬────┐
│ x │ y  │ x │ y  │
├───┼────┼───┼────┤
│ 110112 │
└───┴────┴───┴────┘

with t1(x,y) as (values(1,10),(2,20)), t2(x,y) as (values(1,12),(2,18))
select *
from t1 left join t2 on (t1.x = t2.x and t1.y < t2.y);

┌───┬────┬──────┬──────┐
│ x │ y  │  x   │  y   │
├───┼────┼──────┼──────┤
│ 110112 │
│ 220 │ ░░░░ │ ░░░░ │
└───┴────┴──────┴──────┘
 

where условие здесь понижается left join до inner join неявного.