2010-09-27 5 views
0

Я получаю сообщение об ошибке [ORA-01427: однострочный подзапрос возвращает более одной строки] при выполнении запроса. У меня есть запрос, структурированный так:Ошибочный ORA-01427: однострочный подзапрос возвращает более одной строки

SELECT LV.PRICE, 
(SELECT C.MODEL_NAME FROM CARS C WHERE C.MODEL_ID = LV.MODEL_ID) as MODEL_NAME 
FROM LEDGER_VIEW LV 
WHERE LV.PRICE < 500 

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

LEDGER_VIEW - это вид, построенный поверх другого вида. Возможно ли, что эти многоуровневые представления ошибочны в Oracle 10g? Я не знаю, как еще отладить эту проблему.

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

EDIT: Это действительно странная вещь. LEDGER_VIEW, как я сказал, построен поверх другого представления. В качестве теста я скопировал SQL вложенного представления непосредственно в SQL SQL of LEDGER_VIEW вместо вместо вложенного представления и вернулся без ошибок (как и ожидалось). Это, по-видимому, подтверждает мне, что существует некорректное поведение либо с вложенными представлениями, либо с комбинацией вложенных представлений + ссылок на базы данных.

+0

Когда вы говорите: «MODEL_ID - это уникальное поле», есть первичный ключ или уникальный индекс для его проверки? – pascal

+0

@pascal: Да, это первичный ключ в таблице CARS. –

+0

Может ли проблема быть в самом LEDGER_VIEW? – pascal

ответ

2

Я не может воссоздать с помощью создания сложенного зрения. (Althoug RedFilters найти виновника)

CREATE TABLE t1 
    (
     t1_id NUMBER  , 
     txt VARCHAR2(50), 
     CONSTRAINT t1_pk PRIMARY KEY(t1_id) 
    ) ; 


    CREATE TABLE t2 
    (
     t2_id NUMBER      , 
     t1_id NUMBER      , 
     price NUMBER(10, 4)    , 
     CONSTRAINT t2_pk PRIMARY KEY(t2_id), 
     CONSTRAINT t2_fk FOREIGN KEY(t1_id) REFERENCES t1(t1_id) 
    ); 

    insert into t1(t1_id, txt) values(1,'fit'); 
    insert into t1(t1_id, txt) values(2,'focus'); 
    insert into t1(t1_id, txt) values(3,'golf'); 
    insert into t1(t1_id, txt) values(4,'explorer'); 
    insert into t1(t1_id, txt) values(5,'corolla'); 

insert into t2(t2_id, t1_id, price) values(1,1,17000); 
insert into t2(t2_id, t1_id, price) values(2,2,16000); 
insert into t2(t2_id, t1_id, price) values(3,3,22000); 
insert into t2(t2_id, t1_id, price) values(4,4,31000); 
insert into t2(t2_id, t1_id, price) values(5,5,17000); 


create view t1_view as select * from t1; 
create view t2_view as select * from t2; 
create view t_stacked_view as 
    select t1_view.txt , 
     t2_view.price , 
     t1_view.t1_id 
    from t1_view 
      left join 
      t2_view 
      on t1_view.t1_id = t2_view .t1_id 
    ; 


--stacked view test 
select t1_view.txt , 
     (select t_stacked_view.price 
      from t_stacked_view 
      where t1_view.t1_id = t_stacked_view .t1_id) price 
    from t1_view ; 

--or better yet, just drop the row level query 
select t1_view.txt , 
     t2_view.price 
    from t1_view 
      left join 
      t2_view 
      on t1_view.t1_id = t2_view .t1_id 
    ; 

