Can I display the result of dynamic SQL select statement in SQL Developer's grid? - sql

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.

Related

How to dynamically execute SQL in SAP IQ, to consume in Crystal Reports

Goal:
I have a stored procedure in SAP IQ that uses execute() to execute a dynamic SQL statement into a temp table, and then it selects from the table as the output.
Problem:
The proc returns the appropriate dataset just fine in my SQL client, but when I try to execute it in Crystal Reports, it does not return any columns, and instead returns a column named "expression". I believe this is Crystal's way of indicating that it couldn't interpret the result set.
Question:
What is the correct way to dynamically execute a query in IQ? Particularly in terms of executing the proc via Crystal Reports. I'm used to working in SAP ASE, and this is a procedure that I'm attempting to move from ASE to IQ.
Reproducible example:
/* Example proc that create a temp table with a dynamic value */
create or replace proc test_exec (
#num_value int
)
as
begin
-- Dynamically create the temp table with the requested column value
execute('select ' || #num_value || ' as column_1 into #temp')
-- Return the result
select column_1 from #temp
end
Output from the SQL client (correct):
exec test_exec 123
column_1
123
Output in Crystal Reports (does not return column_1):
This is likely due to a difference in the driver used to connect. The query tool is using a built in JDBC driver, while Crystal is using a different driver for its ODBC connection.
I cannot tinker the ODBC settings on this work computer, so I can't experiment with different settings to give a definitive answer of the cause.

Trying to get HANA Create function to work in ODBC (warning in hdbsql becomes error in ODBC)

I have the following function that we have working in SQL Server, in PostGreSQL, and a version of this working in Oracle (not with a SELECT INTO but using a ref cursor).
Our function in HANA will compile with warnings on the hdbsql command line, but when executed within an ODBC call, it throws an exception. The database I'm using for testing is (unfortunately) a Version 1 db.
CREATE OR REPLACE FUNCTION GETWFFIELD
(
IN TABLENAME VARCHAR,
IN FIELDNAME VARCHAR,
IN LANGCODE VARCHAR,
IN WORKID DECIMAL,
IN SUBWORKID DECIMAL,
IN TASKID DECIMAL,
IN DEFVAL VARCHAR
) RETURNS SQLResults NVARCHAR(2000)
AS
BEGIN
IF TASKID IS NULL THEN
SELECT TOP 1 Value
INTO SQLResults DEFAULT DEFVAL
FROM WML
WHERE TableName=TABLENAME
AND ColName=FIELDNAME
AND Key1=WORKID
AND Key2=SUBWORKID
AND LangCode=LANGCODE;
ELSE
SELECT TOP 1 Value
INTO SQLResults DEFAULT DEFVAL
FROM WML
WHERE TableName=TABLENAME
AND ColName=FIELDNAME
AND Key1=WORKID
AND Key2=SUBWORKID
AND Key3=TASKID
AND LangCode=LANGCODE;
END IF;
END;
I would have used a cursor but unlike Oracle, I couldn't find an example in HANA as to how to call one SQL or another plus that seems to be Dynamic SQL which HANA forbids in functions (but the above is allowed).
My issue with the above is that when I execute it in our GUI, it executes in ODBC not in a SQL console, and the warning becomes an error message:
E675217410:ODBC reported error.:[SAP AG][LIBODBCHDB SO][HDBODBC] General error; > 1347 Not recommended feature: Using SELECT INTO in Scalar UDF
Really there are two elements to this that I need:
the ability to have a slightly different query in HANA when the value TASKID is null or not null (i.e. if it's null, it's not part of the WHERE clause), and
that the query return the passed in default if no results are found.
Is there a way to get this to run in an ODBC call?
Thanks in advance
Do not use dynamic SQL until there's no really dynamic identifiers or dynamic code.
You write this query one time, but then such dynamic SQL will waste resources with every execution, so it is worth to invest more development time to have a single or copied static SQL.
What about answers:
Your statement can be reduced to single statement with ... and ( (:taskid is not null and Key3=:taskid) or :taskid is null) and no dynamic SQL. If you really need to have a dynamic SQL to return something, then you are limited to only scalar output for HANA 2.0 and no parameter binding at all (neither in, nor out) for HANA 1.0 (do not know if this works fine in 2.0).
This can be achieved with aggregation function on your value since aggregation function always return a value (null if no rows were passed where clause), If you want to have a single value with TOP (maybe you need a first row in some order), then you can wrap it into a subquery and then do a dummy aggregation on one row.
SELECT coalesce(max(Value), 'Your default value')
INTO SQLResults
FROM WML
WHERE ...
Or you may use exception handlers, but they are too bulky and with some not visually obvious error codes.
do begin
declare lv_str varchar(100);
begin
DECLARE EXIT HANDLER FOR SQL_ERROR_CODE 1299 /*no data found*/
lv_str := 'Default value';
select 10
into lv_str
from dummy
where 1 = 0;
end;
select :lv_str as res from dummy;
end;
| | RES |
+---+---------------+
| 1 | Default value |
What about the code: it is better to use colon in front of the variable not to mix it with table columns: if you'll have a typo, your query will evaluate, for example, LangCode=LANGCODE as always true for non-nulls and make the debug process hard.

PLSQL Execute Immediate with Dynamic Using

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

MySQL - Using stored procedure results to define an IN statement

I'd like to use a stored procedure to define the IN clause of a select statement.
This is (a simplified version of) what I'm trying to do:
SELECT *
FROM myTable
WHERE columnName IN (CALL myStoredProc)
myStoredProc performs some complicated logic in the database and returns a list of possible matching values for columnName. The statement above does not work obviously. The select statement may be performed in another stored procedure if that makes a difference.
Is this at all possible in mySQL?
What return type does your current stored procedure have? You are speaking of "a list", so TEXT?
Maybe there's an easier way, but one thing you can do (inside another stored procedure) is to build another query.
To do that, we need to work around two limitations of MySQL: a) To execute dynamic SQL inside a stored procedure, it needs to be a prepared statement. b) Prepared statements can only be created out of user variables. So the complete SQL is:
SET #the_list = myStoredProc();
SET #the_query = CONCAT('SELECT * FROM myTable WHERE columnName IN (' , #the_list , ')');
PREPARE the_statement FROM #the_query;
EXECUTE the_statement;
If you're talking about returning a result set from a stored routine and then using it as table, that is not possible. You need to make a temporary table to work around this limitation.

