DB2 LIKE运算符的奇怪长度限制

时间:2012-02-10 19:57:16

标签: sql casting db2 sql-like varchar

我发现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中的错误吗?还是一些无证的限制? N.B:我在这里发现了类似的问题:

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

鉴于另一个IBM产品在2010年为此问题创建了一个解决方法,我想这不是一个真正的错误,否则它会在同一时间得到修复?

3 个答案:

答案 0 :(得分:5)

真正的啊哈!就在这里。

首先,根据rules for the concatenation operator结果类型,连接两个长度为4000字节或更少的VARCHAR会产生该组合长度的VARCHAR,例如: concat(varchar(2000), varchar(2000)) = varchar(4000)。连接长度为4001字节或更多的两个VARCHAR会产生长度为32 700的LONG VARCHAR。虽然不推荐使用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 predicate期望模式表达式为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))

答案 1 :(得分:2)

编辑:啊哈!

在信息中心搜索有关VARCHAR的其他一些知识时,我发现了character data type page上的这一小段信息:

  

SYSFUN模式中的函数将VARCHAR作为参数   不会接受长度大于4 000字节的VARCHAR作为参数。   但是,这些功能中的许多功能还具有替代签名   接受CLOB(1M)。对于这些功能,用户可以明确地   将大于4 000个VARCHAR字符串转换为CLOB,然后重新编译   结果返回到所需长度的VARCHAR。

因此,看起来它是DB2的一个已知“特性”。

我做了一些额外的测试,看起来上面提到的“解决方法”适用于Linux / Unix / Windows上的DB2,但不适用于大型机上的DB2。


从信息中心离开SQL and XML Limits页面,如果查看表7(第三行),它表示行的最大长度,包括页面大小为4k的表空间的所有开销是4005字节。

我的猜测是SYSIBM.DUAL位于4k页面大小的表空间中,这会导致您的错误。您可以查看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'

答案 2 :(得分:1)

这可能与您的表所​​在的表空间的行大小有关吗?

我认为如果DB2 varchar扩展到您要查询的表的rowsize之外,它必须声明为LONG VARCHAR,存储在其余表数据的外部并由指针引用,LIKE查询是不再可能。但是我已经使用DB2多年了。 :)