Странное ограничение длины с оператором DB2 LIKE - PullRequest
4 голосов
/ 10 февраля 2012

Я обнаружил забавную проблему с DB2 v9.7 и оператором SQL LIKE.Проверьте это:

-- this works and returns one record
select 1 
from SYSIBM.DUAL
where 'abc' like concat('a', 'bc') 

-- this doesn't work
select 1 
from SYSIBM.DUAL
where 'abc' like concat(cast('a' as varchar(2001)), cast('bc' as varchar(2000)))

-- It causes this error (from JDBC):
-- No authorized routine named "LIKE" of type "FUNCTION" having compatible 
-- arguments was found.. SQLCODE=-440, SQLSTATE=42884, DRIVER=4.7.85

Я поиграл с длинами, и кажется, что проблема появляется, как только длина складывается, чтобы быть больше, чем 4000.Если я «обрежу» всю сцепленную строку обратно до длины 4000, проблема исчезнет:

select 1 
from SYSIBM.DUAL
where 'abc' like 
  cast(concat(cast('a' as varchar(2001)), cast('bc' as varchar(2000)))
  as varchar(4000))

Интересно, что это действительно связано с функцией CONCAT.Также работает следующее:

select 1 
from SYSIBM.DUAL
where 'abc' like cast('abc' as varchar(32672))

Кто-нибудь сталкивался с такой проблемой?Это ошибка в DB2?Или какое-то недокументированное ограничение?NB: Я нашел похожую проблему здесь:

https://www -304.ibm.com / support / docview.wss? Uid = swg1PM18687

Учитывая, что другой IBMПродукт создает обходной путь для этой проблемы в 2010 году, я полагаю, что это не совсем ошибка, иначе это было бы исправлено за это время?

Ответы [ 3 ]

5 голосов
/ 20 августа 2013

Реальное Ага! здесь.

Во-первых, в соответствии с правилами для оператора конкатенации типа результата, конкатенация двух VARCHAR с объединенной длиной 4000 байтов или менее создает VARCHAR этой объединенной длины, например, concat(varchar(2000), varchar(2000)) = varchar(4000). Объединение двух VARCHAR с общей длиной 4001 байт или более приводит к получению LONG VARCHAR с длиной 32 700. Хотя тип LONG VARCHAR устарел, я предполагаю, что в поведении конкатенации все еще используется устаревшая логика.

$ db2 describe "values concat(cast('a' as varchar(2000)), cast('bc' as varchar(2000)))"

Column Information

Number of columns: 1

SQL type              Type length  Column name                     Name length
--------------------  -----------  ------------------------------  -----------
448   VARCHAR                4000  1                                         1


$ db2 describe "values concat(cast('a' as varchar(2001)), cast('bc' as varchar(2000)))"

Column Information

Number of columns: 1

SQL type              Type length  Column name                     Name length
--------------------  -----------  ------------------------------  -----------
456   LONG VARCHAR          32700  1     

Во-вторых, предикат LIKE ожидает, что выражение шаблона будет VARCHAR с максимальной длиной 32672 байта.

Впоследствии, когда вы неосознанно пытаетесь использовать LONG VARCHAR в качестве выражения шаблона, вы получаете ошибку. Дело не столько в длине операнда, сколько в типе данных. Следующее должно работать:

select 1 
from SYSIBM.DUAL
where 'abc' like 
   cast(concat(cast('a' as varchar(2001)), cast('bc' as varchar(2000)))
   as varchar(32672))
2 голосов
/ 11 февраля 2012

Редактировать: Ага!

При поиске в Информационном центре еще один бит знаний за VARCHAR с, я обнаружил этот отличный лакомый кусочек информации о символьном типе данных page :

Функции в схеме SYSFUN, принимающие VARCHAR в качестве аргумента, не будут принимать VARCHAR длиной более 4 000 байт в качестве аргумента.Однако многие из этих функций также имеют альтернативную подпись, принимающую CLOB (1M).Для этих функций пользователь может явным образом привести более 4000 строк VARCHAR в CLOB и затем преобразовать результат обратно в VARCHAR желаемой длины.

Итак, похоже, это известная «особенность»DB2.

Я провел дополнительное тестирование, и похоже, что «обходной путь», упомянутый выше, работает для DB2 в Linux / Unix / Windows, но не работает для DB2 на мейнфрейме.


Выход из страницы SQL и XML Limits из Информационного центра, если вы посмотрите на Таблицу 7 (третья строка), она говорит, что максимальная длина строки, включая все накладные расходы для таблицыпространство с размером страницы 4 КБ составляет 4005 байт.

Я предполагаю, что SYSIBM.DUAL находится в табличном пространстве размером 4 КБ, что приводит к вашей ошибке.Вы можете проверить SYSCAT.TABLESPACES, что может подтвердить или опровергнуть это подозрение.

Вы можете получить информацию с помощью запроса, например:

SELECT ts.PAGESIZE
FROM SYSCAT.TABLESPACES ts
JOIN SYSCAT.TABLES tb
  ON tb.TBSPACEID = ts.TBSPACEID
WHERE tb.TABSCHEMA = 'SYSIBM'
  AND tb.TABNAME   = 'DUAL'
1 голос
/ 11 февраля 2012

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

Я думаю, что если DB2 varchar выходит за рамки размера строки для запрашиваемой таблицы, он должен быть объявлен как LONG VARCHAR, хранится вне остальной части данных таблицы и на него ссылается указатель, а запросы LIKE больше не возможно. Но я не пользовался DB2 уже несколько лет. :)

...