SQLPlus conditional execution with variable from query - batch-file

I have a batch file which has many steps in it that will get executed one by one.
However, to be able to make it more flexible, I want to include a condition check in SQLPlus.
Something like, to get the conditional variables' value from a query first and store is in say v_variable. Then use it for some checks like
IF v_variable = 'Y' THEN
--DO SOME DDL
ELSE
--DO OTHER DDL
END IF
I have to repeat this block in many places in the batch file and I can't do it through a PL/SQL somehow.
I am trying to use this COLUMN command in SQLPlus but somehow not getting the variable value to get saved.
COLUMN VARIABLE1 NEW_VALUE V_VARIABLE1
SELECT PARAM_VAL AS VARIABLE1 FROM TABLE_T WHERE PARAM_TYPE = 'XYZ';
-- This query will only throw one record.
DEFINE V_VARIABLE1
Is that absolutely wrong? What do we do to see if the V_VARIABLE1 is getting the value coming from the query?
And even after I get it right I am clueless on the IF-ELSE part. Can anybody help here? I am interested in solution that works for SQLPlus.

sql*plus doesn't support flow control natively, so anything you can do here would fall somewhere between "workaround" and "hack". Some of possible options are:
Use PL/SQL block and run your DDL as dynamic SQL via execute
immediate or dbms_utility.execute_ddl_statement. Full access to
PL/SQL features, so most flexible in terms of flow control and
statement building, however harder to manage if you're deploying
something large.
Write a script file per if/else branch, get its name with something
like column/query trick you provided in your post, run it with
something like #&scriptname.
Use substitution variables that, when used properly, will comment
out some parts of your script. You can use Tanel Poder's snapper
utility script as example; notice &_IF_ substitution
variables there.
You can embed child script into parent script's pl/sql block. Like
this:
--
21:21:23 SQL> ho cat run.sql
begin
case '&1.' when 'A' then
#script_a
when 'B' then
#script_b
else
null;
end case;
end;
/
21:21:26 SQL> ho cat script_a.sql
dbms_output.put_line('this is a');
21:21:30 SQL> ho cat script_b.sql
dbms_output.put_line('this is b');
21:21:34 SQL> #run
Enter value for 1: A
this is a
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.02
21:21:37 SQL> #run B
this is b
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.03

