【问题标题】:Using :var with "IN" operator in WHERE clause在 WHERE 子句中使用 :var 和 "IN" 运算符
【发布时间】:2025-12-22 05:00:17
【问题描述】:

我通常使用 MySQL 或 SQL Server,我在 Oracle SQL Developer 中遇到了相当大的问题。

我有这样的查询(只是为了简单地复制我的问题):

SELECT *
FROM table t1
WHERE t1.date > :START_DATE AND t1.date < :END_DATE AND t1.id IN (:IDS)

当我运行此查询时,对话窗口会打开并提示我输入变量。

问题是当我输入逗号分隔的 ID(如 5,6,7 或带引号 '5,6,7')时,我收到此错误:

ORA-01722: 无效号码
01722. 00000 - “无效号码”
*原因:
*行动:

这里有什么想法吗?

PS:输入变量必须有对话框提示。同事对 SQL 不友好。 ;)

【问题讨论】:

  • 伙计,非常感谢。这是我一直在寻找的解决方案。
  • 您是否遇到过 任何 语言,在传递单个字符串参数时将决定(自动)检查内容,观察逗号,而是决定将其视为多个单独的参数? (然而,奇怪的是,人们一直期望这是 SQL 中的行为)
  • @Damien_The_Unbeliever 如果使用替换变量而不是绑定变量,它的行为会像这样。

标签: sql oracle


【解决方案1】:

问题在于绑定变量 :ids 包含一个文字值(而不是文字值列表),因此您的查询是:

AND t1.id IN ( '5,6,7' )

代替:

AND t1.id IN ( 5, 6, 7 )

您需要做的是pass in a collection(您可以从外部语言的数组中定义并直接作为绑定变量传入):

CREATE OR REPLACE TYPE intlist IS TABLE OF INTEGER;
/

SELECT *
FROM table t1
WHERE t1.date > :START_DATE
AND   t1.date < :END_DATE
AND   t1.id MEMBER OF intlist( 5, 6, 7 )

或者使用LIKE比较列表:

SELECT *
FROM table t1
WHERE t1.date > :START_DATE
AND   t1.date < :END_DATE
AND   ',' || :ids || ',' LIKE '%,' || t1.id || ',%'

或者传入delimited string literal and split that

SELECT *
FROM table t1
WHERE t1.date > :START_DATE
AND   t1.date < :END_DATE
AND   t1.id   IN ( SELECT TO_NUMBER( REGEXP_SUBSTR( :ids, '\d+', 1, LEVEL ) )
                   FROM   DUAL
                   CONNECT BY LEVEL <= REGEXP_COUNT( :ids, '\d+' ) );

(或者,如果您使用替换变量而不是绑定变量,逗号分隔的数字列表将在 IN 子句中起作用。)

【讨论】:

    【解决方案2】:

    ID 是 NUMBERS 还是 VARCHAR2?

    这个简单的案例对我有用。请尝试一下:

    select id from
    (
    select 1 id from dual
    union
    select 2 id from dual
    union
    select 3 id from dual
    )
    where id in (:IDS)
    

    【讨论】:

    • 如果你有几十行长的查询,那真是一个丑陋的解决方案。
    • 这不是一个解决方案,只是一个样本来测试参数“IDS”是否有效。