Referencing an array element in select Query in PL/SQL - sql

I am writing some Pl/SQl in which I used an array Variable of Length 5.
Then I stored all the Column name of another table into the above declared array.
Now I am looking for a solution by which I can use the Array element in select Query to fetch the data from another table which exactly has the column name.
Like
arr(1):='Name'
arr(2):='Course'
The Query in Pl/Sql should be something like this (for reference only)
select arr(1) from Mttable;
==== This generates error when I write the Query in this way
Note- All work should be done in Pl/SQL on Oracle 10g
Please Help.

You can build up a query in a string and execute the string. My PL/SQL is rusty, but something like:
begin
query := 'select ' || arr(1) || ' from Mttable';
execute immediate query;
end;

Related

Native Dynamic SQL, creating string

I've just started with PL/SQL. My concern is as follows:
I want to create a string dynamically.
I tried the following, but it always results in ORA-00900 & ORA-06512 at the line of "Execute Immediate...".
Here we go:
Declare
l_pre_sql varchar2(4000) := 'schema.';
l_sql varchar2(4000) := 'concat(concat(:a, :b), :c)';
l_after_sql := '.procedure(a,b,c)';
begin
execute immediate l_sql using l_pre_sql, l_sql, l_after_sql;
end;
Is the syntax of execute immediate wrong? Are there any other working possibilities? As you may see, i am working around the problem that one cannot use schema name as a dynamic variable.
For clarification I basically want to do this:
execute immediate ':a'||'.'||':b'||'.procedure(a,b,c)' using schema, name;
Thanks in advance!
In prepared statements (in Oracle and other languages), you can replace constant values in the query string using parameters. However, you cannot replace column names, table names, users (schemas), procedure names, and so on.
In other words, the substitution is not just by replacing values with string representations. It is plugging parameters into a compiled statement.
So, you need to construct the string with the procedure names first and then call it.
I think what you want is something like:
execute immediate l_pre_sql || l_after_sql || '(:a, :b, :c)' using . . .

Postgres run SQL statement from string

I would like to execute a SQL statement based on a string. I have created the SQL statement through a function which returns a string. Can anybody explain how I can execute the statement that is returned? I know that you can't do it in plain SQL, so I was thinking about putting it in a function. The only issue is that the columns in the statement aren't always the same, so I don't know which data types to use for the columns. I'm using Postgres 9.1.0.
For example, suppose the SQL string returned from my function the is:
Select open, closed, discarded from abc
But, it can also be:
Select open from abc
Or
Select open, closed from abc
How can I execute any of these strings, so that the results would be returned as a table with only the columns listed in the statement?
Edit: the function is written in PL/pgSQL. And the results will be used for reporting where they don't want to see columns that have no values. So the function that I wrote returns the names of all columns that have values and then add it to the SQL statement.
Thanks for your help!
I don't think you can return the rows directly from a function, because its return type would be unknown. Even if you specified the return type as RECORD, you'd have to list the returned columns at call time. Based on Wayne Conrad's idea, you could do this:
CREATE FUNCTION my_create(cmd TEXT) RETURNS VOID AS $$
BEGIN
EXECUTE 'CREATE TEMPORARY TABLE temp_result AS ' || cmd;
END;
$$ VOLATILE LANGUAGE plpgsql;
Then use the function like this:
BEGIN;
SELECT my_create(...);
SELECT * FROM temp_result;
ROLLBACK; -- or COMMIT

using comma separated values inside IN clause for NUMBER column

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.
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.
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.
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.
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;
/

How to execute stored procedures containing dynamic SQL in oracle?

I've created the following procedure
Create or replace procedure abcd
(
tab_name in USER_TABLES.table_name%type
)
is
begin
execute immediate
'select * from'||tab_name;
end abcd;
The procedure gets compiled.
I am trying to get the output using the following
select abcd('Table') from dual ;
I am new to dynamic SQL and this does not seem to work for me. I keep getting the error
[Error] Execution (44: 8): ORA-00904: "ABCD": invalid identifier
Can someone please help ?
Regards,
Kshitij
You're missing a space before your table name:
create or replace procedure abcd (tab_name in USER_TABLES.table_name%type )
is
begin
execute immediate 'select * from '||tab_name;
end abcd;
This won't work because you're trying to call it as a function, not a procedure:
select abcd('Table') from dual ;
Your second attempt should now work:
exec abcd('Table');
... but will now get a different error. In PL/SQL you have to select into something. In this case you probably want to open a cursor with the dynamic string and do something with the results. Not really sure what your end goal is though.
You should also read up about SQL injection while you learn about dynamic SQL.
you cannot perform a select on a procedure, a function will work only if single record return.
use
begin
abcd();
end;
or use
execute keyword
ALSO use a space after from in query
It will not work.
When you invoke EXECUTE IMMEDIATE the sql statement is send to SQL engine. No results are passed back to the PL/SQL.
Writing "SELECT * FROM a_table" is not that hard and much safer.

Oracle SQL: variables used in place of table names

I am converting a MSSQL script to Oracle, and I haven't been able to figure out the syntax to use a variable in place of a table name or column.
Here is a simple example that I've been try to make work in Oracle SQL Developer so I can better understand the syntax:
set serveroutput on format wrapped;
declare
VR_TABLE VARCHAR2(256);
VR_UPDATE VARCHAR2(256);
begin
VR_TABLE :='SYSTEM_STATUS';
EXECUTE IMMEDIATE 'select UPDATE_VERSION INTO VR_UPDATE from ' || VR_TABLE || 'where rownum < 2 ;'
end;
Where VR_TABLE is the variable table name that will get changed each iteration of the loop.
Can somebody point out what I'm doing wrong, or link me to a site that would be useful for me to read? I've read a few tutorials on this, but I haven't had any luck thus far.
You need to have a space between the table name and the subsequent WHERE clause
The INTO needs to be part of the EXECUTE IMMEDIATE, not part of the dynamic SQL statement.
The dynamic SQL statement should not have a trailing semicolon
The EXECUTE IMMEDIATE statement should end with a semicolon
Putting those together, something like this should work
declare
VR_TABLE VARCHAR2(256);
VR_UPDATE VARCHAR2(256);
begin
VR_TABLE :='SYSTEM_STATUS';
EXECUTE IMMEDIATE 'select UPDATE_VERSION from ' || VR_TABLE || ' where rownum < 2'
INTO VR_UPDATE;
end;
Of course, since you're not doing anything with VR_UPDATE, nothing will be displayed when this anonymous block is executed.
INTO part of the query should not be directly included in the query
string.
Syntax
EXECUTE IMMEDIATE(<SQL>)
[INTO<variable>]
[USING <bind_variable_value>]
The above syntax shows EXECUTE IMMEDIATE command.
Clause INTO is optional and used only if the dynamic SQL contains a select statement that fetches values. The variable type should match with the variable type of the select statement.
Clause USING is optional and used only if the dynamic SQL contains any bind variable.
https://www.guru99.com/dynamic-sql-pl-sql.html#2
You can visit this site for a better understanding of Dynamic SQL.