TOAD thinks &String as bind variable - sql

I am developing some ETL with Oracle Data Integrator and sometimes test parts of my code by TOAD. Today I had a problem with TOAD I had a line like
AND column_value like('DEV&PROD')
when I tried to run the SQL which includes filter above, TOAD ask for the value of PROD, it thought like PROD is a bind or substitution variable. Is there any option in TOAD settings to turn this feature of. I am using bind variable with a column (:), and my data includes & so I need to use it.
This code works in ODI perfectly, I only need a solution for TOAD. Thanks in advance.

1) start your script with set define off; (and run whole script with F5 key)
or
2) use 'DEV&'||'PROD' instead of 'DEV&PROD'
or
3) set another prefix symbol for variables
set define ~;
select 'drag&drop', ~column_name from ~table_name;
(you will be prompted for column_name and table_name, but not for 'drop')

In addition - will work in any tool or SQL prompt:
SELECT ('DEV'||'&'||'PROD') val FROM dual
/
-- Q-quote operator introduced in Oracle 10g --
SELECT 'DEV' || q'[&]'||'PROD' AS val FROM dual
/
Using Egor's or my examples - copy/paste, enter 1 for :bind_var :
SELECT 'DEV&'||'PROD' val FROM dual
WHERE :bind_var = 1
/

Related

SAP HANA SQLScript in DBeaver

I would like to ask if anyone has any idea/ know how to use SAP HANA SQLScript in DBeaver.
Since SAP HANA supports some very useful features such as table variables etc, I would like to run following code (just a quick example):
do BEGIN
DECLARE lv_id INT;
lv_id = 100;
lt_test = SELECT id
FROM some_table
WHERE ref_id < :lv_id;
SELECT * FROM some_other_table
WHERE from_id IN (SELECT id FROM :lt_test); END;
but unfortunately it will give some error messages
sql syntax error: incorrect syntax near "NULL": line 13 col 35 (at pos 174)
Does anyone know if there is anything that can be done so this code will work in DBeaver without the need of going into SAP Web IDE or HANA Studio all the time?
Maybe someone also knows any other good IDE with features like code completion, etc., for SQL that works well with HANA (other than Web IDE and HANA Studio)...
The "trick" here is to select the correct handling of bind parameters in DBeaver.
When a SQL command with strings that look like bind parameters should be executed, DBeaver presents a dialogue window:
In this window, one can specify how the bind variables should be handled.
As the SQLScript variables are not bind variables (i.e. the client does not bind values to them) the correct selection in this window is to IGNORE the bind variables.

SQL where clause parameterization

I am trying to parameterize certain where clauses to standardized my Postgres SQL scripts for DB monitoring. But have not found a solution that will allow me to have the following script run successfully
variablename = "2021-04-08 00:00:00"
select * from table1
where log_date > variablename;
select * from table2
where log_date > variablename;
Ideally, I would be able to run each script separately, but being able to find/replace the variable line would go a long way for productivity.
Edit: I am currently using DBeaver to run my scripts
To do this in DBeaver I figured out you can use Dynamic Parameter Bindings feature.
https://github.com/dbeaver/dbeaver/wiki/SQL-Execution#dynamic-parameter-bindings
Here is a quick visual demo of how to use it:
https://twitter.com/dbeaver_news/status/1085222860841512960?lang=en
select * from table1
where log_date > :variablename;
When executing the query DBeaver will prompt you for the value desired and remember it when running another query.

Define a VIEW in Oracle without using CREATE

