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: 将值从内部选择查询传递到顶部选择查询时数字无效的主要内容,如果未能解决你的问题,请参考以下文章

ORA-01722: 无效的包编号

选择时将值从 TabBarController 传递给子视图控制器

将值从文本框传递到 SQL 查询中的“TOP n”子句

如何将值从python传递给c++并返回?

将值从 CFM 传递到 CFM 进行处理

通过 AsyncTask 将值从第一个活动传递到第三个活动