How to put a SELECT from Oracle into a bash variable? - oracle

I try to save the output of an Oracle SELECT command into a bash variable.
I tried the following lines but it didn't work really well...
ACCESS_SQL=`{
sqlplus << EOF
${USER}/${PASSWORD}#DB
set head off;
set feedback off;
set pagesize 5000;
set linesize 30000;
set serveroutput on;
DECLARE
data varchar(5000);
BEGIN
select ACCESS_ID, PROFILE_ID, START_DATE, END_DATE, PLATFORM, ACCESS_TYPE, PERM_FLAG, ACTIVE_FLAG into data from uam.access_list where USER_ID='${USER_ID}';
dbms_output.put_line(data);
END;
/
exit;
EOF
}`
The error statement I get is :
SQL> SQL> SQL> SQL> SQL> SQL> 2 3 4 5 6 7 select ACCESS_ID, PROFILE_ID, START_DATE, END_DATE, PLATFORM, ACCESS_TYPE, PERM_FLAG, ACTIVE_FLAG into data from uam.access_list where USER_ID='PZ230';
*
ERROR at line 4:
ORA-06550: line 4, column 110:
PL/SQL: ORA-00947: not enough values
ORA-06550: line 4, column 2:
PL/SQL: SQL Statement ignored
I was wondering if using a varchar is the right thing to do...

You don't need to select into a variable and then use dbms_output.put_line to print it out. (Your select into statement won't work anyway, because you can't select multiple columns into a single data variable.)
Instead, do it like this:
data=$(sqlplus -S ${USER}/${PASSWORD} << EOF
set head off
set feedback off
set pagesize 5000
set linesize 30000
select ACCESS_ID, PROFILE_ID, START_DATE, END_DATE, PLATFORM, ACCESS_TYPE, PERM_FLAG, ACTIVE_FLAG from uam.access_list where USER_ID='${USER_ID}';
exit
EOF)
echo "$data"

Related

pl/sql if statement failing on incorrect if condition

apologies if this is covered elsewhere, i'm not sure what to search for. I'm having trouble with a pl/sql block.
The issue is with the IF statement below. Even when the condition (r) is not met, the script bottoms out as it attempts to run the block anyway.
I have encountered similar issues before, and resolved by putting select statements into variables and then executing the variables, however i can't get that to work in this instance. Has anyone seen this before, and any idea on how to resolve?
sqlplus -s xxx << EOSQL
set serveroutput on feedback on termout on
DECLARE
r number;
BEGIN
SELECT count(*) INTO r from sys.dba_audit_mgmt_config_params WHERE AUDIT_TRAIL = 'UNIFIED AUDIT TRAIL';
IF (r > 0) THEN
dbms_output.put_line('-- UNIFIED_AUDIT_TRAIL is in use, setting timestamp and purging');
DBMS_AUDIT_MGMT.set_last_archive_timestamp(
audit_trail_type => DBMS_AUDIT_MGMT.AUDIT_TRAIL_UNIFIED,
last_archive_time => SYSTIMESTAMP-30);
DBMS_AUDIT_MGMT.clean_audit_trail(
audit_trail_type => DBMS_AUDIT_MGMT.AUDIT_TRAIL_UNIFIED,
use_last_arch_timestamp => TRUE);
ELSE
dbms_output.put_line('-- UNIFIED_AUDIT_TRAIL not in use, skipping');
END IF;
END;
/
EOSQL
Another example of this can be seen below, this time using a SELECT statement to highlight the issue, the table RANDOMTABLE does not exist purposfully to highlight the issue.
sqlplus -s xxx << EOSQL
set serveroutput on feedback on termout on
DECLARE
r number := 0;
s varchar(200);
BEGIN
IF (r > 0) THEN
dbms_output.put_line('-- UNIFIED_AUDIT_TRAIL is in use, setting timestamp and purging');
select count(*) into s from randomtable where object_name = 'BANANAS';
dbms_output.put_line(s);
ELSE
dbms_output.put_line('-- UNIFIED_AUDIT_TRAIL not in use, skipping');
END IF;
END;
/
EOSQL
Which fails with:
DATABASE:/apps/ora/home> ./test1.sh
select count(*) into s from randomtable where object_name = 'BANANAS';
*
ERROR at line 7:
ORA-06550: line 7, column 41:
PL/SQL: ORA-00942: table or view does not exist
ORA-06550: line 7, column 13:
PL/SQL: SQL Statement ignored
And finally, the below works as expected, returning the ELSE block output. This time the table definitely DOES exist.
sqlplus -s '/ as sysdba' << EOSQL
set serveroutput on feedback on termout on
DECLARE
r number := 0;
s varchar(200);
BEGIN
IF (r > 0) THEN
dbms_output.put_line('-- UNIFIED_AUDIT_TRAIL is in use, setting timestamp and purging');
select count(*) into s from dba_objects where object_name = 'BANANAS';
dbms_output.put_line(s);
ELSE
dbms_output.put_line('-- UNIFIED_AUDIT_TRAIL not in use, skipping');
END IF;
END;
/
EOSQL

