ORA-01722: 将值从内部选择查询传递到顶部选择查询时数字无效
Posted
技术标签:
【中文标题】ORA-01722: 将值从内部选择查询传递到顶部选择查询时数字无效【英文标题】:ORA-01722: invalid number while passing value from inner select query to the top select query 【发布时间】:2018-08-15 13:01:33 【问题描述】:对于 ISBN['9780495809135'],如果 CATEGORY_EXISTS 列返回为 1234,3454,则查询将抛出错误。如果返回单行,则不会抛出错误。
我想在最顶层的查询中写下,如果 CATEGORY_EXISTS ='Category Not Found' 那么 FILE_NAME 列应该显示为 'files not found' 否则将用逗号分隔的 CATEGORY_EXISTS 值传递给最顶层的查询。
请注意,这只是伪查询,在实际查询中还有很多其他表和连接,
ORA-01722: 无效号码 01722. 00000 - “无效号码” *原因:指定的号码无效。 *操作:指定一个有效的数字。
SELECT ISBN ,
(SELECT LISTAGG(ANP.FILE_NAME, ',') WITHIN GROUP (
ORDER BY ANP.FILE_NAME)
FROM TABLE1 T
WHERE T.NODE_ID IN( CATEGORY_EXISTS)
)FILE_NAME
FROM
(SELECT ISBN,
(SELECT (
CASE
WHEN COUNT(DISTINCT AN.ID) > 0
THEN LISTAGG(AN.ID, ',') WITHIN GROUP (
ORDER BY AN.ID)
ELSE 'Category Not Found'
END )
FROM TABLE1 aca
JOIN TABLE2 AN
ON ACA.CHILD_NODE_ID=AN.ID
WHERE PARENT_NODE_ID=GT_CHILD_NODE_ID
) CATEGORY_EXISTS
FROM
(SELECT ISBN,
(SELECT ID FROM TEMP_CHILD_ASSOC ac WHERE CHILD_NODE_NAME=GT.ISBN
) GT_CHILD_NODE_ID
FROM MAIN_TABLE GT
WHERE ISBN='9780495809135'
)
);
【问题讨论】:
CATEGORY_EXISTS
是一个字符串,通过LISTAGG()
构建;您在 IN()
子句中使用该字符串。你期待发生什么?为什么要使用这么多子查询?
为什么当 CATEGORY_EXISTS 值传递到此处 T.NODE_ID IN(CATEGORY_EXISTS) 时会抛出“无效数字”错误?因为性能问题,我不得不创建这么多子查询。这是示例查询,实际上有很多表和相关的连接。
【参考方案1】:
listagg()
函数生成一串以逗号分隔的值(如果有多个 ID)。 case 表达式为您提供生成的字符串或固定文本文字(如果没有 ID)。然后,您尝试将该字符串与数字进行比较;实际上是其中之一:
WHERE T.NODE_ID IN ('4321')
WHERE T.NODE_ID IN ('1234,3454')
WHERE T.NODE_ID IN ('Category Not Found')
您正在将字符串隐式转换为数字以将其与NODE_ID
进行比较。第一个将工作,因为隐式转换是有效的。第二个会给你 ORA-01722 (除非你有两个值,并且你的 NLS 小数分隔符是一个逗号;但仍然不会给出匹配),第三个也会给出那个错误 - 因为这些字符串无法转换到数字。
您可能期望第二个在IN()
子句中被神奇地视为两个数字,但这不是它的工作原理;它得到一个字符串文字,而不是它可以理解的实际数字列表。
The IN
condition 确实接受多个逗号分隔表达式的列表,但您传递的是 single 字符串。 string 恰好由逗号分隔的值组成的事实是无关紧要的:它本身仍然只是一个表达式。并且不能隐式转换为数字。
如果您拥有或可以创建架构级表类型,例如:
create type my_number_tab as table of number
/
然后您可以使用collect()
函数将ID 转换为集合而不是字符串,然后使用member of
查找匹配项;类似于(对您的伪代码进行一些解释):
SELECT ISBN ,
(SELECT LISTAGG(ANP.FILE_NAME, ',') WITHIN GROUP (
ORDER BY ANP.FILE_NAME)
FROM TABLE3 ANP
WHERE ANP.NODE_ID MEMBER OF CATEGORIES -- use collection
)FILE_NAME
FROM
(SELECT ISBN,
(SELECT CAST(COLLECT(AN.ID) AS my_number_tab) -- create collection not string
FROM TABLE1 aca
JOIN TABLE2 AN
ON ACA.CHILD_NODE_ID=AN.ID
WHERE PARENT_NODE_ID=GT_CHILD_NODE_ID
) CATEGORIES
FROM
(SELECT ISBN,
(SELECT ID FROM TEMP_CHILD_ASSOC ac WHERE CHILD_NODE_NAME=GT.ISBN
) GT_CHILD_NODE_ID
FROM MAIN_TABLE GT
WHERE ISBN='9780495809135'
)
);
看起来您也可以在内部查询中加入anp
,这样您就可以生成文件名的字符串列表,而不是(或以及)ID 的字符串列表。但是很难从伪代码中分辨出来;但也许是这样的:
SELECT ISBN,
(SELECT (
CASE
WHEN COUNT(DISTINCT AN.ID) > 0
THEN LISTAGG(ANP.FILE_NAME, ',') WITHIN GROUP (
ORDER BY ANP.FILE_NAME)
ELSE 'Category Not Found'
END )
FROM TABLE1 aca
JOIN TABLE2 AN
ON ACA.CHILD_NODE_ID=AN.ID
JOIN TABLE3 ANP
ON ANP.NODE_ID=AN.ID
WHERE ACA.PARENT_NODE_ID=GT_CHILD_NODE_ID
) FILE_NAME
FROM
(SELECT ISBN,
(SELECT ID FROM TEMP_CHILD_ASSOC ac WHERE CHILD_NODE_NAME=GT.ISBN
) GT_CHILD_NODE_ID
FROM MAIN_TABLE GT
WHERE ISBN='9780495809135'
);
尽管您的评论表明您有理由改用子查询,但您可能也可以对左外连接执行相同的操作(尽管它们可能并不都需要):
SELECT GT.ISBN,
CASE WHEN COUNT(AN.ID) = 0 THEN 'files not found'
ELSE LISTAGG(ANP.FILE_NAME, ',') WITHIN GROUP (ORDER BY ANP.FILE_NAME)
END AS file_name
FROM MAIN_TABLE GT
LEFT JOIN TEMP_CHILD_ASSOC ac ON CHILD_NODE_NAME=GT.ISBN
LEFT JOIN table1 aca ON aca.parent_node_id = ac.id
LEFT JOIN table2 an on an.id = ACA.CHILD_NODE_ID
LEFT JOIN table3 anp on anp.node_id = an.id
WHERE GT.ISBN = '9780495809135'
GROUP BY GT.ISBN;
或类似的东西;又很难从伪代码中分辨出来......
【讨论】:
感谢详细解释。但在 CAST(收集位置..ORA-22814:属性或元素值大于类型 22814 中指定的值。00000 -“属性或元素值大于在类型中指定” *原因:为对象类型属性或集合元素提供的值超出了类型声明中指定的大小。*操作:选择另一个值并重试操作。错误在行:21 列:19 @user739115 - ID 列是什么数据类型,您如何定义用于集合的表类型?听起来那里不匹配。 已修复问题。感谢您抽出宝贵时间并给出详细解释。以上是关于ORA-01722: 将值从内部选择查询传递到顶部选择查询时数字无效的主要内容,如果未能解决你的问题,请参考以下文章