Форум: "Базы";
Текущий архив: 2012.01.15;
Скачать: [xml.tar.bz2];
ВнизОчередные загадки Firebird 2 Найти похожие ветки
← →
dik59 (2010-03-27 21:01) [0]Уважаемые мастера!
Кто-нибудь сталкивался с такой проблемой: запрос
Select * from dn
Where
((select val from READ_DSI(dn.doc,dn.num,99692)) not between 0 and 60)
исполняется без ошибок, результат выдается правильный, а запрос
Select * from dn
Where
((select val from READ_DSI(dn.doc,dn.num,99692)) between 0 and 60)
сообщает:
Unsuccessful execution caused by an unavailable resource.
Unsupported field type specified in BETWEEN predicate.
Вся разница есть или нет "not" перед "between" !!!
Что бы это могло значить и как с этим бороться? Писать отдельно сравнение на первую границу а топом на вторую как-то топорно выглядит.
На всякий случай текст READ_DSI:
CREATE PROCEDURE READ_DSI (
doc integer,
num integer,
atr integer)
returns (
val integer)
as
begin
select val from dsi
where doc=:doc and num=:num and atr=:atr into :val;
suspend;
end
← →
sniknik © (2010-03-27 21:20) [1]> Unsuccessful execution caused by an unavailable resource.
> Unsupported field type specified in BETWEEN predicate.
вернуло значение не поддерживаемого типа, null например, или наоборот рекордсет, а можно только одиночное значение.
> Что бы это могло значить и как с этим бороться?
не знаю как это в синтаксисе Firebird, но попробуй примерно так
....
begin
select first 1 val from dsi
where doc=:doc and num=:num and atr=:atr into :val;
if val is null
begin
set val = -1
end
suspend;
end
← →
dik59 (2010-03-27 21:55) [2]Правильно ли я понял, что BETWEEN не работает со значениями null ?
← →
dik59 (2010-03-27 22:13) [3]Так я сделать не могу, поскольку процедура должна правильно возвращать null, если значения не будет найдено.
Гипотеза о том, что between не работает с null не подтвердилась проверкой.
← →
dik59 (2010-03-27 22:44) [4]Кроме того, в DSI на DOC,NUM,ATR стоит Primary_Key, так что "first 1" тут лишний
← →
dik59 (2010-03-27 23:23) [5]Поднял все записи запросом
Select
(select val from READ_DSI(dn.doc,dn.num,99692)) "val"
,dn.*
from dn
Where
((select val from READ_DSI(dn.doc,dn.num,99692)) >= 0) and
((select val from READ_DSI(dn.doc,dn.num,99692)) <= 60)
который является полным логическим аналогом неработающего запроса (см.первый пост) и убедился, что всеVAL
имеют значение неnull
← →
sniknik © (2010-03-27 23:32) [6]> Правильно ли я понял, что BETWEEN не работает со значениями null ?
кто ж его знает как там у вас в Firebird-е (в mssql работает), но ошибка именно о не поддерживаемом типе, а что еще может возвращать твоя процедура неверного?
> Гипотеза о том, что between не работает с null не подтвердилась проверкой.
явно заданное null (выражение с которым на этапе компиляции вычисляется) проверял или возвращаемое процедурой?
> Кроме того, в DSI на DOC,NUM,ATR стоит Primary_Key, так что "first 1" тут лишний
позновато про Primary_Key, это надо было в первом посте, тогда в ответе было бы только одно действие...
а вообще довольно глупая реализация с процедурой в одно действие... легко обойтись без нее простым запросом на объединение.
← →
sniknik © (2010-03-27 23:36) [7]> который является полным логическим аналогом неработающего запроса (см.первый пост) и убедился, что все VAL имеют значение не null
для проверки нужен не аналог, а те значения которые у тебя в нем отсеиваются условием.
т.е. убери условие вообще, есть хоть один null?
← →
sniknik © (2010-03-28 00:02) [8]> легко обойтись без нее простым запросом на объединение.
SELECT dn.* FROM dn
INNER JOIN dsi ON dn.doc=dsi.doc AND dn.num=dsi.num
WHERE dsi.atr=99692 AND dsi.val between 0 and 60
делов то. и работать это будет быстрее чем с процедурой.
← →
dik59 (2010-03-28 12:56) [9]Запрос
Select dn.* from dn
Where dn.doc=350
and exists (select val from READ_DSI(dn.doc,dn.num,353))
выдал 16 записей. Во всех записяхval <> null
. Значения val в пределах от 1 до 23.
ЗапросSelect dn.* from dn
Where dn.doc=350
and not exists (select val from READ_DSI(dn.doc,dn.num,353))
не выдал ни одной записи.
Т.е. данные корректны.
Запрос
Select dn.* from dn
Where dn.doc=350
and ((select val from READ_DSI(dn.doc,dn.num,353)) between 0 and 60)
опять выдал глюкUnsuccessful execution caused by an unavailable resource.
Unsupported field type specified in BETWEEN predicate
а запросSelect dn.* from dn
Where dn.doc=350
and ((select val from READ_DSI(dn.doc,dn.num,353)) not between 0 and 60)
проработал нормально, выдав пустую таблицу. ЗапросSelect dn.* from dn
Where dn.doc=350
and ((select val from READ_DSI(dn.doc,dn.num,353)) not between 0 and 2)
проработал нормально, выдав таблицу из 10 записей.
Если же заменитьbetween
на условие по двум границам, все запросы проходят на ура и работают правильно.
Таким образом, похоже, что это глюк FireBird, связанный с неправильной работой оператораbetween
Что касается очевидного упрощения кода, то тут не все так просто, поскольку это лишь кусочек большого проекта, в котором запросы динамически формируются, типы поднимаемых полей заранее не известны и призодится писать группу процедур с похожими именами для поднятия данных разных типов (в том числе и нестандартных) из разных таблиц с помощью специального конструктора запроса.
← →
Виталий Панасенко(дом) (2010-03-28 13:40) [10]http://tracker.firebirdsql.org/browse/CORE-1095
← →
Виталий Панасенко(дом) (2010-03-28 13:48) [11]Оттуда же
View that uses select expressions from selectable stored procedure fails to execute with error:
Unsuccessful execution caused by an unavailable resource.
Unsupported field type specified in BETWEEN predicate.
for select from view that uses BETWEEN predicate applied to select expression. See attached script for reproducible test case.
It executes correctly when equivalent construct X >= val1 and X <= val2 is used.
← →
sniknik © (2010-03-28 13:57) [12]> Т.е. данные корректны.
проверять нужно не итоговые данные, а те которые были в условии до получения этих корректных данных.
непонятно?
сравниваем "0" = 0 → неверный тип, 0 = 1 → правильное условие но не подходящее. тебе говорят что у тебя в условиях бывают с неверным типом, а ты проверив другим способом говоришь, вот у меня же значения 0 и оно корректно!
и кучу примеров одного и того же условия разными способами приводишь, а просили тебя проверить вообще без условий....
> т.е. убери условие вообще, есть хоть один null?
вот этот запрос, без условийSelect (select val from READ_DSI(dn.doc,dn.num,99692)) "val"
from dn
← →
sniknik © (2010-03-28 14:00) [13]Виталий Панасенко(дом) (28.03.10 13:48) [11]
> It executes correctly when equivalent construct X >= val1 and X <= val2 is used.
тогда ему придется вызывать процедуру 2 раза...
тогда уж лучше проверить работоспособность такогоWhere not ((select val from READ_DSI(dn.doc,dn.num,99692)) not between 0 and 60)
← →
sniknik © (2010-03-28 14:04) [14]> а просили тебя проверить вообще без условий....
чтобы получить все значения которые попадут на вход тому условию которое не справляется, и посмотреть есть ли среди них не валидные.
← →
dik59 (2010-03-28 15:44) [15][13] тогда уж лучше проверить работоспособность такого
Where not ((select val from READ_DSI(dn.doc,dn.num,99692)) not between 0 and 60)
Пробовал, тот же глюк. Двойное отрицание, по-видимому, оптимизируется до отсутствия отрицаний.
[14] а просили тебя проверить вообще без условий....
чтобы получить все значения которые попадут на вход тому условию
которое не справляется, и посмотреть есть ли среди них не валидные.
запросSelect (select val from READ_DSI(dn.doc,dn.num,99692)) "val"
from dn
вернул 15802 пустых записей и 16 записей с правильными данными. Получается, что дляbetween
значениеnull
недопустимо, а дляnot between
допустимо. Что странно, но представимо.
Однако сделал еще следующие проверки.
ЗапросSelect
(select val from READ_DSI(dn.doc,dn.num,353)) "val"
,dn.* from dn
Where dn.doc=350
вернул 16 записей, все значенияval
неnull
из перечня (0,1,3)
ЗапросSelect
(select val from READ_DSI(dn.doc,dn.num,353)) "val"
,dn.* from dn
Where dn.doc=350
and ((select val from READ_DSI(dn.doc,dn.num,353)) between 0 and 1)
породил уже упомянутый глюк!
Так что либо гипотеза о недопуастимостиnull
должна быть отвергнута, либо среда FireBird второе условие исполняет раньше первого, что странно, поскольку наdoc
вdn
имеется индекс.
← →
sniknik © (2010-03-28 16:08) [16]> породил уже упомянутый глюк!
естественно, т.к. при and, проверяются все условия, должно совпадать и то и то. а если or, то достаточно первого при true и все одно "свалится" при false.
> Так что либо гипотеза о недопуастимости null должна быть отвергнута
остается в силе...
вот так "сработает"...
Where dn.doc<>350
and ((select val from READ_DSI(dn.doc,dn.num,353)) between 0 and 1)
т.к. тут первое будет false и дальнейшая проверка необязательна при "неправильных" вторых значеняих, и true и обязательна при "правильных".
p.s.
единственное показательное было бы проверить изменив процедуру так как показано в [1]. но ты как то странно обходишь все правильные проверки, и делаешь выводы по ничего не значащим тестам (проверяющим "рядом").
← →
sniknik © (2010-03-28 16:17) [17]> вот так "сработает"
хотя, может и не сработать. порядок выполнения условий определяется, насколько помню, самим сервером.
← →
dik59 (2010-03-28 16:28) [18][16] p.s.
единственное показательное было бы проверить изменив процедуру так как показано в [1]
Вdsi
могут быть любые численные значения, в том числе и -1, поэтому и нельзя переделывать процедуру.
Всем спасибо, помогли.
← →
sniknik © (2010-03-28 16:37) [19]> поэтому и нельзя переделывать процедуру.
значит нельзя проверить... странно.
← →
sniknik © (2010-03-28 16:38) [20]а другую написать, и проверить с ней тоже нельзя? еще более странно.
← →
dik59 (2010-03-28 17:20) [21][20] а другую написать, и проверить с ней тоже нельзя? еще более странно.
Проверил, написал. Результат обхохочешься:
ваш запросSelect (select val from READ_DSI(dn.doc,dn.num,99692)) "val"
from dn
вернул вернул 15802 записей со значением val = -1 и 16 записей с правильными данными.
а запросSelect * from dn
Where
((select val from READ_DSI(dn.doc,dn.num,99692)) between 0 and 60)
ОПЯТЬ выдал тот же глюк, что и раньше (хотя "невалидного" null не получал).
Отсюда вывод: все-таки глючит FireBird. Кроме того, в стандарте и реализациях SQL (по Кевину Клайну) вроде бы нет упоминания о невалидности значенияnull
для between, там только говорится, что если хотя бы одна из границnull
, то результат сравнения будетnull
, что, вообще говоря, не должно мешать исполнению запроса, как не мешает исполнению запроса значениеnull
в простом сравнении (напримерval > 2
)
Еще раз всем спасибо.
← →
Виталий Панасенко(дом) (2010-03-28 17:52) [22]
> Виталий Панасенко(дом) (28.03.10 13:48) [11]
>
> Оттуда же
> View that uses select expressions from selectable stored
> procedure fails to execute with error:
> Unsuccessful execution caused by an unavailable resource.
>
> Unsupported field type specified in BETWEEN predicate.
>
> for select from view that uses BETWEEN predicate applied
> to select expression. See attached script for reproducible
> test case.
> It executes correctly when equivalent construct X >= val1
> and X <= val2 is used.
>
Это известный баг оптимизатора.. см.
> Виталий Панасенко(дом) (28.03.10 13:40) [10]
>
> http://tracker.firebirdsql.org/browse/CORE-1095
← →
dik59 (2010-03-28 18:26) [23][22] Это известный баг
Да, спасибо, я понял. Жаль только что разработчикам FireBird этот баг неизвестен.
Сейчас пытался выйти на форум их сайта, но понял, что без бутылки это не судьба. Слишком умные (для меня).
← →
dik59 (2010-03-28 18:36) [24]P.S. может быть кто-то сможет отправить им эту страничку для ознакомления?
← →
Виталий Панасенко(дом) (2010-03-28 19:43) [25]
> dik59 (28.03.10 18:26) [23]
>
> [22] Это известный баг
>
> Да, спасибо, я понял. Жаль только что разработчикам FireBird
> этот баг неизвестен.
Баг известен, я ж на треккер ошибок FireBird ссылку дал
> http://tracker.firebirdsql.org/browse/CORE-1095
.. Но не исправлен, это другое дело...
Страницы: 1 вся ветка
Форум: "Базы";
Текущий архив: 2012.01.15;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.003 c