Перевод multiple rows in singleton select
Уважаемые мастера!
У меня есть хранимая процедура для IB 6.0.
Я ее отлаживаю через IB Expert. Во время отладки (Step over)
она все свои значения в раздел Results отладчика выводит правильно.
Но при запуске процедуры(Run) через IB Expert или Delphi выдает ошибку:
multiple rows in singleton select.
Что тут может быть?
Если хотите могу привести исходный код.
← →
Senator ( 2003-03-20 11:30 ) [1]
← →
Fareader ( 2003-03-20 11:31 ) [2]
Исхоный код конечно привести желательно, но тут и так понятно — когда возвращаешь запись ставь Suspend и все как рукой снимет 🙂
← →
zacho ( 2003-03-20 11:33 ) [3]
Приводи код.
А вообще такая ошибка означает, что выбирается несколько записей, там, где должна быть одна. Например, какой-нибудь SELECT .. FROM . INTO . возвращает больше одной записи
← →
Jaxtor ( 2003-03-20 11:33 ) [4]
CREATE PROCEDURE SNAKL_PROC (
NAKLID INTEGER)
RETURNS (
PN VARCHAR(63),
PRODUCT VARCHAR(255),
COUNTRYNAME INTEGER,
GTD VARCHAR(32),
SN VARCHAR(32),
QUANT INTEGER,
WARRANTY INTEGER,
PR$ DOUBLE PRECISION,
NAKLID_VAR INTEGER)
AS
begin
for select saveprod.pn,saveprod.product,savepr_atr.countryid,savepr_atr.gtd, SerialNo.serialno,stockitem.quantity,naklitem.warantyid, naklitem.naklitemid from saveprod,savepr_atr,serialNo,stockitem,naklitem
where (Savepr_atr.saveprodid=saveprod.saveprodid) and (SerialNo.saveprod_atrid=savepr_atr.saveprod_atrid) and (Stockitem.saveprod_atrid=savepr_atr.saveprod_atrid)
and (NaklItem.saveprod_atrid=Savepr_atr.saveprod_atrid) and (NaklId=:NaklID) into PN, Product, CountryName, GTD,sn,quant,warranty, NAKLID_VAR
do
begin
select NaklSum.sum_value from NaklSum,NaklItem where (NaklSum.naklitemid=:NAKLID_VAR) and (NaklSum.sumid=1) into :PR$;
suspend;
end
zacho> Но ведь через отладчик все работает!
← →
Соловьев ( 2003-03-20 11:37 ) [6]
возможно ты передаешь параметр который NULL .
← →
Jaxtor ( 2003-03-20 11:39 ) [7]
Просто я не понимаю: через отладчик все работает, он выдает правильный набор данных, а через Run не получается.
← →
Fareader ( 2003-03-20 11:40 ) [8]
Я что-то не пойму — ты объвил кучу переменных, а возвращаешь только одну — :PR$ зачем остальные? Надо делать так:
for select saveprod.pn,saveprod.product,savepr_atr.countryid,savepr_atr.gtd, SerialNo.serialno,stockitem.quantity,naklitem.warantyid, naklitem.naklitemid from saveprod,savepr_atr,serialNo,stockitem,naklitem
where (Savepr_atr.saveprodid=saveprod.saveprodid) and (SerialNo.saveprod_atrid=savepr_atr.saveprod_atrid) and (Stockitem.saveprod_atrid=savepr_atr.saveprod_atrid)
and (NaklItem.saveprod_atrid=Savepr_atr.saveprod_atrid) and (NaklId=:NaklID) into PN, Product, CountryName, GTD,sn,quant,warranty, NAKLID_VAR
suspend;
do
begin
select NaklSum.sum_value from NaklSum,NaklItem where (NaklSum.naklitemid=:NAKLID_VAR) and (NaklSum.sumid=1) into :PR$;
suspend;
end
← →
Соловьев ( 2003-03-20 11:41 ) [9]
я тоже когда-то на это напоролся, тоже в отладчике смотрел все нормально, как только так запускаешь, так сразу ошибка. Вроде тогда решил эту проблему, приведением входного параметра к типу.
> Jaxtor © (20.03.03 11:35)
> zacho> Но ведь через отладчик все работает!
Отладчик не есть IB :), мало ли что через него работает 🙂
Посмотрел твой код, вроде все правильно, но подозреваю, что неправильно связываются таблицы. Попробуй переделать через явный JOIN или явно указывай алиасы таблиц во FROM. Кстати, точно не помню, но вроде бы в какой-то версии IB был баг, проявляющийся если в запросе алиас таблицы совпадал с ее названием.
← →
zacho ( 2003-03-20 11:43 ) [11]
← →
Jaxtor ( 2003-03-20 11:44 ) [12]
>Fareader
>GTD,sn,quant,warranty, NAKLID_VAR
>suspend;
>do
А где do перед suspend?
← →
Соловьев ( 2003-03-20 11:45 ) [13]
параметра того который работает в теле цыкла.
← →
Fareader ( 2003-03-20 11:46 ) [14]
Хотя изначально ХП неправильно спроектирована, может так:
for select saveprod.pn,saveprod.product,savepr_atr.countryid,savepr_atr.gtd,SerialNo.serialno,stockitem.quantity,naklitem.warantyid, naklitem.naklitemid
from saveprod, savepr_atr, serialNo, stockitem, naklitem
where
(Savepr_atr.saveprodid=saveprod.saveprodid) and (SerialNo.saveprod_atrid=savepr_atr.saveprod_atrid) and (Stockitem.saveprod_atrid=savepr_atr.saveprod_atrid) and (NaklItem.saveprod_atrid=Savepr_atr.saveprod_atrid) and (NaklId=:NaklID)
(NaklSum.naklitemid=naklitem.naklitemid) and (NaklSum.sumid=1)
into PN, Product, CountryName, GTD,sn,quant,warranty, NAKLID_VAR, PR$;
do
suspend;
Так пожалуй правильнее
Вот немножко изменил код, чтобы проблема была яснее, что мне
нужно сделать:
CREATE PROCEDURE SNAKL_PROC (
NAKLID INTEGER)
RETURNS (
PN VARCHAR(63),
PRODUCT VARCHAR(255),
COUNTRYNAME INTEGER,
GTD VARCHAR(32),
SN VARCHAR(32),
QUANT INTEGER,
WARRANTY INTEGER,
PR$ DOUBLE PRECISION,
PRR DOUBLE PRECISION,
NAKLID_VAR INTEGER)
AS
begin
for select sp.pn,sp.product,satr.countryid,satr.gtd, srn.serialno,si.quantity,ni.warantyid, ni.naklitemid from saveprod sp,savepr_atr satr,serialNo srn,stockitem si,naklitem ni
where (satr.saveprodid=sp.saveprodid) and (srn.saveprod_atrid=satr.saveprod_atrid) and (si.saveprod_atrid=satr.saveprod_atrid)
and (Ni.saveprod_atrid=Satr.saveprod_atrid) and (NaklId=:NaklID) into PN, Product, CountryName, GTD,sn,quant,warranty, NAKLID_VAR
do
begin
select ns.sum_value from NaklSum ns,NaklItem ni where (ns.naklitemid=:NAKLID_VAR) and (ns.sumid=1) into :PR$;
select ns.sum_value from NaklSum ns,NaklItem ni where (ns.naklitemid=:NAKLID_VAR) and (ns.sumid=11) into :PRR;
suspend;
end
Стал использовать псевдонимы.
Ведь если логически рассуждать, у меня все должно работать.
А получается наоборот.
← →
Соловьев ( 2003-03-20 12:43 ) [16]
> select ns.sum_value from NaklSum ns,NaklItem ni where (ns.naklitemid=:NAKLID_VAR)
> and (ns.sumid=1) into :PR$;
> select ns.sum_value from NaklSum ns,NaklItem ni where (ns.naklitemid=:NAKLID_VAR)
> and (ns.sumid=11) into :PRR;
:NAKLID_VAR точно не NULL .
← →
Jaxtor ( 2003-03-20 12:48 ) [17]
У NAKLID_VAR не бывает значения NULL.
← →
zacho ( 2003-03-20 12:51 ) [18]
Все-таки похоже, что в одной из связываемых таблиц у тебя находяться несколько записей, удовлетворяющих условию, вместо одной. Надеюсь, связываешь по PK или UNIQUE ?
← →
Jaxtor ( 2003-03-20 12:54 ) [19]
Название у PK содержит буквы id, например, NAKLID.
← →
zacho ( 2003-03-20 13:01 ) [20]
> select ns.sum_value from NaklSum ns,NaklItem ni where (ns.naklitemid=:NAKLID_VAR)
> and (ns.sumid=1) into :PR$;
> select ns.sum_value from NaklSum ns,NaklItem ni where (ns.naklitemid=:NAKLID_VAR)
> and (ns.sumid=11) into :PRR;
Похоже, что дело в одном из этих двух select»ов. Проверь, действительно ли они возвращают только одну запись. И еще, непонятно зачем в этих запросах NaklItem ni, имхо, нафиг не нужно, в WHERE все равно не участвует
Только запрос типа
select MAX(ns.sum_value) from .
или
select SUM(ns.sum_value) from .
обязательно вернёт ОДНУ запись, твои же запросы ориентируются на то, что запись ДОЛЖНА БЫТЬ одна, но НЕ ОБЯЗАНА, если нет уникального ключа по полям (naklitemid, sumid)
Кстати, а что мешает составить запрос, м посмотреть, нет ли таких строк?
← →
zacho ( 2003-03-21 10:26 ) [22]
> zacho © (20.03.03 11:42)
>
> Посмотрел твой код, вроде все правильно
Че-то я вчера долго тормозил .. 🙁
Блин, сразу надо было заметить, что запрос
select ns.sum_value from NaklSum ns,NaklItem ni where (ns.naklitemid=:NAKLID_VAR) and (ns.sumid=1) into :PR$;
вернет столько записей, сколько в таблице NaklItem.
Вот отсюда и ошибка
← →
PAV ( 2003-03-21 19:24 ) [23]
Однозначно, хранимая процедура возвращает больше одной записи вместо одной. Выход либо в правке текста процедуры, либо в «правильности данных».
Перевод multiple rows in singleton select
Alex |
| ||||||||||||
Эксперт Профиль Репутация: 17 Очевидно что данная ошибка происходит в вашем триггере или хранимой процедуре. Обычный SELECT внутри триггера или процедуры должен возвращать одну строку (row), т.к. при двух и более строках IB не знает куда поместить значения полей этих строк. Если ваш SELECT возвращает несколько записей, то нужно пользоваться конструкцией FOR SELECT . INTO . DO . которая производит обработку возвращаемого набора записей в цикле. Если-же вы уверены, что ваш SELECT должен вернуть только одну запись, а ошибка все-таки возникает, то давайте рассмотрим следующую ситуацию: существуют таблицы ORDERS (заказы) и CLIENTS (клиенты). где ? — либо значение либо переменная. Теперь представим себе, что этот запрос должен выполняться в триггере при вставке записи в таблицу ORDERS
Итак, поскольку в запросе использован псевдоним C (FROM CLIENTS C), то якобы существует гарантия что в предложении WHERE будут сравниваться поле C.CLIENT_ID из таблицы CLIENTS и поле CLIENT_ID из таблицы ORDERS (в триггере доступны имена полей собственной таблицы). На самом деле даже использование псевдонимов не дает гарантии что переменные будут разичаться, и получается что в предложении WHERE сравнивается само с собой поле таблицы CLIENTS.CLIENT_ID, и в запросе возвращается ВСЯ таблица CLIENTS. Вот почему возникает вышеупомянутое сообщение об ошибке. Избавиться от него можно несколькими путями: Использовать разные имена полей для связи между CLIENTS и ORDERS. например OCLIENT_ID и CCLIENT_ID.
Перед запросом поместить CLIENT_ID в локальную переменную, и в запросе использовать сравнение не с полем, а с этой локальной переменной.
Borland Interbase / Firebird FAQ
|