Adding extra data/information to filename using spool in sqlplus

I'm trying to achieve the below requirements in the filename being exported as csv
FILENAME: filename_yyyymmdd_nnnnnn_xxxxxx.csv
where
yyyymmdd = Datestamp on when the Account file was generated
nnnnnn = 6-byte random generated batch ID
xxxxxx = 6-byte zero-padded string that contains the number of records in the file
So far, I have the below query saved as a script which I run on sqlplus.
set head off;
set feedback off;
set term off;
set pagesize 0;
set linesize 3000;
set trimspool on;
set colsep ,;
set verify off;
set echo off;
ALTER SESSION SET NLS_DATE_FORMAT= 'MM-DD-YYYY';
whenever sqlerror exit sql.sqlcode;
whenever oserror exit failure;
column date_stamp new_value sys_date noprint
column rnd_num new_value random noprint
column row_count new_value rc noprint
select to_char(sysdate,'mmddYYYY') date_stamp
from dual;
select lpad(round(dbms_random.value(1,999999)),6,'0') rnd_num from dual;
/* select count(*) as row_count
from table a, table b join on a.id = b=id where condition; */
spool filepath.&sys_date..&random..&rc..&1..csv
select statement fetching the actual data;
spool off;
exit;
The problem is:
I am able to generate the random no,but not able to add record count (xxxxxx part of the filename requirement). When the part commented is uncommented and run, the sql script runs but no file is generated. When it is run with the "select count(*)" part as commented, the file is generated as expected, has the random no bit(nnnnnn) but doesn't have the no of records(xxxxxx), obviously because it is commented out. How to include the no of records in the filename as well?
So, with enough reading around the web, I found the solution. The row_count for some reason in my query was returning with a 5 empty spaces padded value then the actual row_count. Posting the answer below:
set head off;
set feedback off;
set term off;
set pagesize 0;
set linesize 3000;
set trimspool on;
set colsep ,;
set verify off;
set echo off;
ALTER SESSION SET NLS_DATE_FORMAT= 'MM-DD-YYYY';
whenever sqlerror exit sql.sqlcode;
whenever oserror exit failure;
column date_stamp new_value sys_date noprint
column rnd_num new_value random noprint
column row_count new_value rc noprint
select to_char(sysdate,'mmddYYYY') date_stamp
from dual;
select lpad(round(dbms_random.value(1,999999)),6,'0') rnd_num from dual;
select row_count from (select trim(count(*)) as row_count
from table a ...;
spool filepath.&sys_date..&random..&rc..&1..csv
select statement fetching the actual data;
spool off;
exit;

Is there any PL/SQL script to modify column value of each table in each schema of Oracle Database

I have written pl/sql code to modify column values in a table of one schema. But I need to execute the same script in each table of each schema. I will take the list of the table name, column name from spreadsheet.
define schema_name = 'D';
define hours_offset = '(-3/24)';
set echo off;
set timi off;
set heading off;
set feedback off;
set linesize 250;
spool convert_01.sql
select 'set echo on;' from dual;
select 'set timi on;' from dual;
select 'set heading on;' from dual;
select 'set feedback on;' from dual;
select 'set linesize 250;' from dual;
select 'spool convert_01.log;' from dual;
select 'update '||owner||'.'||table_name||' set '||column_name||'
='||column_name||' + &hours_offset;'
from dba_tab_columns where owner = '&schema_name' and
(
data_type = 'DATE' or
data_type like 'TIMESTAMP%'
) and
data_type not like 'TIMESTAMP%WITH TIME ZONE'
order by owner, table_name, column_name;
select 'spool off;' from dual;
spool off;
I need to execute the same script in each table of each schema
That's most probably not true. There are users (schemas) you shouldn't modify at all, e.g. SYS, SYSTEM, CTXSYS, APEX180200 and such.
Therefore, you'd rather collect list of users you want to skip (or the ones you want to affect; it's up to you). That list would then be used instead of '&schema_name'.
A simple option is to store list of users into a table and use its contents as a subquery in your current script.
Unrelated, but:
I have written pl/sql code ...
Nope; what you wrote is a pure SQL script readable by SQL*Plus (and, possibly, some other tools which understand commands you used).

oracle alter sequence by shell script & sqlplus

