Oracle 提取 returns 多于请求

Oracle fetch returns more than requested

所以我得到了另一个有错误的简单过程。这一次,提取返回的记录多于请求的记录。我最初检查了我的查询并发现了一个错误。我的查询 returns 得到了正确的结果,但提取仍然无效。 程序:

--View Customer Service History
create or replace procedure SERVICEHISTORY(name in customer.name%type) is

carModel char(11);
serviceCharge decimal(7,2);
serviceName char(20);
serviceDate date;
cusName char(15);
cusID number;



--Query tested, it works
cursor nextService is
select name, workOrder.serviceDate, workOrderServices.actualCharge
from workOrder join workOrderServices on workOrder.workOrderID=workOrderServices.workOrderID join services on workOrderServices.serviceID=services.serviceID
where workOrderServices.customerID=cusID;

begin
--Get customer ID from name, another janky work around
select customerID
into cusID
from customer
where customer.name=name;

--Gets the car model
select model
into carModel
from vehicle
where vehicle.customerID=cusID;

open nextService;
fetch nextService into serviceName, serviceDate, serviceCharge;
if nextService%notfound then
    dbms_output.put_line('No service history found.');
else
    dbms_output.put_line('Service-------Date-------Cost');
    loop
        dbms_output.put_line(serviceName||'  '||serviceDate||'  '||serviceCharge);
        fetch nextService into serviceName, serviceDate, serviceCharge;
        if nextService%notfound then
            dbms_output.put_line('Report finished.');
        end if;
    exit when nextService%notfound;
    end loop;
end if;
close nextService;
end serviceHistory;
/

但是它抛出这个错误:

ERROR: 
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at line 20
ORA-06512: at line 1

这是表格:

create table customer
    (
        customerID number(8) not null primary key constraint lengthCHK13 check(LENGTH(customerID)=8),
        name varchar2(20) not null,
        address varchar2(20) not null,
        insurance varchar2(20) not null,
        contactInfo number(10) not null,
        customerType varchar2(15) not null,
        licenseNumber varchar2(13) not null,
        amountOwed decimal(7,2) not null constraint notNeg6 check(amountOwed >=0)
    );

create table vehicle
    (
        --some error about no matching unique or primary key for this column on cusomterID
        VIN varchar2(17) not null primary key constraint lengthCHK113 check(length(VIN)=17),
        customerID number(8) not null references customer(customerID) constraint lengthCHK12 check(length(customerID)=8),
        make varchar2(10) not null,
        model varchar2(10) not null,
        carYear number(4) not null,
        color varchar2(10) not null,
        notes varchar2(20),
        currentMileage number(6) not null,
        engineType varchar2(10) not null,
        licenseNumber varchar(12) not null,
        amountOwed decimal(7,2) constraint notNeg7 check(amountOwed >=0)
        --primary key(VIN, customerID) DOESNT WORK BUT NEEDS TO
    );

create table workOrder
    (
        workOrderID number(8) not null constraint lengthCHK10 check(length(workOrderID)=8),
        VIN varchar2(17) not null references vehicle(VIN) constraint lengthCHK14 check(length(VIN)=17),
        serviceDate date not null,
        --Removing b/c it's a pain serviceTime TIME not null,
        serviceBay number(2),
        description varchar2(20) not null,
        results varchar2(20) not null,
        primary key(workOrderID)
    );

create table services
    (
        serviceID number(8) not null primary key constraint lengthCHK17 check(length(serviceID)=8),
        name varchar2(20) not null,
        price decimal(7,2) not null constraint notNeg8 check(price >=0),
        estimatedHours number(2) not null
    );

create table workOrderServices
    (
        serviceID number(8) not null references services(serviceID) constraint lengthCHK20 check(length(serviceID)=8),
        workOrderID number(8) not null references workOrder(workOrderID) constraint lengthCHK22 check(length(workOrderID)=8),
        customerID number(8) not null references customer(customerID) constraint lengthCHK87 check(length(customerID)=8),
        actualHours number(2) not null constraint notNeg11 check(actualHours >=0),
        actualCharge decimal(7,2) not null constraint notNeg10 check(actualCharge >=0),
        primary key(serviceID, workOrderID)
    );

测试数据:

INSERT INTO services(serviceID, name, price, estimatedHours)
VALUES(48937322, 'Tire Rotate', 19.99, 1);
INSERT INTO services(serviceID, name, price, estimatedHours)
VALUES(47873231, 'Xmission Flush', 63.99, 1);
INSERT INTO customer (customerID, name, address, insurance, contactInfo, customerType, licenseNumber, amountOwed)
VALUES (45124512, 'Bob Jones',  '232 Sycamore Ln.', 'Pekin', 3095555145, 'New', 'SSSSFFFYYDDD', 220.00);
INSERT INTO customer (customerID, name, address, insurance, contactinfo, customertype, licensenumber, amountOwed)
VALUES (12892222, 'Mike Tyson','100 Haters Rd.', 'Progressive', 2175555555, 'Regular', 'FGHJHHHHTYYY', 42.00);

