Reputation: 25
I am dynamically constructing a string with name user_data in PL/Sql procedure by appending USERNAMEs, single quotes(') and commas(,) of the form
'abc123','xyz456','pqr789'
But when I pass this string to WHERE IN condition of SELECT statement
SELECT * FROM table_name WHERE USERNAME IN (user_data)
It is throwing a NO_DATA_FOUND exception.
On the other hand if my string contains only one user without the quotes, it is able to find that user and display desired output.
The datatype of string user_data is varchar2.
Upvotes: 0
Views: 2242
Reputation: 1006
Your select statement
SELECT * FROM table_name WHERE USERNAME IN (user_data)
will be treated as
SELECT * FROM table_name WHERE USERNAME = 'abc123','xyz456','pqr789'
which is not correct.
One alternative is
SELECT * FROM table_name WHERE INSTR(user_data, USERNAME) > 0
Upvotes: 0
Reputation: 167972
You can do it using a collection:
CREATE TYPE VARCHAR2s_Table IS TABLE OF VARCHAR2(100);
/
Then enter your data like this:
SELECT *
FROM table_name
WHERE user_data MEMBER OF VARCHAR2s_Table( 'abc123','xyz456','pqr789' );
Alternatively:
You can create a function to split the data and generate the collection:
CREATE TYPE VARCHAR2_TABLE AS TABLE OF VARCHAR2(4000);
/
CREATE OR REPLACE FUNCTION split_String(
i_str IN VARCHAR2,
i_delim IN VARCHAR2 DEFAULT ','
) RETURN VARCHAR2_TABLE DETERMINISTIC
AS
p_result VARCHAR2_TABLE := VARCHAR2_TABLE();
p_start NUMBER(5) := 1;
p_end NUMBER(5);
c_len CONSTANT NUMBER(5) := LENGTH( i_str );
c_ld CONSTANT NUMBER(5) := LENGTH( i_delim );
BEGIN
IF c_len > 0 THEN
p_end := INSTR( i_str, i_delim, p_start );
WHILE p_end > 0 LOOP
p_result.EXTEND;
p_result( p_result.COUNT ) := SUBSTR( i_str, p_start, p_end - p_start );
p_start := p_end + c_ld;
p_end := INSTR( i_str, i_delim, p_start );
END LOOP;
IF p_start <= c_len + 1 THEN
p_result.EXTEND;
p_result( p_result.COUNT ) := SUBSTR( i_str, p_start, c_len - p_start + 1 );
END IF;
END IF;
RETURN p_result;
END;
/
Then you can do:
SELECT *
FROM table_name
WHERE user_data MEMBER OF split_String( 'abc123,xyz456,pqr789', ',' );
or:
SELECT *
FROM table_name
WHERE user_data MEMBER OF split_String( TRIM( '''' FROM '''abc123'',''xyz456'',''pqr789''' ), ''',''' );
Upvotes: 3
Reputation: 22949
You can a dynamic string in your IN
clause with something like this:
SQL> declare
2 user_data varchar2(1000);
3 vSQL varchar2(2000);
4 type tabUser is table of varchar2(16);
5 outData tabUser;
6 begin
7 user_data := '''abc'', ''123'', ''zzz''';
8 --
9 vSQL := 'select userName from table_name where username in (' || user_data || ')';
10 --
11 execute immediate vSQL bulk collect into outData;
12 --
13 dbms_output.put_line('user_data: ' || user_data);
14 for i in outData.first .. outData.last loop
15 dbms_output.put_line('User: ' || outData(i));
16 end loop;
17 end;
18 /
user_data: 'abc', '123', 'zzz'
User: abc
User: 123
PL/SQL procedure successfully completed.
SQL> select * from table_name;
USERNAME
----------------
abc
ABC
123
In this case you always have to use quoted names in your string, no matter if you have one or more usernames.
Upvotes: 0
Reputation: 596
It isn't work like that. Your expression is equal to
SELECT * FROM table_name WHERE USERNAME = '''abc123'', ''xyz456'', ''pqr789''';
That's why no results found.
You could do something like this, to achive desire effect:
SELECT * FROM table_name WHERE user_data like '%''' || USERNAME || '''%';
But it wouldn't be the same though.
Upvotes: 0