I don't have any experience with SQLPlus. I am going to assume that you can redirect the output of your select command to a temp file. Assuming you only selected one column in 1 record you can then do something like this:
FOR /F "tokens=*" %%A IN ('FINDSTR /v "(" YourTempFile.txt) DO SET YourVariable=%%A
"tokens=*" is optional. It will remove leading spaces and save the rest of the string including spaces. May not be relevant depending on your data.
You may not need the 'FINDSTR /V "(" and the trailing ' either. I am assuming the output of SQLPlus will be similar to SQL and this would exclude the number of rows processed that gets reported by SQL. Anything is possible. If you can't make this work, post the contents of the temp file and we can make the necessary modifications.

Related

Procedure not running in toad asking for the variable

I'm using TOAD for Oracle. I'm trying to execute a stored procedure with two parameters - one IN and one OUT. It looks like this:
PROCEDURE get_stuff (
parm_1 IN VARCHAR2,
parm_2 OUT currefcursor)
In the SQL Editor window in TOAD, I've tried various things to no avail. I'm sure this is something simple that I'm missing, 'cause I've tried all sorts of things I've seen in other solutions here at Experts Exchange, but can't get past various errors. Here's what I think should work from what I've seen here:
var p1 VARCHAR2 := 'some text';
var p2 currefcursor;
EXEC get_stuff( :p1, :p2 );
When I run this, though, the SQL Editor pops up a window titled 'Variables' that appears to be looking for a value. No matter whether I put something in the 'Value' textbox or not, when I click OK, it says:
ORA-00900: invalid SQL statement
and highlights the 'var' in front of p1.
Please tell me what I'm missing!
Status Solved Priority Medium Security Public Views 21999
As the second parameter is OUT, you have to declare the variable which will accept that value. Here's how; I don't know what currefcursor type is - I guess you do.
declare
l_out currefcursor;
begin
get_stuff(:p1, l_out);
end;
/
A simple option to view the result would be this: put this code into the editor and run it as a script; the result will be displayed in the Script Output tab.
variable l_out currefcursor
exec get_stuff(:p1, :l_out);
print l_out
Or, you could even create a wrapper function which returns cursor, and then select from it:
create or replace function f_get_stuff(p1 in number)
return currefcursor
is
l_out currefcursor;
begin
get_stuff(p1, l_out);
return l_out;
end;
/
select f_get_stuff(:p1) from dual;
You can use Toad to execute without writing the execution harness yourself as well. Here is one method using the Schema Browser. Select your object and right-click > Execute.
You are presented with a dialog asking for your input parameters. Set your inputs and you can see the generated execution harness below. You can also use this generated code as an educational guide to see one method of writing the code yourself.
Click OK and your function/procedure is executed and results are shown.

Python & SQL - Python wont actually commit data to SQL DB

This is a 2 part question but Ill get to my first conundrum.
I have some code I'm just trying to test where I want Python to run a stored procedure with the required variables and it runs and even shows the new row. However, if I go into the DB and run a SELECT statement to show me the data, its not there. Its as if the DB blocked it or something strange.
This code WORKS if I run a select statement instead of this stored procedure. The stored procedure works and even when I run this code, Python will run the stored procedure and spit back the new row (complete with the new row number that's auto-generated due to the IDENTITY I have on the column)
import pyodbc
conn = pyodbc.connect('Driver={SQL Server};'
'Server=REPORT\INSTANCE;'
'UID=UserID;'
'PWD=Password;'
'Database=ReportDB;'
'Trusted_Connection=no;')
cursor = conn.cursor()
cursor.execute('EXEC [Schema].[Comments] \'2019-04-18 00:00:00.000\',\'Team\',\'1900-01-01 13:12:16.000\',\'testing this string\',\'username\'')
for row in cursor:
print(row)
Kind of lost here. Python will run the stored procedure (which I have set to run a select at the end of, to prove the data was committed) and Python shows that but I don't see it in the actual DB. That line is gone.
You can see here, the 470 is the ID Column (Identity, no null) and that's what it should be.
Notice that the most recent entry is still 469
Same Instance
Same DB
EDIT
I just noticed something in the Python. Each time I run the Python code, it runs the code and the stored procedure does the select at the end but each time I run it, the CommentsID increases by 1 (as it should) but its NOT remembering the previous ones inserted by Python. The only ones the SELECT statement pulls back in is the one I committed via SQL itself.
Notice here that the CommentsID (the first number in each line that starts with a 4) goes from 469 to 471. Yet I just had that image above that shows 470 - where did 470 go?!
Second part:
I'm having a hard time putting variables into that EXEC section of the code. I think I need to wrap it in single quotes which means I need to put \ in front of the quotes I need to stay for the SQL code. But when I do that and then try to run it, I cant get it to pull in the variables.
Here is what the SQL needs to be:
EXEC [schema].[Comments] 'Username'
In Python, I know I need it to be in single quotes but because the SQL code has quotes, you typically just put \ in front like this:
'EXEC [schema].[Comments] \'Username\''
That works. However, I then want username to pull from a variable, not be a string.

Replace is not working for weird character

I use UPDATE a SET GR_P = REPLACE(GR_P,'','') FROM mytable a to replace things.
But replace function is not working for below charter:
In Query analyzer it works but when I used SSIS Execute SQL task or OLEDB Source then it is giving me error:
No Connection manager is specified.
In Toad against Oracle (since that's one of your tags), I issued this (pressing ALT-12 to get the female symbol) and got 191 as a result. note selecting it back using CHR(191) shows an upside-down question mark though.
select ascii('♀') from dual;
Given that, this worked but it's Oracle syntax, your mileage may vary.
UPDATE mytable SET GR_P = REPLACE(GR_P, CHR(191));
Note if it does not work, that symbol could be for another control character. You may need to use a regular expression to eliminate all characters not in a-zA-Z0-9, etc. I suspect you'll need to update your tags to get a more accurate answer.
Maybe this info will help anyway. Please post back what you find out.

SQL Injection, ignore first select command

I am trying to build a scenario that would allow me to expose additional data from a server (for case-demo purposes). The server calls a vulnerable SQL code:
EXEC my_storeProc '12345'
where "12345" (not the single quotes) is the parameter. This performs a SELECT statement. I would like to eliminate this execution and instead call my own select statement, however the server side code will only accept the first select statement called, contained within the aforementioned EXEC call. Calling the second statement is easy:
EXEC my_storeProc '12345 ' select * from MySecondTable--
(the -- at the end will block the closing single quote added by the server to prevent errors). My problem is that although there are 2 select statements, the server will only parse the first one. Is there a way to cancel the first EXEC call without throwing an error so that the second one would be taken instead? Perhaps even a UNION but there isn't much I can do with only one variable open to exploit (variable being 12345 in this case).
You have to think of how it will be executed, specifically you want it called so it doesn't raise an exception and put the kabosh on the whole statement. You can't set the result to always true with a proc call, so there is no real way escape the proc. Instead, you'll want to slip a second command in, Your desired code looks like;
exec my_Storeproc '1234'; select * from mysecondtable
So we need to close the quotes, and make a new statement. That would mean the string with the insert needs to be;
1234'; select * from mysecondtable where 1 = '1
There is a flaw in this, whatever command you are executing is not being returned to the UI. To get the data you'll have to add a server connection to the second command.
To make the second command unnecessary you would have to inject code into the proc, which is a non starter since the proc is already complied and sql injection relies on confusing the compiler as to what is data and what is commands. For a more verbose explanation of that check out this answer:
https://security.stackexchange.com/a/25710

Script output to file when using SQL-Developer

I have a select query producing a big output and I want to execute it in sqldeveloper, and get all the results into a file.
Sql-developer does not allow a result bigger than 5000 lines, and I have 100 000 lines to fetch...
I know i could use SQL+, but let's assume I want to do this in sqldeveloper.
Instead of using Run Script (F5), use Run Statement (Ctrl+Enter). Run Statement fetches 50 records at a time and displays them as you scroll through the results...but you can save the entire output to a file by right-clicking over the results and selecting Export Data -> csv/html/etc.
I'm a newbie SQLDeveloper user, so if there is a better way please let me know.
This question is really old, but posting this so it might help someone with a similar issue.
You can store your query in a query.sql file and and run it as a script. Here is a sample query.sql:
spool "C:\path\query_result.txt";
select * from my_table;
spool off;
In oracle sql developer you can just run this script like this and you should be able to get the result in your query_result.txt file.
#"C:\Path\to\script.sql"
Yes you can increase the size of the Worksheet by change the setting Tool-->Preferences - >Database -> Worksheet -> Max rows to print in a script(depends on you).
Mike G answer will work if you only want the output of a single statement.
However, if you want the output of a whole sql script with several statements, SQL*Plus reports, and some other output formats, you can use the spool command the same way as it is used in SQL*Plus.

Resources