INSERT INTO vehicle(VIN, customerID, make, model, carYear, color, notes, currentMileage, engineType, licenseNumber, amountOwed)
VALUES('KNDKG3A31A7568300', 45124512, 'Ford', 'Focus', 2009, 'Red',  'side door damage', 10346, 'V4', 'h5303h87dk23', 0);
INSERT INTO vehicle(VIN, customerID, make, model, carYear, color, notes, currentMileage, engineType, licenseNumber, amountOwed)
VALUES('SALTW16413A376838', 12892222, 'Chrysler', 'Sebring', 2004, 'Green', 'Basically a Go-Kart', 105098, 'V4', 'r2345h23tx31', 0);

INSERT INTO workOrder( workOrderID, VIN, serviceDate, serviceBay, description, results)
VALUES(12312312, 'KNDKG3A31A7568300', '07-FEB-12', 2, 'Oil Change', 'Changed oil'); 
INSERT INTO workOrder( workOrderID, VIN, serviceDate, serviceBay, description, results)
VALUES(32132132, 'SALTW16413A376838', '07-FEB-12', 3,'Tire Rotation', 'Rotated the tires');

INSERT INTO workOrderServices(serviceID, workOrderID, customerID, actualHours, actualCharge)    
VALUES(17278722, 12312312, 45124512, 5,  45.00);
INSERT INTO workOrderServices(serviceID, workOrderID, customerID,actualHours, actualCharge)
VALUES(48937322, 32132132, 12892222,10, 90.00);

如果您像我一样在代码中添加了一些额外的消息,您会很快发现错误的根源。

create or replace procedure SERVICEHISTORY(name in customer.name%type) is

carModel char(11);
serviceCharge decimal(7,2);
serviceName char(20);
serviceDate date;
cusName char(15);
cusID number;



--Query tested, it works
cursor nextService is
select name, workOrder.serviceDate, workOrderServices.actualCharge
from workOrder 
    join workOrderServices 
    on workOrder.workOrderID=workOrderServices.workOrderID 
    join services on workOrderServices.serviceID=services.serviceID
where workOrderServices.customerID=cusID;

begin
dbms_output.put_line('Get customer ID from name, another janky work around');
select customerID
into cusID
from customer
where customer.name=name;
dbms_output.put_line('cusID='||cusID);
--Gets the car model
select model
into carModel
from vehicle
where vehicle.customerID=cusID;
dbms_output.put_line('carModel='||carModel);

open nextService;
fetch nextService into serviceName, serviceDate, serviceCharge;
if nextService%notfound then
    dbms_output.put_line('No service history found.');
else
    dbms_output.put_line('Service-------Date-------Cost');
    loop
        dbms_output.put_line(serviceName||'  '||serviceDate||'  '||serviceCharge);
        fetch nextService into serviceName, serviceDate, serviceCharge;
        if nextService%notfound then
            dbms_output.put_line('Report finished.');
        end if;
    exit when nextService%notfound;
    end loop;
end if;
close nextService;
end serviceHistory;
/

这是我的输出:

SQL> exec SERVICEHISTORY(name=>'Bob Jones')
Get customer ID from name, another janky work around
BEGIN SERVICEHISTORY(name=>'Bob Jones'); END;

*
ERROR at line 1:
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "APC.SERVICEHISTORY", line 23
ORA-06512: at line 1

这是抛出的第一个查询。为什么要这样做?因为您已为参数指定了与列相同的名称。在 PL/SQL 中,变量命名具有作用域,最近的声明胜过更远的声明。

所以在您的查询中...

select customerID
into cusID
from customer
where customer.name=name;

...Oracle 将右侧的 name 解释为 table、 的列,因为这是最窄的范围 。实际上,您的过滤器是 where 1=1,根本就不是过滤器。

解决此问题所需要做的就是将参数更改为 p_name 之类的参数,然后在查询中使用它...

SQL> exec SERVICEHISTORY(p_name=>'Mike Tyson')
Get customer ID from name, another janky work around
cusID=12892222
carModel=Sebring
Service-------Date-------Cost
Tire Rotate           07-FEB-12  90
Report finished.

PL/SQL procedure successfully completed.

SQL> 

当然,如果您的客户拥有多辆汽车(数据模型支持),您将从 VEHICLE 查询中得到相同的错误。

目前您不使用该查询的结果,因此最简单的解决方法是将其删除。但可能您想将其包含在输出中,因此最好的解决方案可能是在主查询中包含 VEHICLE。