【问题标题】:Invalid number of returned comma delimited string in a IN clause in OracleOracle中IN子句中返回的逗号分隔字符串的数量无效
【发布时间】:2011-06-11 20:54:13
【问题描述】:

我正在尝试使用在 IN 子句中返回逗号分隔字符串的子查询。

以下方式:

SELECT p.person_id, g.name || '>>' || p.firstname || ' ' || p.lastname as GROUP_PATH
FROM PERSON p 
LEFT JOIN GROUP g ON (
    g.group_id = p.group_id
)
WHERE p.person_id IN ( 
    SELECT person_ids FROM other WHERE other_id = :OTHER_ID
) 
ORDER BY lower(GROUP_PATH) 

我收到以下错误:

ORA-01722: 无效号码。

有没有更好的方法来做到这一点甚至可能?

【问题讨论】:

  • 你能显示所有三个表的表定义(特别是 id 列类型)吗?以及如何定义:other_id?您可能将数字列连接到您认为只有数字或仅匹配数字的 varchar,并且它会绊倒您不希望相关的非数字值。
  • 我刚刚注意到我的初始查询是错误的。我更新了。
  • person_ids 在other 中是逗号分隔的列表吗?如果是这样,那在IN 子句中将不起作用。您需要将字符串解析为一个集合并在查询中使用该集合。但是你不应该首先在关系数据库中存储一个逗号分隔的键列表,所以你可能想要修复你的数据模型。

标签: oracle subquery in-clause ora-01722


【解决方案1】:

最明显的解释是你试图用一个字符串做数学......

尝试转换 字符串到数字失败 因为字符串不是 有效的数字文字。只有数字 字段或字符字段包含 数值数据可用于算术 函数或表达式。只有数字 字段可以添加或减去 从日期开始。

http://ora-01722.ora-code.com/

更新 #1:

你的描述让我担心:

我正在尝试使用一个子查询 在 a 中返回一个逗号分隔的字符串 IN 子句。

您的子查询应该不返回一个逗号分隔的字符串(除非g.group_id 是一个字符串并且需要一个逗号分隔的字符串)。您必须根据需要检索尽可能多的行中的单个项目(无论如何少于 1,000 个)。

更新 #2:

只是为了说清楚:

SELECT *
FROM (
    SELECT 1 AS FOO_ID FROM DUAL UNION SELECT 2 FROM DUAL UNION SELECT 3 FROM DUAL
) FOO;

FOO_ID                 
---------------------- 
1                      
2                      
3  

你可以这样做:

SELECT *
FROM (
    SELECT 1 AS FOO_ID FROM DUAL UNION SELECT 2 FROM DUAL UNION SELECT 3 FROM DUAL
) FOO
WHERE FOO_ID IN (1, 2);

FOO_ID                 
---------------------- 
1                      
2 

但不是这个:

SELECT *
FROM (
    SELECT 1 AS FOO_ID FROM DUAL UNION SELECT 2 FROM DUAL UNION SELECT 3 FROM DUAL
) FOO
WHERE FOO_ID IN ('1,2');

SQL Error: ORA-01722: invalid number

因为您无法将数字 1 与字符串 '1,2' 进行比较。子查询遵循类似的规则:

SELECT *
FROM (
    SELECT 1 AS FOO_ID FROM DUAL UNION SELECT 2 FROM DUAL UNION SELECT 3 FROM DUAL
) FOO
WHERE FOO_ID IN (
    SELECT 1 AS FOO_ID FROM DUAL UNION SELECT 2 FROM DUAL
);

FOO_ID                 
---------------------- 
1                      
2 

SELECT *
FROM (
    SELECT 1 AS FOO_ID FROM DUAL UNION SELECT 2 FROM DUAL UNION SELECT 3 FROM DUAL
) FOO
WHERE FOO_ID IN (
    SELECT '1,2' AS FOO_ID FROM DUAL
);

SQL Error: ORA-01722: invalid number

【讨论】:

  • 当我只查询子查询并将结果(逗号分隔)粘贴到 IN 子句中时,它工作正常。对此有何解释?
  • 假设您收到'10,20,30'。你用它做什么? g.group_id IN (10,20,30)(三个数字)还是g.group_id IN ('10,20,30')(一个字符串)?
  • 我注意到我重写了查询错误。现在检查一下。我应该得到多个 person_ids 而不是 group_ids。
  • 没关系;多个 ID 是否以字符串形式返回?
  • 是的,我会这么说,因为列 person_ids 的类型是 varchar2。
【解决方案2】:

至少,为了引用别名GROUP_PATH,您需要使用嵌套子查询,其中别名在您在 ORDER BY 子句中引用之前定义。这实际上不会导致 ORA-01722 错误,但这是一个问题

SELECT group_id, group_path
  FROM (SELECT g.group_id, 
               g.name || '>>' || p.firstname || ' ' || p.lastname as GROUP_PATH
          FROM PERSON p 
               LEFT JOIN GROUP g ON (
                      g.group_id = p.group_id
               )
         WHERE p.person_id IN ( 
               SELECT person_ids FROM other WHERE other_id = :OTHER_ID
               ) 
 ORDER BY lower(GROUP_PATH) 

如果OTHER 表中的PERSON_IDS 列是一个逗号分隔的值列表,那么您的IN 列表将不会按照您的预期进行。您需要将标量字符串(其中恰好有逗号)转换为某种类型的多个 PERSON_ID 值的集合。有多种方法可以做到这一点,Tom Kyte 有一个使用variable IN list 的示例。假设您复制 Tom 的 IN_LIST 函数,您应该能够执行类似的操作

SELECT group_id, group_path
  FROM (SELECT g.group_id, 
               g.name || '>>' || p.firstname || ' ' || p.lastname as GROUP_PATH
          FROM PERSON p 
               LEFT JOIN GROUP g ON (
                      g.group_id = p.group_id
               )
         WHERE p.person_id IN ( 
               SELECT column_value
                 FROM TABLE(SELECT in_list(person_ids) 
                              FROM other 
                             WHERE other_id = :OTHER_ID)
               ) 
 ORDER BY lower(GROUP_PATH) 

【讨论】:

  • 感谢贾斯汀的回复。我只是注意到我写错了查询。我没有得到逗号分隔的组 id 字符串,而是得到逗号分隔的人员 id。
  • @Kel - 编辑我的查询以匹配
猜你喜欢
  • 1970-01-01
  • 2013-06-04
  • 1970-01-01
  • 2012-05-15
  • 1970-01-01
  • 2011-06-08
  • 1970-01-01
  • 2023-01-03
  • 1970-01-01
相关资源
最近更新 更多