Ошибка sql 01427

ORA-01427

ORA-01427: запрос к единственной строке возвращает более чем одну строку

Причина:

Так как ваш подзапрос возвращает более чем одну строку, ваш внешний запрос должен использовать одно из ключевых слов ANY, ALL, IN, или NOT IN для указания значений для сравнения.

Действие:

Используйте ANY, ALL, IN или NOT IN для указания какие значения надо сравнивать, или сформулируйте запрос так, чтобы находилась одна строка.

Приходилось сталкиваться с такой ошибкой?
Читаем дальше.

Зачем же использовать такие подзапросы, коль возможны ошибки?
Но ведь удобно же!

Пример.
Ест у нас запрос, который скажем выводит некий список расходных транзакций модуля Inventory


SELECT ...
FROM mtl_material_transactions mmt
WHERE ...

Нам здесь не важно, что выводит этот список и по какому критерию, но нужно отметить, что за многоточиями может скрываться не один десяток, а то и не одна сотня, строк кода.

Но вот возникла необходимость добавить в запрос еще одну колонку — счет ГК с которого списали ТМЦ. Мы знаем, что в таблице mtl_transaction_accounts по коду складской транзакции можно найти две полупроводки, одна с положительной суммой (дебет), другая с отрицательной (кредит). Ну вот значит счет кредитовой полупроводки нас и интересует. Самым простым способом «вклиниться» в существующий запрос будет что-то такое:


SELECT ...
,(SELECT mta.reference_account
FROM mtl_transaction_accounts mta
WHERE mta.transaction_id = mmt.transaction_id
AND mta.base_transaction_value < 0
) AS "Счет учета ТМЦ"
FROM mtl_material_transactions mmt
WHERE ...

Запускаем — беда!
ORA-01427: подзапрос одиночной строки возвращает более одной строки

Почему возникла ошибка?
Для некоторых складских транзакций наши предположения оказались неверны.
И это плохо.
А плохо потому, что проблемными могут оказаться всего лишь пара записей из нескольких тысяч, а мы не увидим ничего, т.к. весь запрос возвращает ошибку.

Прежде чем начинать исправить ситуацию, нужно понять а какой собственно результат запроса был бы приемлемым, учитывая наличие складских транзакций с неожиданными распределениями(проводками)?

А хотелось бы, чтобы запрос таки отработал, и все сотни, а то и тысячи (а то и больше) «правильных» записей мы увидели, а для тех нескольких ошибочных пусть вернется хоть что-нибудь — мы с ними отдельно разберемся, главное чтобы их отличить от правильных можно было.

Теперь приступаем.
Итак для того чтобы ошибка не возникала, нужно чтобы там где подзапрос возвращает несколько записей — возвращалась одна.

Одна запись из нескольких может получиться при использовании групповых функций.
Ну что же:


SELECT ...
,(SELECT MAX(mta.reference_account)
FROM mtl_transaction_accounts mta
WHERE mta.transaction_id = mmt.transaction_id
AND mta.base_transaction_value < 0
) AS "Счет учета ТМЦ"
FROM mtl_material_transactions mmt
WHERE ...

Однако. Как оказалось, вернуть что-нибудь — не проблема, проблема потом понять что получили. Применив групповую функцию MAX мы гарантируем, что ошибки ORA-01427 больше не будет. Какой-нибудь счет да вернется. Но при таком подходе, мы никогда и не узнаем, что у нас есть записи с некорректно
определенным счетом.

Тем не менее, главный шаг к правильному решению уже сделан, осталось чуть-чуть. Ведь во всех случаях, где подзапрос возвращает одну запись, использование MAX не является ошибкой — максисум от одного значения равен самому значению. Значит нам нужно в тех случаях, где подзапрос возвращает одну запись — использовать
MAX (ну хотите MIN). А там где больше чем одну — возвращать значение, указывающее на ошибку.

Так ведь это же совсем не сложно сделать!
Количество записей подзапроса — это COUNT(*), условную логику можно реализовать через CASE или, по старинке, через DECODE. Не забудем и про то, что подзапрос может совсем не вернуть записей:

  
SELECT ...
,(SELECT DECODE(COUNT(*), 1,MAX(mta.reference_account), 0,NULL, -999)
FROM mtl_transaction_accounts mta
WHERE mta.transaction_id = mmt.transaction_id
AND mta.base_transaction_value < 0
) AS "Счет учета ТМЦ"
FROM mtl_material_transactions mmt
WHERE ...

Всё.
Теперь не только ошибка ORA-01427 больше не появится, но и можно легко найти те записи, где наша логика определения счета учета ТМЦ дала сбой.

Дополнительно отметим, что так как mta.reference_account имеет числовой тип данных, то и ошибочное значение должно быть числовым (-999). Для строковых типов данных можно было бы использовать — ‘Ошибка’ или ‘ORA-01427’. Для дат — что-то из далекого прошлого или будущего. Важно лишь, чтобы такого значения гарантированно не было в реальных данных.

Подводим итоги.
При использовании подзапросов вместо


SELECT
(SELECT t2.column
FROM table2
WHERE ...)
FROM table1 t1
WHERE ...

лучше использовать


SELECT
(SELECT DECODE(COUNT(*), 0,NULL, 1,MAX(t2.column), 'ORA-01427')
FROM table2
WHERE ...)
FROM table1 t1
WHERE ...

И не забыть разобраться почему появились записи с ‘ORA-01427’

