|
17.02.2011, 10:41 | #1 |
Участник
|
Аксапта ограничивает размер строки-маски в операторе like размером фильтруемого поля
Обнаружил сейчас неприятную особенность оператора like. Заключается она в следующем.
Допустим в таблице есть поле длиной 10 символов. В нём хранится значение занимающее полностью весь столбец, т.е. тоже длиной в 10 символов. Допустим это "ABC0123456". Если попытаться отфильтровать его по условию like "*ABC0123456", то в результате получим пустую выборку. Потому что, на самом деле маска длиной 11 символов обрезается справа до длины поля, т.е до 10. В результате маска превращается в "*ABC012345".И если в таблице будут записи удовлетворяющие этому обрезанному критерию, то они выберутся. Если в маску добавить две звёздочки, то соответственно справа обрежутся уже два символа. В начале я подумал, что это Аксаптовские проделки, но поэкспериментировав на SQL сервере обнаружил что проблема глубже. Скорее всего для внутреннего представления значения маски SQL Server использует тот же самый тип данных, что и у поля, по которому происходит фильтрация. В случае временных таблиц, работу с которыми аксапта реализует самостоятельно, всё работает корректно. |
|
17.02.2011, 12:12 | #2 |
Участник
|
Версия Аксапты, версия сиквела ?
|
|
17.02.2011, 12:41 | #3 |
Участник
|
А Вы не записываете маску в переменную? Может, проблема с типом данных той переменной, в которую записали маску?
X++: str 3 testVar = "1234"; ; print testVar; pause; |
|
17.02.2011, 13:07 | #4 |
Участник
|
AX2009 SP1
SQL Server 2008 R2 X++: static void JobTestLike20110217(Args _args) { // TableTestLike.Field1 StringSize 10 TableTestLike TableTestLike; Range mask = '*ABC0123456'; ; delete_from TableTestLike; TableTestLike.clear(); TableTestLike.Field1 = 'ABC0123456'; TableTestLike.insert(); TableTestLike.clear(); TableTestLike.Field1 = 'ABC012345'; TableTestLike.insert(); info(strfmt('mask: %1', mask)); while select TableTestLike where TableTestLike.Field1 like mask { info(TableTestLike.Field1); } } |
|
17.02.2011, 13:30 | #5 |
Мрачный тип
|
Мда ...
Явно не в переменной дело, да и не в сервере очень даже может быть. Вариант того, что особо "одаренное" ядро может обрезать строку ограничения до размерности поля в репозитарии, выдавая такого "кастрата" на сервер, рассматривался ? "Кастрат", я так понимаю, обнаружился при трассировке переданного системой запроса ?
__________________
Мы летаем, кружимся, нагоняем ужасы ... Последний раз редактировалось TasmanianDevil; 17.02.2011 в 13:32. |
|
17.02.2011, 13:43 | #6 |
Участник
|
В том то и дело что результат выполнения такого запроса в SQL Server Management Studio точно такой же. Т.е. ошибка не в аксапте а в СУБД
|
|
17.02.2011, 13:57 | #7 |
Участник
|
Цитата:
Код: select * from TableTestLike where TableTestLike.Field1 like '%ABC0123456' Microsoft SQL Server 2005 - 9.00.4285.00 (Intel IA-64) Feb 8 2010 23:35:42 Copyright (c) 1988-2005 Microsoft Corporation Standard Edition (64-bit) on Windows NT 5.2 (Build 3790: Service Pack 2) ---------------------- Даже с учетом того, что MS SQL выполняет не прямой запрос, в фетчит курсор, все-равно все в порядке Код: DECLARE @Field1 varchar(10) DECLARE cursor1 CURSOR FOR SELECT Field1 FROM TableTestLike where Field1 like '%ABC0123456' OPEN cursor1 FETCH NEXT FROM cursor1 into @Field1 WHILE @@FETCH_STATUS = 0 BEGIN select 'cursor1', @Field1 FETCH NEXT FROM cursor1 into @Field1 ; END; CLOSE cursor1 DEALLOCATE cursor1 Последний раз редактировалось Владимир Максимов; 17.02.2011 в 14:02. |
|
|
За это сообщение автора поблагодарили: S.Kuskov (2). |
17.02.2011, 13:53 | #8 |
Участник
|
Профайлер SQL-сервера показывает, что на сервер попадает уже обрезанное значение. Т.е. действительно это ошибка ядра Axapta. И действительно искомое значение обрезается до размерности поля в репозитарии
Например, для следующего запроса профайлер SQL-сервера показывает, что в качестве параметра передается только первые 10 символов константы X++: while select TableTestLike where TableTestLike.Field1 == 'ABC0123456890123456789' { info(TableTestLike.Field1); } |
|
17.02.2011, 13:55 | #9 |
Участник
|
Можно обойтись без профайлера SQL, ограничившись штатной трассировкой запросов, если в запросе использовать hint forceliterals. Хотя в запросе с литералами и без них может получиться разное значение маски
|
|
17.02.2011, 14:25 | #10 |
Участник
|
Цитата:
X++: while select forceLiterals TableTestLike where TableTestLike.Field1 like mask { info(TableTestLike.Field1); } X++: while select forceLiterals TableTestLike where TableTestLike.Field1 like '*ABC0123456' { info(TableTestLike.Field1); } Код: SELECT * FROM TableTestLike WHERE (Field1 like '\%ABC0123456' ESCAPE '\' ) |
|
17.02.2011, 14:05 | #11 |
Участник
|
Что же делать ?
QueryRun нас спасет ? |
|
17.02.2011, 14:10 | #12 |
Участник
|
Да на SQL Server я зря наговаривал (видимо я в попыхах перепутал процент со звёздочкой), там всё в порядке, чего не скажешь про аксапту
Неа X++: static void JobTestLike20110217(Args _args) { // TableTestLike.Field1 StringSize 10 Query Query; QueryRun QueryRun; TableTestLike TableTestLike; Range mask = '*ABC0123456'; ; delete_from TableTestLike; TableTestLike.clear(); TableTestLike.Field1 = 'ABC0123456'; TableTestLike.insert(); TableTestLike.clear(); TableTestLike.Field1 = 'ABC012345'; TableTestLike.insert(); info(strfmt('mask: %1', mask)); while select TableTestLike where TableTestLike.Field1 like mask { info(TableTestLike.Field1); } Query = new Query(); Query.addDataSource(tablenum(TableTestLike)).addRange(fieldNum(TableTestLike, Field1)).value(mask); QueryRun = new QueryRun(Query); while(QueryRun.next()) { TableTestLike = QueryRun.get(tablenum(TableTestLike)); info(TableTestLike.Field1); } } |
|
17.02.2011, 16:04 | #13 |
Участник
|
Просьба модераторов изменить заголовок темы
|
|
17.02.2011, 16:31 | #14 |
Administrator
|
Сделано
__________________
Возможно сделать все. Вопрос времени |
|
Теги |
like, баг |
|
|