Оставленное внешнее соединение и необходимый подзапрос с датой в Oracle - PullRequest
0 голосов
/ 06 декабря 2018

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

(Этот вопрос отличается от Не работает левое внешнее соединение? тем, что необходим подзапрос для определения максимальной даты.)

Вот упрощенный пример:

Table Contracts:
customer_id, status

Table Values:
customer_id, value_code, value, begin_date

Я хочу отобразить всех клиентов со статусом = 'активный' и последним значениемдля определенного value_code, скажем, «громкость».Есть больше value_codes и значения имеют определенную дату, с которой они действительны.Также не может быть никакого value_code, НО тогда я хочу NULL на правой стороне.

Итак, вот что я пытался сделать:

SELECT * FROM CONTRACTS C
LEFT JOIN VALUES V ON C.CUSTOMER_ID = V.CUSTOMER_ID
                      AND VALUE_CODE = 'VOLUME'
WHERE C.STATUS = 'ACTIVE'
     AND V.BEGIN_DATE = (
                         SELECT MAX(BEGIN_DATE) FROM VALUES V2 
                         WHERE V2.CUSTOMER_ID = V.CUSTOMER_ID
                         AND V2.VALUE_CODE = 'VOLUME'
                         )

Я не могу поместить подзапрос впредложение присоединиться, Oracle не примет это.С другой стороны, мой подзапрос делает так, что все строки, которые не имеют записи для значения с кодом «volume», опущены.Я хочу иметь значение = NULL вместо всех клиентов слева.

Спасибо за помощь!

Ответы [ 2 ]

0 голосов
/ 06 декабря 2018

Поскольку MT0 предложил использовать разбиение и сортировку по номеру строки, помогло.Мне нужно было только включить value_code в разделение для моей цели.

Так что этот запрос, наконец, сделал то, что я хотел:

SELECT *
FROM   CONTRACTS C
       LEFT JOIN
       ( SELECT *
         FROM   (
           SELECT V.*,
                  ROW_NUMBER() OVER ( PARTITION BY CUSTOMER_ID, VALUE_CODE ORDER BY BEGIN_DATE DESC )
                    AS rn
           FROM   VALUES V
         )
         WHERE rn = 1
       ) V
ON     ( C.CUSTOMER_ID = V.CUSTOMER_ID
         AND VALUE_CODE = 'VOLUME' )
WHERE C.STATUS = 'ACTIVE'
0 голосов
/ 06 декабря 2018

Сначала отфильтруйте строки VALUE, а затем LEFT JOIN:

SELECT *
FROM   CONTRACTS C
       LEFT JOIN
       ( SELECT *
         FROM   (
           SELECT V.*,
                  ROW_NUMBER() OVER ( PARTITION BY CUSTOMER_ID ORDER BY BEGIN_DATE DESC )
                    AS rn
           FROM   VALUES V
         )
         WHERE rn = 1
       ) V
ON     ( C.CUSTOMER_ID = V.CUSTOMER_ID
         AND VALUE_CODE = 'VOLUME' )
WHERE C.STATUS = 'ACTIVE'
...