Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 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 &#8594; неверный тип, 0 = 1 &#8594; правильное условие но не подходящее. тебе говорят что у тебя в условиях бывают с неверным типом, а ты проверив другим способом говоришь, вот у меня же значения 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
1-1279183953
TKN
2010-07-15 12:52
2012.01.15
QuickReport - вывести в файл


15-1316555083
Джо
2011-09-21 01:44
2012.01.15
Сша, психоделик, 60-е.


2-1318095947
Pcrepair
2011-10-08 21:45
2012.01.15
Ctrl+A и Ctrl+C в компоненте TWebBrowser


15-1317550613
Loginov Dmitry
2011-10-02 14:16
2012.01.15
Indy - работа с электронной почтой


1-1279883255
killy
2010-07-23 15:07
2012.01.15
Variant как ссылка на OLE-объект





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский