I am dynamically building a search query with bind variables with at least 1 and at most 7 different potential criteria. I know I can do this -
EXECUTE IMMEDIATE sql USING bind_var1, bind_var2 or
EXECUTE IMMEDIATE sql USING bind_var3, bind_var5, bind_var7.
Is it possible to include the bind variables within the sql?
sql = 'SELECT * FROM table WHERE id = :bind_var1 AND name = :bind_var2 USING bind_var1, bind_var2'
and do
EXECUTE IMMEDIATE sql?
I want and need to dynamically build the USING piece instead of writing a lot of IF THEN statements.
According to your tags, I assume this will be used inside some kind of PL/SQL block. So, maybe are you looking for the open for statement.
This allows you to get a cursor on an dynamic query:
sql := 'SELECT * FROM table WHERE id = :bind_var1 AND name = :bind_var2';
open my_cursor for sql using bind_var1, bind_var2';
-- do whatever you need with your cursor
your USING bind_var1, bind_var2 pice of code should be out side os your sql string and come at the end of execute immediate statement and also for select senarios try to use dynamic sql for select with a cursor unless you want to select into a variable
Related
In Oracle's SQL Developer, I can execute a "dynamic" SQL select statement in the Script Output pane with something like:
script
var tabName = 'all_users';
sqlcl.setStmt('select * from ' + tabName);
sqlcl.run();
/
Now, I am wondering if it is possible to execute a dynamic select statement such that its result is displayed in the result grid.
SqlDev is implemented in Java which includes Nashorn scripting engine. Therefore, you can basically execute JDBC in your Nashorn script. Here is one way to do it.
Paste
select REGIONS,
COUNTRIES,
LOCATIONS,
DEPARTMENTS,
JOBS,
EMPLOYEES,
JOB_HISTORY,
TM_USER_INFO,
USER_ROLES,
PAYMENT_PRICE_SHOP,
SHOP_USER from dual
into your worksheet.
Open "Code Outline" panel. Type "arbori", or open the following "querySQL.arbori" file:
include "std.arbori"
prelude: runOnce -> {
var ConnectionResolver = Java.type('oracle.dbtools.db.ConnectionResolver');
var connectionList = ConnectionResolver.getConnectionNames();
var conn = ConnectionResolver.getConnection('IdeConnections%23local_hr');
}
queries: [node) column -> {
var node = tuple.get('node');
var table = target.input.substring(
target.src[node.from].begin,
target.src[node.to-1].end
);
var query = 'select * from ' + table;
var ps = conn.createStatement();
var rs = ps.executeQuery(query);
while( rs.next() )
print(rs.getString(1));
}
It outputs the first column of each table to the standard java output
, so it would require some reverse engineering to get a handle to the SqlDev script output panel and channel the result there.
Dynamic SQL can be displayed in an Oracle SQL Developer grid using a function returning a ref cursor (sort of), a polymorphic table function (18c+), or Oracle Data Cartridge (requires custom PL/SQL packages and types).
Function Returning Ref Cursor
As explained in this answer, the output from a function returning a ref cursor can be displayed in the "Output Variables" window. The example from the answer used static SQL, but it's pretty easy to make it dynamic:
create or replace function refcursor_function return sys_refcursor as
c sys_refcursor;
begin
open c for 'select * from all_objects';
return c;
end;
/
The downside is that getting the results takes a few more clicks than a normal query, and the Output Variables grid is not nearly as powerful as the regular results grid. If you just need a window for viewing and copying and pasting, Output Variables is good enough. But it doesn't allow any advanced GUI features.
Polymorphic Table Function
Since Oracle 18c, you can create a polymorphic table function that accepts input and has variable output. You have to program how to handle the tables and columns, but if you just need simple pass-through logic it's not that difficult. See my answer here for an example of a query that returns every column from a table excluding specific columns. The results are "regular" SQL as far as any program knows, and will work in any grid GUI.
Oracle Data Cartridge
My open source program Method4 can run dynamic SQL in SQL. After you download and install the packages and types, you can write a SQL statement that generates another SQL statement. If you need to use PL/SQL to generate the query, you may need to use a PL/SQL WITH function. Like the polymorphic table function, the results look like normal SQL and will work in any grid.
select * from table(method4.dynamic_query(
q'[
--Query that builds another query.
select replace(
q'!
select * from #TABLE_NAME#
!', '#TABLE_NAME#', table_name) sql_statement
from
(
--Enter your script here that returns a table name to select from.
select 'ALL_USERS' table_name
from dual
)
]'
));
You may want to add some details about what exactly you're trying to do and why; that might help narrow down the possible solutions.
Is it possible to access the temp data created within a SQL Server cursor? I would like to set some conditions within the cursor but those depends on the data that the cursor has example:
Cursor declaration.....
if (#Column = (SELECT MAX(ID) from cursor_name/table where Rid = #Rid))
begin
....
I'm actually doing this using a table variable that is being read by the cursor but I wonder if there's a better way to achieve this, any suggestions?
Thanks
I have a requirement where-in I need to read a table (table name provided as input parameter of the SP), store the results in a temp table and then store the count of the read table into a variable. Please advise how can this be achieved. I have been able to read the table and its count using dynamic query but am not able to put the results in a temp table/ variable. 'Select' and 'Into' clauses do not seem to be working with 'Execute Immediate'. Thanks.
It is not very clear to me exactly what is being asked, but you should be able to execute a SELECT statement in the following manner:
CREATE PROCEDURE p1(IN tablename VARCHAR) AS
BEGIN
execute immediate 'SELECT * FROM ' || :tablename;
END;
Then the following statements create a table and call the procedure to retrieve the result:
create table T (i integer);
insert into T values (123);
The following would produce a result set with one row/column with the value 123:
CALL p1('T')
Please note that with this type of functionality, you need to be very careful not to allow any user-provided input to be given directly to a procedure that uses EXECUTE IMMEDIATE to avoid the possibility of SQL injection attacks.
Let's say sStorecode is: 00020
The following just executes the select statement to get the accountid at another database STORE in the table STOREINFO, for example connecting to p008081 (where 008 is the substring of the sStorecode and 081 is what I am joining below),
but I am getting errors for some reason (Invalid SQL Statement), can someone help?
EXECUTE IMMEDIATE 'select AccountID from STOREINFO#STORE.p'||substr(sSTORECODE,3,3)||'081';
Thanks in advance!
EXECUTE IMMEDIATE is a PL/SQL command. In PL/SQL, the result of a SELECT statement needs to go somewhere. But it your statement, you don't specify where it should go.
So if you expect a single row, you could write:
EXECUTE IMMEDIATE 'select AccountID from STOREINFO#STORE.p'||substr(sSTORECODE,3,3)||'081'
INTO l_account_id;
l_account_id is a local PL/SQL variable.
If you expect several row, you could use
EXECUTE IMMEDATE ... BULK COLLECT INTO l_account_tab;
l_account_tab is a PL/SQL collection variable.
Or if you want to work with cursors, you can write:
OPEN account_id_cv FOR 'select AccountID from STOREINFO#STORE.p'||substr(sSTORECODE,3,3)||'081';
account_id_cv is a REF CURSOR variable.
Seems like that should be something like this instead:
'select AccountID from STORE.STOREINFO WHERE sStorecode = ''p'||substr(sSTORECODE,3,3)||'081''';
I have a SQL query where I want to specify the names of the columns dynamically.
Let's say I have a table called TABLE_A, and it has a column by name ID. I was wondering if I could do something like:
SELECT (SELECT 'ID'
FROM DUAL)
FROM TABLE_A
Obviously this is not possible. Is there a better way to this?
SQL does not support dynamic column or table names -- you need to use dynamic SQL to get the functionality you want. Dynamic SQL means constructing a string, concatenating as necessary, before submitting the string (containing the query) to the database for interpretation.
Dynamic SQL is supported by most databases, but the syntax is often very different. Oracle provides:
EXECUTE IMMEDIATE
using an implicit cursor
This link provides examples of both.
Lest we forget Little Bobby Tables, dynamic SQL is an increased risk of SQL injection attacks...
You could use dynamic SQL if you are in a PL/SQL environment.
Build your SQL string as a VARCHAR2 before executing it.
DECLARE
v_sql VARCHAR2(4001);
v_column VARCHAR2(30) := 'whatever';
v_sql_result VARCHAR2(4001);
BEGIN
v_sql := 'SELECT '||v_column||' FROM table_a';
EXECUTE IMMEDIATE v_sql
INTO v_sql_result;
EXCEPTION
WHEN ...
THEN
...
END;
This will select the contents of column "whatever" into the v_sql_result.
Of course I ommitted the WHERE clause to ensure only one row was returned for this example but you can add that yourself or lookup how EXECUTE IMMEDIATE works in Oracle.
If you want a dynamic list of columns, you might be better off using dynamic sql. I try to avoid it whenever I can, but this is a prime example of when to use it.
example:
DECLARE #sqlQuery varchar(300)
SET #sqlQuery = 'select '
------ logic loop happens -----
SET #sqlQuery = #sqlQuery + 'columnname, '
------ end loop ------
SET #sqlQuery = #sqlQuery + ' from TABLE_A where '
exec(#sqlQuery)
It's at least a place to start for you.