Перевод multiple rows in singleton select

Перевод 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
Дата 13.11.2004, 15:41 (ссылка) | (нет голосов) Загрузка .

Эксперт

Профиль
Группа: Экс. модератор
Сообщений: 4147
Регистрация: 25.3.2002
Где: Москва

Репутация: 17
Всего: 162

Очевидно что данная ошибка происходит в вашем триггере или хранимой процедуре. Обычный SELECT внутри триггера или процедуры должен возвращать одну строку (row), т.к. при двух и более строках IB не знает куда поместить значения полей этих строк. Если ваш SELECT возвращает несколько записей, то нужно пользоваться конструкцией FOR SELECT . INTO . DO . которая производит обработку возвращаемого набора записей в цикле.

Если-же вы уверены, что ваш SELECT должен вернуть только одну запись, а ошибка все-таки возникает, то давайте рассмотрим следующую ситуацию:

существуют таблицы ORDERS (заказы) и CLIENTS (клиенты).
обе эти таблицы имеют поле связи CLIENT_ID INTEGER.
для того чтобы вытащить информацию о клиенте используется запрос:

где ? — либо значение либо переменная.

Теперь представим себе, что этот запрос должен выполняться в триггере при вставке записи в таблицу ORDERS

Код
CREATE TRIGGER TI_ORDERS FOR ORDERS
ACTIVE AFTER INSERT POSITION 0
AS
DECLARE VARIABLE CID INTEGER;
DECLARE VARIABLE CNAME CHAR(30);
BEGIN
SELECT C.CLIENT_ID, C.CLIENT_NAME
FROM CLIENTS C
WHERE C.CLIENT_ID = CLIENT_ID
INTO :CID, :CNAME;
.

Итак, поскольку в запросе использован псевдоним C (FROM CLIENTS C), то якобы существует гарантия что в предложении WHERE будут сравниваться поле C.CLIENT_ID из таблицы CLIENTS и поле CLIENT_ID из таблицы ORDERS (в триггере доступны имена полей собственной таблицы). На самом деле даже использование псевдонимов не дает гарантии что переменные будут разичаться, и получается что в предложении WHERE сравнивается само с собой поле таблицы CLIENTS.CLIENT_ID, и в запросе возвращается ВСЯ таблица CLIENTS.

Вот почему возникает вышеупомянутое сообщение об ошибке.

Избавиться от него можно несколькими путями:

Использовать разные имена полей для связи между CLIENTS и ORDERS. например OCLIENT_ID и CCLIENT_ID.
Использовать уточнитель new.CLIENT_ID, несмотря на то что в документации указано что для триггеров последействия (AFTER) он не имеет смысла.

Код
SELECT C.CLIENT_ID, C.CLIENT_NAME
FROM CLIENTS C
WHERE C.CLIENT_ID = new.CLIENT_ID
.

Перед запросом поместить CLIENT_ID в локальную переменную, и в запросе использовать сравнение не с полем, а с этой локальной переменной.

Код
CID=CLIENT_ID;
SELECT C.CLIENT_ID, C.CLIENT_NAME
FROM CLIENTS C
WHERE C.CLIENT_ID = :CID
.

Borland Interbase / Firebird FAQ
Borland Interbase / Firebird Q&A, версия 2.02 от 31 мая 1999
последняя редакция от 17 ноября 1999 года.
Часто задаваемые вопросы и ответы по Borland Interbase / Firebird
Материал подготовлен в Демо-центре клиент-серверных технологий. (Epsylon Technologies)
Материал не является официальной информацией компании Borland.
E-mail mailto:[email protected]
www: http://www.ibase.ru/
Телефоны: 953-13-34
источники: Borland International, Борланд АО, релиз Interbase 4.0, 4.1, 4.2, 5.0, 5.1, 5.5, 5.6, различные источники на WWW-серверах, текущая переписка, московский семинар по Delphi и конференции, листсервер ESUNIX1, листсервер mers.com.
Cоставитель: Дмитрий Кузьменко

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

1. Базы данных (Paradox, Oracle и т.п.)

2. Способа доступа (ADO, BDE и т.д.)

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) — крупнейшем в рунете сборнике материалов по Дельфи
  • Вопросы по SQL и вопросы по базам данных не связанные с Дельфи задавать здесь

Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Vit, Петрович.

0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Базы данных и репортинг | Следующая тема »

[ Время генерации скрипта: 0.0973 ] [ Использовано запросов: 21 ] [ GZIP включён ]

Источник

Поделиться с друзьями
admin
Оцените автора
( Пока оценок нет )
Как переводится?
Adblock
detector