Debug SQL in pgAdmin when SQL contains variables

In SQL Server I could copy sql code out of an application and paste it into SSMS, declare & assign vars that exist in the sql and run. yay great debugging scenario.
E.g. (please note I am rusty and syntax may be incorrect):
declare #x as varchar(10)
set #x = 'abc'
select * from sometable where somefield = #x
I want to do something similar with Postgres in pgAdmin (or another postgres tool, any recommendations?) where I can just drop my SQL (params & all) into something that will run against Postgres DB.
I realise you can create pgscript, but it doesn't appear to be very good, for example, if I do the equivalent of above, it doesn't put the single quotes around the value in #x, nor does it let me by doubling them up and you don't get a table out after - only text...
Currently I have a piece of SQL someone has written that has 3 unique variables in it which are used around 6 times each...
So the question is how do other people debug SQL efficiently, preferably in a similar fashion to my SQL Server days.
You can achieve this using the PREPARE, EXECUTE, DEALLOCATE commands for handling statements, which is really what we are talking about here.
For example:
PREPARE test AS SELECT * FROM users WHERE first_name = $1;
EXECUTE test ('paul');
DEALLOCATE test;
Perhaps not as graphical as some may like, but certainly workable.
I would give a shot at writing a SQL function that wraps your query. It can be something as simple as
CREATE OR REPLACE FUNCTION my_function(integer, integer)
RETURNS integer
AS
$$
SELECT $1 + $2;
$$
LANGUAGE SQL;
SELECT my_function(1, 2);
I would do this instead of a PREPARE since it will be simpler to update it. Depending on how complex the function is, you might want to also look at some of the other PL's in Postgres.
SQL procs are notoriously hard to debug. My lame but practical solution has been to write log messages to a log table, like this (please excuse syntax issues):
create table log_message (
log_timestamp timestamp not null default current_timestamp,
message varchar(1000)
);
then add lines to your stored proc like:
insert into log_message (message) values ("The value of x is " || #x);
Then after a run:
select * from log_message order by 1;
It's not pretty, but works in every DB.