using comma separated values inside IN clause for NUMBER column

人盡茶涼 提交于 2019-12-03 18:07:52

问题


I have 2 procedures inside a package. I am calling one procedure to get a comma separated list of user ids.

I am storing the result in a VARCHAR variable. Now when I am using this comma separated list to put inside an IN clause in it is throwing "ORA-01722:INVALID NUMBER" exception.

This is how my variable looks like

l_userIds VARCHAR2(4000) := null;

This is where i am assigning the value

l_userIds := getUserIds(deptId);  -- this returns a comma separated list

And my second query is like -

select * from users_Table where user_id in (l_userIds);

If I run this query I get INVALID NUMBER error.

Can someone help here.


回答1:


Do you really need to return a comma-separated list? It would generally be much better to declare a collection type

CREATE TYPE num_table
    AS TABLE OF NUMBER;

Declare a function that returns an instance of this collection

CREATE OR REPLACE FUNCTION get_nums
  RETURN num_table
IS
  l_nums num_table := num_table();
BEGIN
  for i in 1 .. 10
  loop
    l_nums.extend;
    l_nums(i) := i*2;
  end loop;
END;

and then use that collection in your query

SELECT *
  FROM users_table
 WHERE user_id IN (SELECT * FROM TABLE( l_nums ));

It is possible to use dynamic SQL as well (which @Sebas demonstrates). The downside to that, however, is that every call to the procedure will generate a new SQL statement that needs to be parsed again before it is executed. It also puts pressure on the library cache which can cause Oracle to purge lots of other reusable SQL statements which can create lots of other performance problems.




回答2:


You can search the list using like instead of in:

select *
from users_Table
where ','||l_userIds||',' like '%,'||cast(user_id as varchar2(255))||',%';

This has the virtue of simplicity (no additional functions or dynamic SQL). However, it does preclude the use of indexes on user_id. For a smallish table this shouldn't be a problem.




回答3:


The problem is that oracle does not interprete the VARCHAR2 string you're passing as a sequence of numbers, it is just a string.

A solution is to make the whole query a string (VARCHAR2) and then execute it so the engine knows he has to translate the content:

DECLARE
    TYPE T_UT IS TABLE OF users_Table%ROWTYPE;
    aVar T_UT;
BEGIN
    EXECUTE IMMEDIATE 'select * from users_Table where user_id in (' || l_userIds || ')' INTO aVar;
...

END;

A more complex but also elegant solution would be to split the string into a table TYPE and use it casted directly into the query. See what Tom thinks about it.




回答4:


DO NOT USE THIS SOLUTION!

Firstly, I wanted to delete it, but I think, it might be informative for someone to see such a bad solution. Using dynamic SQL like this causes multiple execution plans creation - 1 execution plan per 1 set of data in IN clause, because there is no binding used and for the DB, every query is a different one (SGA gets filled with lots of very similar execution plans, every time the query is run with a different parameter, more memory is needlessly used in SGA).

Wanted to write another answer using Dynamic SQL more properly (with binding variables), but Justin Cave's answer is the best, anyway.

You might also wanna try REF CURSOR (haven't tried that exact code myself, might need some little tweaks):

DECLARE
    deptId                  NUMBER := 2;
    l_userIds               VARCHAR2(2000) := getUserIds(deptId);
    TYPE t_my_ref_cursor IS REF CURSOR;
    c_cursor                t_my_ref_cursor;
    l_row                   users_Table%ROWTYPE;
    l_query                 VARCHAR2(5000);
BEGIN
    l_query := 'SELECT * FROM users_Table WHERE user_id IN ('|| l_userIds ||')';
    OPEN c_cursor FOR l_query;

    FETCH c_cursor INTO l_row;
    WHILE c_cursor%FOUND
    LOOP
        -- do something with your row
        FETCH c_cursor INTO l_row;
    END LOOP;

END;
/



来源:https://stackoverflow.com/questions/18006883/using-comma-separated-values-inside-in-clause-for-number-column

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!