I'm working on altering sequence through sqlplus in a shell script.
What I'm about to do is to get the max seq_no of the table, set the value in v_increment_num, and increase the sequence by v_increment_num. But it gets an error when alter statement runs.
The script is like below.
echo start load_my_adm_user.sh
sqlplus myId/myPassword <<EOF
set echo on
set time on
set timing on
set serveroutput on
spool TB_MY_ADM_USER.log
var v_increment_num varchar2(1000);
SELECT MAX(SEQ_NO) INTO :v_increment_num FROM TB_MY_ADM_USER;
alter sequence mydb.SQ_ADM_USER increment by v_increment_num;
select mydb.SQ_ADM_USER.nextval from dual;
alter sequence mydb.SQ_ADM_USER increment by 1;
spool off
EOF
exit
and the running result(TB_MY_ADM_USER.log) is like:
07:01:23 SQL> SELECT MAX(SEQ_NO) INTO :v_increment_num FROM TB_MY_ADM_USER;
MAX(SEQ_NO)
-----------
4
Elapsed: 00:00:00.00
07:01:23 SQL>
07:01:23 SQL> alter sequence mydb.SQ_ADM_USER increment by v_increment_num;
alter sequence mydb.SQ_ADM_USER increment by v_increment_num
*
ERROR at line 1:
ORA-01722: invalid number
Elapsed: 00:00:00.00
07:01:23 SQL>
07:01:23 SQL> select mydb.SQ_ADM_USER.nextval from dual;
NEXTVAL
----------
19
Elapsed: 00:00:00.02
07:01:23 SQL> alter sequence mydb.SQ_ADM_USER increment by 1;
Sequence altered.
Elapsed: 00:00:00.02
What exactly am I doing wrong?
Thanks in advance.
You have almost everything correct, just have to remember that DDL statements, i.e. alter sequence, too, don't work with bind variables. Which, I mean a bind variable, is what your v_increment_num is.
If SQL*Plus is what you're going to use, then try it with its own substitution "variables", i.e. the "ampersand"-variables...
echo start load_my_adm_user.sh
sqlplus myId/myPassword <<EOF
set echo on
set time on
set timing on
set serveroutput on
spool TB_MY_ADM_USER.log
-- do not do...
-- var v_increment_num varchar2(1000);
-- do instead...
column max_seq_no new_val v_increment_num
-- note: this makes all MAX_SEQ_NO column values from all subsequent SELECTs to be stored in the &V_INCREMENT_NUM variable
-- do not do...
-- SELECT MAX(SEQ_NO) INTO :v_increment_num FROM TB_MY_ADM_USER;
-- do instead...
SELECT MAX(SEQ_NO) as max_seq_no FROM TB_MY_ADM_USER;
-- note: at this point, you will have your MAX(SEQ_NO) value stored in your &V_INCREMENT_NUM variable
-- do not do...
-- alter sequence mydb.SQ_ADM_USER increment by v_increment_num;
-- do instead...
alter sequence mydb.SQ_ADM_USER increment by &v_increment_num;
select mydb.SQ_ADM_USER.nextval from dual;
alter sequence mydb.SQ_ADM_USER increment by 1;
spool off
EOF
exit
Note: I did not try this particular code, just wrote it here directly, so it may not be working at the first attempt, but we'll get that eventuality sorted out later.

sql syntax is missing & error handling

I want to handle errors in sql script, I have put some statements for it.But its not working. I think i am missing begin & end statements position.
here is my sql script please correct it.
set colsep ',';
set trimout off;
set pagesize 0;
set trimspool off;
set feedback off;
set heading off;
set heading off;
set verify off;
set errorlogging on;
var envame varchar2(20)
exec :envame := '&1'
set errorlogging on;
spool C:\UsersDesktop\batch\pres64.csv app
begin
select '&&1', user_name, user_id from employee where designation = 'manager';
exception
when others then
dbms_output.put_line('ERROR');
end;
exit;
this gives output as
12
13
14
15
.
.
please suggest modifications..
spool C:\UsersDesktop\batch\pres64.csv app
begin
select '&&1', user_name, user_id from employee where designation = 'manager';
exception when others then
dbms_output.put_line('ERROR');
You have mixed SQL*Plus with PL/SQL exception handling. SPOOL is a SQL*Plus command. It won't work if you use the BEGIN-END PL/SQL block.
Since you are using SQL*Plus, I would strongly recommend to use the new SQL*Plus error logging feature rather doing it in PL/SQL. It was introduced in release 11.1.
I have written an article about it here http://lalitkumarb.wordpress.com/2014/01/21/sqlplus-error-logging-new-feature-release-11-1/
For example,
SQL> set errorlogging on
SQL> show errorlogging
errorlogging is ON TABLE LALIT.SPERRORLOG
SQL> desc sperrorlog
Name Null? Type
----------------------------------------- -------- -----------------------
USERNAME VARCHAR2(256)
TIMESTAMP TIMESTAMP(6)
SCRIPT CLOB
IDENTIFIER VARCHAR2(256)
MESSAGE CLOB
STATEMENT CLOB
SQL> selct * from dual;
SP2-0734: unknown command beginning "selct * fr..." - rest of line ignored.
SQL>
So, the above SP2 error is now logged in the sperrorlog table.
SQL> select timestamp, username, statement, message from sperrorlog;
TIMESTAMP USERNAME STATEMENT MESSAGE
------------------------------ -------- -------------------- --------------------------------------------------
06-APR-15 10.42.49.000000 AM LALIT selct * from dual; SP2-0734: unknown command beginning "selct * fr...
" - rest of line ignored.
SQL>

Resources