2015-10-28 3 views
0

У меня есть SQL, который терпит неудачу в левом внешнем объединении подзапроса сOracle проблема с левым внешним соединением подзапрос

ORA-01427: single-row subquery returns more than one row 

Вот фрагмент left outer join запроса:

LEFT OUTER JOIN (aa.location) LOCATION 
    ON (location_info_300.client_num = location.client_num 
    AND location_info_300.source = location.source 
    AND location_info_300.location_code = location.location_code 
    AND 1 = 
      (SELECT ROW_NUMBER() 
        OVER(PARTITION BY location_code, client_num, SOURCE 
         ORDER BY expiry_date DESC) 
         AS rec_order_by_expiry_desc 
       FROM aa.location l2 
      WHERE location.client_num = l2.client_num 
       AND location.source = l2.source 
       AND location.location_code = l2.location_code 
       AND l2.expiry_date >= 
         TO_DATE('01-JAN-' || location_info_300.reporting_year, 
           'DD-MON-YYYY') 
       AND l2.effective_date <= 
         TO_DATE('31-DEC-' || location_info_300.reporting_year, 
           'DD-MON-YYYY'))) 

Я попытался ее исправление выполнив следующие изменения в последних AND критериев:

1 = 
(SELECT rec_order_by_expiry_desc 
    FROM (SELECT ROW_NUMBER() OVER (PARTITION BY LOCATION_CODE, CLIENT_NUM, SOURCE ORDER BY EXPIRY_DATE DESC) AS REC_ORDER_BY_EXPIRY_DESC 
    FROM aa.LOCATION l2 
    WHERE location.CLIENT_NUM = l2.CLIENT_NUM 
    AND location.SOURCE = l2.SOURCE 
    AND location.LOCATION_CODE = l2.LOCATION_CODE 
    AND l2.EXPIRY_DATE >= TO_DATE('01-JAN-'||location_info_300.REPORTING_YEAR,'DD-MON-YYYY') 
    AND l2.EFFECTIVE_DATE <= TO_DATE('31-DEC-'||location_info_300.REPORTING_YEAR,'DD-MON-YYYY')) 
WHERE rec_order_by_expiry_desc = 1) 

Но теперь я я получаю следующую ошибку:

ORA-00904: "LOCATION_INFO_300"."REPORTING_YEAR": invalid identifier 

Я не уверен, что еще попробовать. Я надеюсь, что кто-то это сделает!

+0

«LOCATION_INFO_300» находится в пункте где из не из пункта. –

+1

проверка на 1 = (получение номера строки для максимальной даты истечения срока действия) просто проверяет, что для этих критериев максимальная дата истечения срока действия, и если да, тогда все строки будут возвращены для этой комбинации клиента, источника и местоположения. Это то, что вы хотите? –

ответ

3

Я думаю, что вы в основном проверяете, существует ли строка в подзапросе? Если это так, то просто сделать EXISTS:

LEFT OUTER JOIN (aa.location) LOC 
           ON (location_info_300.client_num = loc.client_num 
            AND location_info_300.source = loc.source 
            AND location_info_300.location_code = loc.location_code 
            AND exists (SELECT null 
               FROM aa.location l2 
               WHERE loc.client_num = l2.client_num 
               AND loc.source = l2.source 
               AND loc.location_code = l2.location_code 
               AND l2.expiry_date >= TO_DATE('01-JAN-' || location_info_300.reporting_year, 'DD-MON-YYYY') 
               AND l2.effective_date <= TO_DATE('31-DEC-' || location_info_300.reporting_year, 'DD-MON-YYYY'))) 

нотабене Я изменил псевдоним таблицы aa.location, чтобы избежать возможных конфликтов между таблицами aa.location внешнего и подзапроса (гораздо лучше убедиться, что псевдонимы не совпадают с именами существующих идентификаторов, чтобы избежать какой-либо потенциальной области проблемы с конфликтом. Кроме того, это облегчает понимание, когда вы читаете запрос).

+0

Что будет лучше, используя 'EXISTS' или заменив' = 'на' IN', чтобы проверить, существует ли запись, что позволяет избежать ошибки ORA-01427'? – user3224907

+2

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

1

Ваш первый подзапрос должен возвращать ровно одну строку, но он возвращает более одного.

Это потому, что вы выполняете аналитическую функцию, которая по существу должна возвращать разнообразное количество строк. Единственный способ утверждать, что будет возвращена только одна строка, - это использовать агрегатную функцию или использовать условия, которые это гарантируют.

Что касается второго запроса, обратите внимание, что вы вызываете поле из таблицы, которая не существует в данном контексте.

Если вы пытаетесь проверить, существует ли строка или нет, вы должны прочитать ее в функции EXISTS или, возможно, использовать COUNT в подзапросе.

Edit: вот пример для второго варианта (кулак уже отвечал):

(SELECT COUNT(*) 
       FROM aa.location l2 
      WHERE location.client_num = l2.client_num 
       AND location.source = l2.source 
       AND location.location_code = l2.location_code 
       AND l2.expiry_date >= TO_DATE('01-JAN-' || location_info_300.reporting_year, 'DD-MON-YYYY') 
       AND l2.effective_date <= TO_DATE('31-DEC-' || location_info_300.reporting_year, 'DD-MON-YYYY')) 

Обратите внимание, что я удалил поля в PARTITION BY пункта и не добавить их в GROUP BY, поскольку они противоречат вашей потребности только в одной строке.

1

проверка на 1 = (получение номера строки для максимальной даты истечения срока действия) просто проверяет, что для этих критериев существует максимальная дата истечения срока действия, и если да, тогда все строки будут возвращены для этой комбинации клиента, источника и местоположения. Это то, что вы хотите?

Если вы хотите фактическую запись с максимальной датой истечения срока, то

LEFT OUTER JOIN (aa.location) LOCATION 
    ON (location_info_300.client_num = location.client_num 
    AND location_info_300.source = location.source 
    AND location_info_300.location_code = location.location_code 
    AND location.expiry_date = 
      (SELECT MAX(expiry_date) 
       FROM aa.location l2 
      WHERE location.client_num = l2.client_num 
       AND location.source = l2.source 
       AND location.location_code = l2.location_code 
       AND l2.expiry_date >= 
         TO_DATE('01-JAN-' || location_info_300.reporting_year, 
           'DD-MON-YYYY') 
       AND l2.effective_date <= 
         TO_DATE('31-DEC-' || location_info_300.reporting_year, 
           'DD-MON-YYYY'))) 
+0

В чем разница между вашим вторым запросом и использованием примера пользователя @boneist? – user3224907

+0

глядя на него, они по сути идентичны, поэтому я удалю второй запрос из моего. Спасибо что подметил это. –

Смежные вопросы