The error ORA-01427 is raised, when a sub-query returns more than one row to an Equality or in-Equality operator.

ORA-01427

The reason being there are restrictions on the legal comparison operators.The single row subquery operator are

Symbol Meaning
= equal
> greater than
>= greater than or equal
< less than
<= less than or equal
<> not equal
!= not equal

So whenever you are using these single row subquery operator, if you return more than one row,it will start throwing the error

How to resolve the error ORA-01427

(1) either we change the query to use Multiple -row Subquery Operators 

Multiple-row Sub-query Operators
Symbol Meaning
IN equal to any member in a list
NOT IN not equal to any member in a list
ANY returns rows that match any value on a list
ALL returns rows that match all the values in a list

(2) We look at the query and find out what is happening, why it is returning more rows than expected. Like the way we resolved this error for Concurrent Manager issue. It is generally advisable  use the sub-query based on primary key in order to get consistent result,

Lets us take a look at few example

Few Examples

(1) While starting the concurrent Manager in the EBS environment, we were getting below error

Cause: cleanup_node failed due to ORA-01427: single-row subquery returns more than one row
ORA-06512: at "APPS.FND_CP_FNDSM", line 29
ORA-06512: at line 1.

This error happens when we have more than two FNDSM of FNDIM defined for the node.So we selected the node name of all the concurrent Manager in the system

Solution
We can resolve the solution manually through below update

SQL> select CONCURRENT_QUEUE_NAME,NODE_NAME from fnd_concurrent_queues group by CONCURRENT_QUEUE_NAME,NODE_NAME;
CONCURRENT_QUEUE_NAME NODE_NAME
FNDSCH SUNTEST
PODAMGR SUNTEST
FTE_TXN_MANAGER SUNTEST
FNDSM_20151_SUNTEST SUNTEST
FNDICM SUNTEST
FNDTMTST SUNTEST
STANDARD SUNTEST
FNDIM_SUNTEST SUNTEST
FNDIM_20153_SUNTEST SUNTEST
WFMLRSVC SUNTEST
XDP_Q_FE_READY_SVC SUNTEST
WMSTAMGR SUNTEST
INVMGR SUNTEST
AMSDMIN SUNTEST
FNDSM_SUNTEST SUNTEST

We can see there are two FNDSM and FNDIM for the node SUNTEST.


FNDSM_20151_SUNTEST SUNTEST
FNDIM_SUNTEST SUNTEST
FNDIM_20153_SUNTEST SUNTEST
FNDSM_SUNTEST SUNTEST

Lets do the update now

SQL> update fnd_concurrent_queues set NODE_NAME=null where CONCURRENT_QUEUE_NAME='FNDSM_20151_SUNTEST';
1 row updated.
SQL> update fnd_concurrent_queues set NODE_NAME=null where CONCURRENT_QUEUE_NAME='FNDIM_20153_SUNTEST';
1 row updated.
SQL> commit;
Commit complete.
SQL> select CONCURRENT_QUEUE_NAME,NODE_NAME from fnd_concurrent_queues group by CONCURRENT_QUEUE_NAME,NODE_NAME;
CONCURRENT_QUEUE_NAME NODE_NAME
FNDSCH SUNTEST
PODAMGR SUNTEST
FTE_TXN_MANAGER SUNTEST
FNDSM_20151_SUNTEST  
FNDICM SUNTEST
FNDTMTST SUNTEST
STANDARD SUNTEST
FNDIM_SUNTEST SUNTEST
FNDIM_20153_SUNTEST  
WFMLRSVC SUNTEST
XDP_Q_FE_READY_SVC SUNTEST
WMSTAMGR SUNTEST
INVMGR SUNTEST
AMSDMIN SUNTEST
FNDSM_SUNTEST SUNTEST

Or we can run conc clean and run autoconfig again to resolve the issue

SQL> EXEC FND_CONC_CLONE.SETUP_CLEAN;
COMMIT;
EXIT;

(2) Another example would be

SELECT * FROM employers
WHERE dept_id = (SELECT dept_id
FROM dept);

This will fail as we are selecting all dept_id in subquery while expecting one. This will succeed if dept is having one rows only. To resolve we need to add some where clause in subquery so that it returns one value

SELECT * FROM employers
WHERE dept_id = (SELECT dept_id
FROM dept where location='NEWYORK');

or

We can put in operator in place of equality operator

SELECT * FROM employers
WHERE dept_id in (SELECT dept_id
FROM dept);

I hope you this content on ORA-01427: single-row subquery returns more than one row. Please do provide feedback

Also Reads
ORA-00900 : Invalid Sql statement : check out this post for the various solutions for ORA-00900 invalid sql statement.Reasons for the error.How to debug and resolve it quickly,
ORA-03113 : Check out method to resolve ORA-03113: end-of-file on communication channel. This error could happen in database startup, running program
ora-29283: invalid file operation : check out this post on how to resolve ORA-29283 : invalid file operation
ORA-29285: file write error : ORA-29285: file write error is the common error while doing file handling operation.Check out this post on various reason and solution on how to solve it
ORA-00054 : ORA-00054: resource busy and acquire with NOWAIT specified with DDL statement,select for update,forms nowait locks,DDL_LOCK_TIMEOUT

Понравилась статья? Поделить с друзьями:
  • Ошибка spotify нет интернета
  • Ошибка riso j08
  • Ошибка spn 1041 камаз
  • Ошибка p2a00 опель антара
  • Ошибка spn 792 fmi 5 камаз евро