Ошибочный ORA-01427: однострочный подзапрос возвращает более одной строки - PullRequest
0 голосов
/ 27 сентября 2010

Я получаю ошибку [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? Я не знаю, как еще отладить эту проблему.

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

РЕДАКТИРОВАТЬ : Вот действительно странная вещь. LEDGER_VIEW, как я уже сказал, построен поверх другого представления. В качестве теста я скопировал SQL вложенного представления непосредственно в SQL SQL LEDGER_VIEW вместо вложенного представления, и он вернулся без ошибок (как и ожидалось). Это, кажется, подтверждает мне, что есть некоторое ошибочное поведение либо с вложенными представлениями, либо с комбинацией вложенных представлений + ссылок на базы данных.

Ответы [ 5 ]

4 голосов
/ 27 сентября 2010

Ваш подзапрос возвращает несколько строк. Используйте запрос ниже, чтобы узнать, какие 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
2 голосов
/ 27 сентября 2010

Я не могу воссоздать через создание стека представления. (хотя 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 года спустя, гарантировано приложение (как в БД, так и в вызывающем приложении), которое не может иметь условие, которое вызовет эту ошибку? Один оператор Rouge входит, и все ваше приложение умирает?

    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 голос
/ 27 сентября 2010

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

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

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

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

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

0 голосов
/ 05 июля 2014
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
0 голосов
/ 28 сентября 2010

Попробуйте заставить ваш подзапрос вернуть один результат, добавив 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

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

...