oracle alter sequence by shell script & sqlplus - oracle

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.

Related

How to replace specified substring with another string for the complete session

I want to create a csv file using sqlplus command for multiple tables as below and it will be called inside shell script.
sqlplus Username/Password#SSD << EOF
set colsep ,
set pagesize 0
set trimspool on
set linesize 32768
set echo off
spool $TABLE.csv;
SELECT * FROM $TABLE;
spool off;
EXIT;
EOF
My Data can also contain a comma(,). if any column data contains comma I want to replace it with "\,".
How can I replace comma for multiple tables and multiple columns? I checked replace function but I don't want to mention column names
As long as you are on SQL Plus 12.2 or above, you should be able to get close to your needs with SET MARKUP
SQL> create table t ( x varchar2(10), y varchar2(10));
Table created.
SQL> insert into t values ('Hello','There');
1 row created.
SQL> insert into t values ('He,llo','The,re');
1 row created.
SQL> set markup csv on
SQL> select * from t;
"X","Y"
"Hello","There"
"He,llo","The,re"
SQL> set markup csv on quote off
SQL> select * from t;
X,Y
Hello,There
He,llo,The,re
You don't get the escape, but if you are enclosing things in quotes, then perhaps that won't matter.

Instead of trigger with Oracle sequence

I have some old applications (legacy applications) which uses their own MAX NUMBER table. The problem is that we cannot modify and release all the applications at the same time. And therefore, we would like to do it in phases.
I came up with the following proposal. But, I do not know why Oracle executes the view's select query when I am executing the update statement.
Current usage:
-- Update the max number table
Update Sysadm.DummyTable
Set MaxNumber = MaxNumber + 1;
-- An application needs to select current value from the MaxNumber table.
Select * From Sysadm.DummyTable;
Proposed solution:
CREATE SEQUENCE SYSADM.SEQ_DummyTable START WITH 12345 INCREMENT BY 1;
--- Common function ---
--- The following function will get the current sequence number of the Oracle sequence across all the sessions.
CREATE OR REPLACE FUNCTION Sysadm.GetCurrValue(sLSeqName VARCHAR)
RETURN NUMBER
AS nLDummy NUMBER;
BEGIN
if (sLSeqName = 'SEQ_DUMMYTABLE') Then
SELECT SEQ_DUMMYTABLE.CURRVAL Into nLDummy FROM DUAL;
Else
Return null;
End If;
RETURN(nLDummy);
END;
/
--- The existing DummyTable table will be dropped and DummyTable (exactly with the same name including its structure) view will be created.
Create or Replace View Sysadm.DummyTable (MAXNUMBER)
As
Select sysadm.GetCurrValue('SEQ_DUMMYTABLE') As MAXNUMBER From Sysadm.ABC Where RowNum = 1;
--- The following trigger will get executed when the application tried to update the DummyTable table. This trigger will get executed instead of update statement from the application.
Create Or Replace Trigger Sysadm.TR_DummyTable
Instead of UPDATE ON Sysadm.DummyTable
Declare
nLDummy NUMBER;
Begin
SELECT SEQ_DUMMYTABLE.NEXTVAL Into nLDummy FROM DUAL;
End;
/
I have Instead of trigger on the view. However, When I am trying to execute the following update query I get an error message.
-- Update the max number table
Update Sysadm.DummyTable
Set MaxNumber = MaxNumber + 1;
ORA error message:
Error starting at line : 1 in command -
Update Sysadm.DUMMYTABLE Set MaxNumber = MaxNumber + 1
Error report -
SQL Error: ORA-08002: sequence SEQ_DUMMYTABLE.CURRVAL is not yet defined in this session
ORA-06512: at "SYSADM.GETCURRVALUE", line 10
08002. 00000 - "sequence %s.CURRVAL is not yet defined in this session"
*Cause: sequence CURRVAL has been selected before sequence NEXTVAL
*Action: select NEXTVAL from the sequence before selecting CURRVAL
As Oracle told you: you can't fetch currval if you didn't fetch from the sequence within this session, and you do that by selecting nextval. For example:
SQL> create sequence seqa;
Sequence created.
This doesn't work - you already know that, you hit the error already:
SQL> select seqa.currval from dual;
select seqa.currval from dual
*
ERROR at line 1:
ORA-08002: sequence SEQA.CURRVAL is not yet defined in this session
So: nextval first, currval next (if you need it):
SQL> select seqa.nextval from dual;
NEXTVAL
----------
1
SQL> select seqa.currval from dual;
CURRVAL
----------
1
SQL>
In your case, it means that this would look like
if (sLSeqName = 'SEQ_DUMMYTABLE') Then
SELECT SEQ_DUMMYTABLE.NEXTVAL Into nLDummy FROM DUAL;
Else -------
By just changing the function we can get it to work. This will fix the concurrency issue as well:
--- The following function will get the current sequence number of the Oracle sequence across all the sessions.
CREATE OR REPLACE FUNCTION Sysadm.GetCurrValue(sLSeqName VARCHAR)
RETURN NUMBER
AS nLDummy NUMBER;
BEGIN
if (sLSeqName = 'SEQ_DUMMYTABLE') Then
SELECT SEQ_DUMMYTABLE.CURRVAL Into nLDummy FROM DUAL;
Else
Return null;
End If;
RETURN(nLDummy);
EXCEPTION
WHEN OTHERS THEN
RETURN NULL;
END;
/

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>

How to pass a variable from a Windows Batch File to SQL*Plus

I want to pass a variable from a Windows Batch File to SQLPLUS,
while displaying sql result batch variable should print along with the sql result.
Result should be stored in csv file.
How can I do that.
This is possible in Unix(shell script) how can I do that in Windows(batch script).
I want to pass a variable from a Windows Batch File to SQLPLUS
Just pass it as an argument to the SQL script. And use substitution variables in the same order that of the arguments list &1 &2...
For example,
mybatchfile.BAT:
sqlplus -S username/password#sid
#c:\sql\mysqlfile.sql 1000 7369
mysqlfile.SQL:
update emp set sal = &1 where empno = &2
while displaying sql result batch variable should print along with the sql result.
To display the variables which you pass as arguments to the SQL script, first you need to define the bind variables, then assign the argument value and then print the value.
For example,
I have test.sql:
For NUMBER type
-- define the bind variable
var sal number
-- assign the first argument's value
exec :sal := &1
-- display the value
print :sal
-- define the bind variable
var empno number
-- assign the second argument's value
exec :empno := &2
-- display the value
print :empno
Now, let's test the script:
SQL> #D:\test.sql 1000 7369
PL/SQL procedure successfully completed.
SAL
----------
1000
PL/SQL procedure successfully completed.
EMPNO
----------
7369
SQL>
For STRING type
-- define the bind variable
var ename varchar2(10)
-- assign the argument's value
exec :ename := '&1'
-- display the value
print :ename
Now, let's test the script:
SQL> #D:\test.sql LALIT
PL/SQL procedure successfully completed.
ENAME
--------------------------------
LALIT
SQL>
Result should be stored in csv file.
Handle this in the SQL script. Use proper SQL*Plus formatting for comma separated result. To store the result set, you just need to SPOOL
For example,
set colsep , -- separate columns with a comma
set pagesize 0 -- No headers
set trimspool on -- remove trailing blanks
spool mycsvfile.csv
SELECT ....
spool off

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

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"

Resources