Но возникает вопрос, почему вы делаете запрос на уровне строк здесь? В то время как 10g должны оптимизировать их одинаково, мне всегда было легче писать запросы, как показано ниже, как для удобства чтения, так и для удобства, и специально избегать ошибки, которую вы имеете (всегда, 3 года в пути, гарантированной применение (как в БД и приложении вызова), что вы не можете иметь условие, которое будет вызывать эту ошибку? Один румяна заявление входит и все ваше приложение умирает?

SELECT LV.PRICE, 
      c.model_name 
FROM LEDGER_VIEW LV 
     LEFT /* OR INNER */ JOIN CARS C 
     ON C.MODEL_ID = LV.MODEL_ID 
WHERE LV.PRICE < 500 
+1

+1: er ... Я как бы пропустил верхнюю часть вашего вопроса (вложенные представления Oracle - это WAY над моей головой), но я заметил, что я писал идентичный SQL для кода внизу вашего сообщения в качестве нового ответа. .. (о, я также добавил недостающее слово JOIN в нижний запрос) – Powerlord

+0

@R. Bemrose упс! спасибо, что добавили это для меня! – Harrison

+0

Я переписал запрос, используя внутреннее соединение, и теперь он отлично работает. Мне просто хотелось бы найти объяснение ошибки, потому что это не имеет никакого смысла, и это меня беспокоит. Это не первый случай, когда у меня возникла проблема между этими двумя связанными базами данных, которые наш администратор не мог объяснить. –

4

Ваш подзапрос возвращает несколько строк. Используйте запрос ниже, чтобы узнать, какие MODELID значения в таблице Car продублировано:

select MODELID as CarsModelID, count(*) as Count 
from cars 
where MODELID in (
    select MODEL_ID 
    from LEDGER_VIEW 
    WHERE LV.PRICE < 500 
) 
group by MODELID 
having count(*) > 1 
+0

Этот запрос возвращает 0 записей. Мой исходный возвращает 5 строк, и если я добавлю LV.MODEL_ID в возвращаемые столбцы, все 5 строк имеют MODEL_ID = 27. Если я тогда hardcode C.MODEL_ID = 27 вместо C.MODEL_ID = LV.MODEL_ID, он возвращает ожидаемый 5 строк с правильным MODEL_NAME. LEDGER_VIEW построен поверх другого представления, которое использует ссылку на базу данных, которая является единственной потенциальной странностью, которую я могу идентифицировать в этом запросе - в противном случае это очень просто. –

+0

Есть ли таблица «CARS» на удаленной БД, и если у этого есть дубликаты? Разумеется, не стоит смотреть на удаленный. –

1

Я предлагаю использовать ответ RedFilter, чтобы проверить, есть ли это несколько автомобилей с заданным MODEL_ID.

Если вы абсолютно уверены, что CARS.MODEL_ID уникален, это означает, что сообщение об ошибке генерируется путем выбора из LEDGER_VIEW - поэтому попробуйте запустить эквивалентный запрос без подзапроса на АВТОМОБИЛЕЙ, например, так:

SELECT LV.PRICE 
FROM LEDGER_VIEW LV 
WHERE LV.PRICE < 500 

Если вы по-прежнему видим ту же ошибку (вы должны, если CARS.MODEL_ID уникален) вам нужно отладить LEDGER_VIEW - то есть. проверьте, чтобы подзапросы возвращали несколько строк в LEDGER_VIEW и основные представления, на которых он основан.

Создание представлений на основе представлений возможно в большинстве форм SQL, но, как правило, это плохая идея - именно по этой причине.

+0

Выбор из LEDGER_VIEW не дает мне ошибки ... это только когда я добавляю подзапрос, соединяющий MODEL_ID. LEDGER_VIEW объединяет локальные таблицы с несколькими удаленными таблицами в DB Link, используя подсказку DRIVING_SITE (remote). Сообщение об ошибке сообщается удаленной базой данных. –

+0

Я предлагаю повторить вышеупомянутый запрос с помощью подсказки DRIVING_SITE (remote); тот факт, что сообщение об ошибке сообщается удаленной базой данных, похоже, подтверждает, что проблема связана с LEDGER_VIEW. –

0

Попробуйте заставляет подзапрос возвращает единственный результат, прилагая ROWNUM = 1, как это:

SELECT LV.PRICE, 
(SELECT C.MODEL_NAME FROM CARS C WHERE C.MODEL_ID = LV.MODEL_ID AND ROWNUM = 1) as MODEL_NAME 
FROM LEDGER_VIEW LV 
WHERE LV.PRICE < 500 

Это вероятно, будет работать, и если это произойдет, вы будете знать, что ваш подзапрос возвращает несколько строк, которые, судя по коду ошибки он должен быть. Конечно, это не решение, поэтому вам, возможно, придется исправить свои данные в таблице автомобилей, чтобы реально решить проблему. «Уход» и «rownum = 1» устраняют ошибку, если model_id снова дублируется, чтобы вы не заметили проблему.

+0

'rownum = 1' этого не сделает, вы должны использовать' rownum <2' –

+0

@be здесь сейчас: 'rownum = 1' works. Это просто, когда вы пытаетесь использовать значение, большее, чем 'rownum = x' не работает. – Allan

+0

rownum = 1 и rownum <2 эквивалентны, поскольку нумерация строк в Oracle начинается с 1 и растет вверх. – vls

0
select 
            a.account_number, 
            a.party_id, 
            a.TRX_NUMBER, 
            a.trx_date, 
            a.order_number, 
            adv.unapplied_amt, 
            a.Finance, 
            a.customer_name,a.PARTY_NAME, 
            a.customer_number,a.contact_number, 
            a.name, 
            a.Aging, 
            a.transaction_type, 
            a.exec_name, 
            a.team_leader, 
            sum(a.O_SAmount), 
            (case when (trunc(sysdate) - trunc(a.trx_date)) <=:ag1 then sum(a.O_SAmount) else 0 end) bucket1,--"<" || :ag1, 
            (case when (trunc(sysdate) - trunc(a.trx_date)) between :ag1+1 and :ag2 then sum(a.O_SAmount) else 0 end) bucket2,--:ag1+1 || "to" || :ag2, 
            (case when (trunc(sysdate) - trunc(a.trx_date)) between :ag2+1 and :ag3 then sum(a.O_SAmount) else 0 end) bucket3,--:ag2+1 || "to" || :ag3, 
            (case when (trunc(sysdate) - trunc(a.trx_date)) >:ag3 then sum(a.O_SAmount) else 0 end) bucket4, 
            :AS_ON_date 
from 
(select distinct hca.account_number,hp.party_id,--rcta.CUSTOMER_TRX_ID, 
--rcta.trx_number,rcta.trx_date,apsa.due_date, 
(
select distinct 
          --ooha.order_number, 
          rcta.trx_number 
          --to_char(rcta.trx_date,'DD-MON-YYYY') trx_date 
from        
          ra_customer_trx_all rcta, 
          oe_order_headers_all ooh, 
          oe_order_lines_all oola, 
          --ra_customer_trx_all rcta, 
          ra_customer_trx_lines_all rctla, 
          ra_cust_trx_types_all rctta 
          --ra_customer_trx_lines_all rctl 
where 1=1 
       AND ooh.header_id = oola.header_id 
        --AND ooh.order_number = '111111010101698' 
        AND ooh.order_number=oohA.order_number 
        AND TO_CHAR (ooh.order_number) = rcta.ct_reference 
        AND rcta.customer_trx_id = rctla.customer_trx_id 
        AND rctla.inventory_item_id = oola.inventory_item_id 
        and rcta.CUST_TRX_TYPE_ID = rctta.cust_trx_type_id 
        and rcta.org_id = rctta.org_id 
        and rctta.type like 'INV' 
        and oola.ordered_item LIKE 'MV%' 
        AND oola.attribute3 = 'Y' 
        AND ooh.flow_status_code <> 'ENTERED' 
        AND oola.flow_status_code <> 'CANCELLED' 
)TRX_NUMBER, 
(select distinct 
--ooha.order_number, 
--rcta.trx_number 
rcta.trx_date 
from 
      ra_customer_trx_all rcta, 
      oe_order_headers_all ooh, 
      oe_order_lines_all oola, 
      --ra_customer_trx_all rcta, 
      ra_customer_trx_lines_all rctla, 
      ra_cust_trx_types_all rctta 
      --ra_customer_trx_lines_all rctl 
where 1=1 
       AND ooh.header_id = oola.header_id 
       --AND ooh.order_number = '111111010101698' 
       AND ooh.order_number=oohA.order_number 
       AND TO_CHAR (ooh.order_number) = rcta.ct_reference 
       AND rcta.customer_trx_id = rctla.customer_trx_id 
       AND rctla.inventory_item_id = oola.inventory_item_id 
       and rcta.CUST_TRX_TYPE_ID = rctta.cust_trx_type_id 
       and rcta.org_id = rctta.org_id 
       and rctta.type like 'INV' 
       and oola.ordered_item LIKE 'MV%' 
       AND oola.attribute3 = 'Y' 
       AND ooh.flow_status_code <> 'ENTERED' 
       AND oola.flow_status_code <> 'CANCELLED' 
)TRX_Date, 
rcta.INTERFACE_HEADER_ATTRIBUTE1 order_number, 
ooha.attribute10 Finance, 
f.customer_name,HP.PARTY_NAME, 
TO_NUMBER(f.customer_number)customer_number,hp.primary_phone_number contact_number,--csi.incident_number, 
--cii.instance_number, 
haou.name, 
--sum(acr.amount) Advance,--rcta.CUST_TRX_TYPE_ID,--acr.cash_receipt_id, 
--sum(abs((apsa.AMOUNT_DUE_REMAINING-nvl(acr.amount,0)))) "O_SAmount", 
apsa.AMOUNT_DUE_REMAINING O_SAmount, 
--sum(abs((apsa.AMOUNT_DUE_REMAINING))) "O_SAmount", 
round(months_between(sysdate,rcta.trx_date)*30) Aging, 
--(case when ((round(months_between(sysdate,rcta.trx_date)*30)>=0) or (round(months_between(sysdate,rcta.trx_date)*30)<:aging1)) then apsa.AMOUNT_DUE_REMAINING end) "0 TO 30" 
--(case when (trunc(sysdate) - trunc(apsa.Due_Date)) <=:ag1 then apsa.AMOUNT_DUE_REMAINING else 0 end) bucket1,--"<" || :ag1, 
--(case when (trunc(sysdate) - trunc(apsa.Due_Date)) between :ag1+1 and :ag2 then apsa.AMOUNT_DUE_REMAINING else 0 end) bucket2,--:ag1+1 || "to" || :ag2, 
--(case when (trunc(sysdate) - trunc(apsa.Due_Date)) between :ag2+1 and :ag3 then apsa.AMOUNT_DUE_REMAINING else 0 end) bucket3,--:ag2+1 || "to" || :ag3, 
--(case when (trunc(sysdate) - trunc(apsa.Due_Date)) >:ag3 then apsa.AMOUNT_DUE_REMAINING else 0 end) bucket4, 
--apsa.amount_due_original, 
--TO_NUMBER(apsa.AMOUNT_DUE_REMAINING)AMOUNT_DUE_REMAINING, 
rctta.name transaction_type, 
PAPF.full_name||'-'||PAPF.EMPLOYEE_NUMBER exec_name, 
ooha.attribute9 team_leader, 
:AS_ON_date 
from     ra_customer_trx_all rcta, 
         oe_order_headers_all ooha, 
         hz_cust_accounts hca, 
         hz_parties hp, 
         --cs_incidents_all_b csi, 
         --csi_item_instances cii, 
         hr_all_organization_units haou, 
         ar_cash_receipts_all acr, 
         ar_receivable_applications_all aaa, 
         ra_cust_trx_types_all RCTTA, 
         hr.per_all_people_f papf, 
         ar_customers f, 
         ar_payment_schedules_all apsa, 
         jtf.JTF_RS_SALESREPS jrs 
where 1=1 
         --and INTERFACE_HEADER_ATTRIBUTE1 like '111111060100538' 
         --and INTERFACE_HEADER_ATTRIBUTE1 like '111111010105402' 
         --and INTERFACE_HEADER_ATTRIBUTE1 like '111111010102791' 
         and rcta.ct_reference(+)=TO_CHAR(ooha.order_number) 
         AND f.customer_id = (rcta.bill_to_customer_id) 
         and f.customer_id=hca.cust_account_id 
         and hca.party_id=hp.party_id 
         and haou.organization_id=rcta.INTERFACE_HEADER_ATTRIBUTE10 
         --and hp.party_id=cii.owner_party_id 
         --and csi.inventory_item_id=cii.inventory_item_id 
         --and csi.inv_organization_id=haou.organization_id 
         --and haou.organization_id=nvl(:location,haou.organization_id) 
         and ooha.SHIP_FROM_ORG_ID=nvl(:location,haou.organization_id) 
         AND RCTTA.NAME like :transaction_type||'%' 
         --decode(:org_id,null,null,(select name from ar_cash_receipts_all where organization_id = :org_id)) ||'%') 
         and rcta.trx_date<=to_date(:AS_ON_date) 
         --AND RCTTA.NAME=NVL(:TRANS_TYPE,RCTTA.NAME) 
         and rcta.org_id=nvl(:org_id,rcta.org_id) 
         --and f.customer_name like 'VIKAS SATAV' 
         and aaa.applied_customer_trx_id(+)=rcta.customer_trx_id 
         and aaa.cash_receipt_id=acr.cash_receipt_id(+) 
         and rcta.status_trx like 'OP' 
         and rcta.CUST_TRX_TYPE_ID=rctta.CUST_TRX_TYPE_ID 
         and apsa.CUSTOMER_TRX_ID=rcta.CUSTOMER_TRX_ID 
         and TO_NUMBER(apsa.AMOUNT_DUE_REMAINING) >0 
         --and hp.party_id=papf.party_id(+) 
         and jrs.salesrep_id = ooha.SALESREP_ID 
         and jrs.ORG_ID = ooha.ORG_ID 
         and jrs.PERSON_ID = papf.PERSON_ID(+) 
) a, 
(
select 
b.order_number, 
sum(b.AMOUNT_APPLIED) unapplied_amt 
from 
         (select distinct to_char(ooha.order_number) order_number,ara.* from 
         oe_order_headers_all ooha, 
         oe_payments oe, 
         ar_receivable_applications_all ara 
where     1=1--ooha.order_number = :p_order_num 
         and oe.header_id=ooha.header_id 
         and ara.PAYMENT_SET_ID=oe.PAYMENT_SET_ID 
         and ara.DISPLAY='Y' 
         and (ara.STATUS like 'OTHER ACC' or ara.STATUS like 'UNAPP') --or ara.STATUS like 'ACC') 
         ) b 
group by b.order_number 
) adv 
where      adv.order_number(+)=a.order_number 
group by     a.account_number, 
          a.party_id, 
          a.TRX_NUMBER, 
          a.trx_date, 
          a.order_number, 
          adv.unapplied_amt, 
          a.Finance, 
          a.customer_name,a.PARTY_NAME, 
          a.customer_number,a.contact_number, 
          a.name, 
          a.Aging, 
          a.transaction_type, 
          a.exec_name, 
          a.team_leader 
order by a.Aging desc