DB2 for iSeries中如何将SELECT结果作为LIMIT子句的参数
问题原因
你写的语句无法运行,是因为iSeries平台的DB2(即DB2 for i)不支持直接在LIMIT子句中嵌套子查询作为参数。而且你这个跨环境重复的场景,其实不需要硬套LIMIT逻辑,有更适配系统表特性的稳定解法。
方案1:窗口函数直接去重(最推荐,适配V7R2及以上版本,覆盖绝大多数在用的iSeries环境)
不需要算总列数、不需要传参,直接按你提到的重复排序IDOrdinal_Position分组,每个序号只取1条记录,从根源绕开跨环境字段编码差异、环境值不固定的问题,不会出现去重不全的情况:
SELECT SYSTEM_COLUMN_NAME, DATA_TYPE, STORAGE, COLUMN_TEXT, COLUMN_NAME, COLUMN_HEADING FROM ( SELECT SYSTEM_COLUMN_NAME, DATA_TYPE, STORAGE, COLUMN_TEXT, COLUMN_NAME, COLUMN_HEADING, ROW_NUMBER() OVER (PARTITION BY ORDINAL_POSITION ORDER BY SYSTEM_TABLE_SCHEMA) AS RN FROM SYSCOLUMNS WHERE TABLE_NAME = '*EXAMPLE*' ) T WHERE RN = 1 ORDER BY ORDINAL_POSITION
这个写法会固定取第一个匹配到的schema下的表字段,不会混不同环境的重复记录。
方案2:会话变量传参实现LIMIT逻辑
如果你一定要按原来的思路,把最大序号值传给LIMIT,可以用DB2 for i支持的会话变量实现:
- 先创建会话级变量存储最大序号
CREATE VARIABLE SESSION.TARGET_MAX_ORDINAL INT; - 给变量赋值
SET SESSION.TARGET_MAX_ORDINAL = ( SELECT MAX(ORDINAL_POSITION) FROM SYSCOLUMNS WHERE TABLE_NAME = '*EXAMPLE*' ); - 执行查询,注意必须加
ORDER BY,否则返回顺序随机,可能拿到跨环境混杂的结果SELECT SYSTEM_COLUMN_NAME, DATA_TYPE, STORAGE, COLUMN_TEXT, COLUMN_NAME, COLUMN_HEADING FROM SYSCOLUMNS WHERE TABLE_NAME = '*EXAMPLE*' ORDER BY ORDINAL_POSITION, SYSTEM_TABLE_SCHEMA LIMIT SESSION.TARGET_MAX_ORDINAL
方案3:老版本兼容动态SQL写法
如果你的iSeries系统版本低于V7R2,不支持窗口函数和会话变量,可以用SQL块的动态SQL拼接实现:
BEGIN DECLARE MAX_POS INT; DECLARE QUERY_STMT VARCHAR(1200); -- 拿到单表最大列序号 SELECT MAX(ORDINAL_POSITION) INTO MAX_POS FROM SYSCOLUMNS WHERE TABLE_NAME = '*EXAMPLE*'; -- 拼接查询语句执行 SET QUERY_STMT = 'SELECT SYSTEM_COLUMN_NAME, DATA_TYPE, STORAGE, COLUMN_TEXT, COLUMN_NAME, COLUMN_HEADING FROM SYSCOLUMNS WHERE TABLE_NAME = ''*EXAMPLE*'' ORDER BY ORDINAL_POSITION, SYSTEM_TABLE_SCHEMA LIMIT ' || TRIM(CHAR(MAX_POS)); PREPARE RUN_STMT FROM QUERY_STMT; EXECUTE RUN_STMT; END
注意事项
之前用GROUP BY去重效果差,核心原因是不同环境下的同名字段可能存在CCSID编码差异、文本字段尾部空格填充差异,按ORDINAL_POSITION分区取数的逻辑完全绕开了字段内容比对,不会因为这类细微差异导致去重失败。
内容的提问来源于stack exchange,提问作者Teddy Wauquier
相关产品推荐
相关产品推荐