I do not have sufficient privileges to use a CREATE statement, I can only SELECT. I have a script that has three distinct parts and calculations that need to run and each one references the same complicated WITH statement selection that redundantly clutters the code and is a pain to maintain in three separate locations.
I have tried creating temp tables and views, but again, privileges do not support. Is there a way using either SQL or PL/SQL syntax to define my WITH statement ONCE without using CREATE, and then reference it like I would any other table? Example:
--Define the temp table
WITH tempview AS (SELECT .... FROM ...);
--First query
SELECT ... FROM tempview;
/
--Second query
SELECT ... FROM tempview;
/
--Third query
SELECT ... FROM tempview;
/
Getting the correct permissions and creating permanent objects is the best approach. It sounds like this view would only be used in a single script, which doesn't necessarily make it any less valid to create it, but you might find it harder to justify depending on your DBA and policies. It's certainly worth trying that approach, as #DCookie suggested.
If that fails then there may be hacky workarounds, depending on the client you will run this script in.
For instance, in SQL*Plus it's possible to abuse substitution variables to get something close to what you describe. This uses the define command to create a substitution variable that contains the 'view' query, and then uses that variable inside a WITH clause. (You can't replace the entire with like this, but it's maybe clearer like this anyway). I'm used a trivial dummy query:
define tempview_query = 'SELECT * -
FROM dual -
UNION ALL -
SELECT * -
FROM dual'
WITH tempview AS (&tempview_query)
SELECT * FROM tempview;
WITH tempview AS (&tempview_query)
SELECT * FROM tempview;
When the script is run the output produced is:
D
-
X
X
2 rows selected.
D
-
X
X
2 rows selected.
I've also executed set verify off to hide the substitutions, but turning it on might be instructive to see what's happening.
Notice the dashes at the end of each line of the query; that's the continuation character, and as the define docs mention:
If the value of a defined variable extends over multiple lines (using the SQL*Plus command continuation character), SQL*Plus replaces each continuation character and carriage return with a space.
so the 'new' query shown by set verify on will have your entire view query on a single line (if you display it). It's feasible that with a long enough query you'd hit some line length limit but hopefully you won't reach that point (except you did; see below).
You can do the same thing in SQL Developer, but there the continuation needs to use two dashes, so:
define tempview_query = 'SELECT * --
FROM dual --
UNION ALL --
SELECT * --
FROM dual'
except it isn't quite the same as the continuation in SQL*Plus; here the define has to end with a dash, but it is not replaced in the way the SQL*Plus docs describe - so with a single dash the define works but the query ends up invalid. (At least in 4.2.0; possibly a bug...) By using two dashes the multi-line define still works, the dashes remain part of the query, but they're treated as comment markers; so they make the substituted query look odd (again, if you display it) but don't stop it working. You won't notice with set verify off unless someone looks in v$sql.
If your query exceeds 240 characters - which is rather likely unless it's trivial enough to repeat anyway - you'll hit something like:
string beginning "'SELECT * ..." is too long. maximum size is 240 characters.
Both SQL*Plus and SQL Developer allow you to set a substitution variable from a query, using the column ... new_value command:
column tempalias new_value tempview_query
set termout off
select q'[SELECT *
FROM dual
UNION ALL
SELECT *
FROM dual]'
FROM dual;
set termout on
The query selects the text of your view query as a string; I've used the alternative quoting mechanism, with [] as the delimiters, so you don't have to escape any single quotes in the view query. (You need to pick a delimiter that can't appear in the query too, of course). Also note that you don't need the line continuation character any more.
The text literal that query generates is aliased as tempalias. The column command sets the tempview_query substitution variable to whatever that aliased column expression contains. Using the substitution variable is then the same as in the previous examples.
WITH tempview AS (&tempview_query)
SELECT * FROM tempview;
The set termout lines just hide that generating query; you can temporarily omit the off line to see what the query produces, and that it does exactly match the view query you expected.
Other clients might have similar mechanisms, but those are the only two I'm really familiar with. I should probably also reiterate that this is a bit of a hack, and not something I'd necessarily recommend...
Another trick with SQL*Plus is to import code from a second SQL script. You can do this with the # command (making sure to put the # at the very start of a line), e.g.:
tempview.sql
WITH tempview AS (SELECT .... FROM ...)
(notice there is no ending semicolon ; here, and make sure you either don't have a blank line at the end of the file or set sqlblanklines on)
main.sql
--First query
#tempview.sql
SELECT ... FROM tempview
/
--Second query
#tempview.sql
SELECT ... FROM tempview
/
--Third query
#tempview.sql
SELECT ... FROM tempview
/

Using Dynamic Variables in Oracle SQL Developer

Trying to setup a WHILE LOOP in Oracle SQL Developer but I'm having a lot of trouble trying to set/define a variable. I'm used to working in PHP where I would declare this on my PHP scripts.
Here is what I have below. The script is unfinished I am basically going to have it loop through weeks when it is done.
VARIABLE MYDateVar2 varchar2(40);
EXEC :MYDateVar2 := '01-JAN-14';
select customer_name,
sum(CASE when to_char(to_date(PLANNED_SHIP_DATE), 'WW') = 40 then (REVISED_QTY_DUE - QTY_SHIPPED) * SALE_UNIT_PRICE end) as Wk40
from customer_order_join
where planned_ship_date >= :MYDateVar2
group by customer_name;
So I am having trouble basically placing the variable 'MYDateVar2' back into the script. I've tried using ## and : before but Oralce SQL Developer keeps prompting me for values. I also know I should probably set the varchar to be DATE but that should be fine for now.
Can someone please let me know how I properly insert a variable into the script? Thanks!
What you're doing is fine, as long as you tell SQL Developer to run the whole script, not just the select statement; you need to Run Script (F5), rather than Run Statement (Ctrl+Enter). If it runs the statement stand-alone then it will always prompt for the bind variable value.
Not directly relevant, but... presumably you've used a date format that is valid for your client's NLS settings, but you shouldn't rely on that; it's safer to always explicitly set the format:
where planned_ship_date >= to_date(:MYDateVar2, 'DD-MON-RR')
If you're going to loop, though, then you need to be writing PL/SQL, so you might as well declare the variable inside the block rather than at client level, unless you want to pass the same value into multiple blocks or stored procedure calls.

Parse Oracle Query using perl

I have to perform lexical analysis on the oracle query and separate the query to various parts (based on the clauses)in perl. For example,Consider :
Select deleteddate,deletedby from temptable where id = 10;
I need to print
select : deleteddate , deletedby
from : temptable
where : id = 10
I used this code snippet :
my $parser= SQL::Statement->new();
$parser->{PrinteError}=1;
my $query = SQL::Statement->new("select deleteddate,deletedby from temptable where id =10",$parser);
my #columns = $query->columns();
print $columns[0]->name();
Though this prints deleteddate, this fails when i give a subquery inside the select clause:
Select deleteddate,deletedby,(select 1+1 from dual) from temptable where id = 10;
Can you please point me in the correct direction.
Thanks.
It looks to be a limitation of that package; it seems to be a general purpose parser and not something that can understand advanced features like subqueries or Oracle-specific constructs like "from dual".
What are the constraints of your system? If python is an option it looks like this is a more fully-featured library:
http://code.google.com/p/python-sqlparse/
The other option would be to use the actual Oracle database, if that's an option. You would:
use the DBI and DBD::Oracle modules to create a connection to Oracle & get a database handle,
create a statement handle by calling prepare() on the database handle using your query,
execute the query (there may be an option in Oracle to execute in "test only" or "parse only" mode),
examine the statement handle (such as the NAMES_hash property) to get the column names.
Otherwise it seems the SQL::Statement module unfortunately just isn't up to the task...