How to Access Oracle Table through bash when it's a new create table - bash

I have a simple script in bash that just return the count of a given table
The trow command through bash its like that
user>bash Bash_Script.bsh -T MyTableTthatAlreadyExists
After the conections parameters it just do that:
SQLSTRING="SELECT COUNT(*) FROM $SYBTAB;"
BATCH_ARGS=`sqlplus -S /nolog <<SQL | tail -1
connect $ORCL_USR/$ORCL_PWD#$ORCL_TNS;
alter session set nls_date_format='YYYYMMDD';
set pagesize 0 long 4096 linesize 32767 feed off head off;
$SQLSTRING
quit;
SQL`
echo "$BATCH_ARGS"
And it works. Yest it works, it returns the nummer of rows of my table.
The problem come when I create a new table MyNewTable
- The table exists in Oracle
so when I do in SQL Developer
select count(*) from MyNewTable;
return the correct nummer.
But when I throw again the unix command. It doesnt work, it doesnt return anything
user>bash Bash_Script.bsh -T MyNewTable --> return nothing
I wonder myself what I m missing, wat I m not taking account.
I thounk about Grant privileges but they both haven the same.
can anyone here help me ?
Thanks in advance, Enrique

Your script is only getting the last line of output from SQL*Plus
BATCH_ARGS=`sqlplus -S /nolog <<SQL | tail -1
If you remove the tail part:
BATCH_ARGS=`sqlplus -S /nolog <<SQL
then you'll see what is actually happening. With a table that exists, with that modification I see:
user>bash Bash_Script.bsh -T MyTableTthatAlreadyExists
Session altered.
1815
and with a table that does not exist I see:
user>bash Bash_Script.bsh -T MyNewTable
Session altered.
SELECT COUNT(*) FROM t43
*
ERROR at line 1:
ORA-00942: table or view does not exist
It seems you are seeing ORA-01031: insufficient privileges, so the user you are connecting as needs to have select privileges granted for the new table.
As you only want the actual count, if you swap the order of the alter and set clauses the Session altered. message will also be suppressed as feedback will be switched off by then:
BATCH_ARGS=`sqlplus -S /nolog <<SQL
connect $ORCL_USR/$ORCL_PWD#$ORCL_TNS;
set pagesize 0 long 4096 linesize 32767 feed off head off;
alter session set nls_date_format='YYYYMMDD';
$SQLSTRING
quit;
SQL`
and you'd then see, for an existing table, just:
user>bash Bash_Script.bsh -T MyTableTthatAlreadyExists
1815
making the tail unnecessary anyway.

Related

How to store sql query output in variable in shell script

I am trying to store the value of sql query output in a variable using shell script.
size=`${PATH_TO_CLIENT}sqlplus $IMPUSER/$IMPPWD#$ENDPOINT<< EOF
select owner, sum(bytes)/1024/1024/1024 Size_GB from dba_segments where owner = 'XXXX' group by owner;
exit;
EOF`
echo "Total data is ${size}"
The output I am getting is
**Total data is**
SQL*Plus: Release 21.0.0.0.0 - Production on Fri May 14 11:06:42 2021
Version 21.1.0.0.0
Copyright (c) 1982, 2020, Oracle. All rights reserved.
Last Successful login time: Fri May 14 2021 11:01:02 -04:00
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.8.0.0.0
SQL>
OWNER
--------------------------------------------------------------------------------
SIZE_GB
----------
XXXXXXX
12.2345
SQL> Disconnected from Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.8.0.0.0
Inside the variable full connection string and sql query output all are getting stored. I just want to get value like $size=12.2345 Please tell me how to get that
The size value might be assigned to the current variable through use of the following code block
size=$(sqlplus -S /nolog << EOF
conn $IMPUSER/$IMPPWD#$ENDPOINT
whenever sqlerror exit sql.sqlcode
SET PAGES 0
SELECT SUM(bytes)/1024/1024/1024 FROM dba_segments WHERE owner = 'XXXX';
EOF
)
echo "Total data is "$size
where
keeping owner column and group by clause are redundant as
returning only one column value for a single schema
no need to alias the calculated value as not needed for the returning result while hiding the column title through use of SET PAGES 0 command
using direct connection is not safe, but use sqlplus -S /nolog before
schema connection in order to hide the password while listed by
anbody through ps command.
You can use this:
size=`${PATH_TO_CLIENT}sqlplus -s $IMPUSER/$IMPPWD#$ENDPOINT <<EOF
set echo off
set feedback off
set heading off
set pages 0
select sum(bytes)/1024/1024/1024 Size_GB from dba_segments where owner = 'SYS';
exit;
EOF`
echo "Total data is ${size}"
If the output is consistent with newlines, you could use:
size=`${PATH_TO_CLIENT}sqlplus $IMPUSER/$IMPPWD#$ENDPOINT<< EOF | sed -n '/^\s*SIZE_GB$/{n;n;n;p}'
select owner, sum(bytes)/1024/1024/1024 Size_GB from dba_segments where owner = 'XXXX' group by owner;
exit;
EOF`
It will return the third line after line which contains 'SIZE_GB'.

How to export half a million records from PL/SQL

I've a table with around 500,000 records. I need all records to be exported in excel. When I query I'm not able to get all as I was said as Out Of memory
Table doesn't have any primary key/Index.
Is there any way to extract?
it would be very easy in to write file output form sqlplus .
mycsv.sql:
SET DEFINE OFF
SET ECHO OFF
SET SERVEROUTPUT OFF
SET TERMOUT OFF
SET VERIFY OFF
SET FEEDBACK OFF
SET PAGESIZE 10000
SET ARRAYSIZE 5000
REM SET HEAD OFF
SET LINE 500
spool /tmp/mycsvfile.csv;
select * from MY_table;
spool off;
exit;
and from Linux prompt you can run like
$> sqlplus username/password #/tmp/mycsv.sql

Fetching SQL execution plan. PL/SQL Developer = strange behaviour. SQL*Plus = no rows selected

I have a problem with fetching SQL plans.
In the final form, I have to fetch them through PL*SQL.
So I have a bash script, a loop to iterate through sql plan names and parameters, and a code like this:
sqlplus -s /nolog > /dev/null 2>&1 <<EOF
CONNECT BLAH/BLAH#BLAH
*CLEAR AND SET COMMANDS HERE*
VARIABLE RC REFCURSOR;
SPOOL ${BERICHT}_${configArray[0]}.DATA
SET TIMING ON;
EXEC :RC := $aktuellesBericht;
SET TIMING OFF;
PRINT RC;
DISCONNECT
QUIT
EOF
And the second part: (logging in as SYS, but without the SYSDBA permissions, I dont have them and I dont think that I will have them...)
sqlplus -s /nolog > /dev/null 2>&1 <<EOF
CONNECT SYSBLAH/SYSBLAH#BLAH
SPOOL ${BERICHT}_${configArray[0]}.SQLPLAN.TXT
CLEAR BREAK
CLEAR COMP
CLEAR COL
select
sqlplan.operation,
sqlplan.options,
sqlplan.object_name,
sqlplan.cost,
sqlplan.depth
from v\$sqlarea sqlarea,
v\$session sesion,
v\$sql_plan sqlplan
where sesion.sql_hash_value = sqlarea.hash_value
and sesion.sql_address = sqlarea.address
and sqlarea.plan_hash_value = sqlplan.plan_hash_value
and sesion.username = 'BLAH' order by sqlplan.depth;
QUIT
EOF
All I can get from this is *.SQLPLAN.TXT files containing just one sentence: no rows selected
What is strange here, that when I do the same in PL/SQL Developer - i get the same results, BUT when I just click on the Auto Refresh timer button on both SQL windows, both queries are running in parallel, and SOMETIMES the second query (the one to fetch SQL plan) is giving me results. And sometimes it doesnt.
It seems that theese commands need to be run in parallel... or am I missing something?
The sql query in my question was never needed.
All I needed is to write to the admin team to grant me the SELECT premissions on:
V$SQL_PLAN, V$SESSION and V$SQL_PLAN_STATISTICS_ALL
The answer to my question was found here.
I will need a deeper understanding of the problem in the future but for now, FWIK, looking deeper into the dbms_xplan package gave me the idea.
The approach to get the queries from the SYSACC account was the wrong idea. This acc has access to all the queries history and it is hard and painful (if even possible) to husk out the sql plan I needed.

Multiple Line Variable into SQLPlus from Shell Script

What is the best way to pass multiple values from one variable into separate records in an oracle db?
I want to take the output from:
hddlist=`iostat -Dl|awk '{print ""$1"="$(NF)}'
This returns output like this:
hdisk36=0.8
hdisk37=0.8
hdisk38=0.8
hdisk40=5.5
hdisk52=4.9
I want to insert them into a database like so:
sqlplus -s /nolog <<EOF1
connect / as sysdba
set verify off
insert into my_table ##Single Record Here
EOF1
How can I systematically separate out the values so i can create individual records that look like this:
Disk Value
--------- -------
hdisk36 0.8
hdisk37 0.8
hdisk38 0.8
hdisk40 5.5
hdisk52 4.9
I originally tried a while loop with a counter but could not seem to get it to work. An exact solution would be nice but some directional advice would be just as helpful.
Loop and generate insert statements.
sql=$(iostat -Dl | awk '{print ""$1"="$(NF)}' | while IFS== read -r k v ; do
printf 'insert into mytable (k, v) values (%s, %s);\n' "$k" "$v"
done)
This output can be passed in some manner to sqlplus, perhaps like this
sqlplus -s /nolog <<EOF1
connect / as sysdba
set verify off
$sql
EOF1
Although, depending on the line format of iostat, it might be simpler to just omit awk and parse with read directly.
You can redirect the output to a file and then use an external table
It should look something like this:
CREATE TABLE hddlist_ext_table (
disk CHAR(16),
value CHAR(3)
ORGANIZATION EXTERNAL (
TYPE ORACLE_LOADER DEFAULT DIRECTORY tab_dir
ACCESS PARAMETERS (RECORDS DELIMITED BY NEWLINE
FIELDS TERMINATED BY '=')
LOCATION ('your_file_name'));
Then you can either use this table for your data or insert-select from it to your table;
insert into my_table
select disk, value from hddlist_ext_table;
You can insert multiple rows in a single SQL statement in Oracle like this
INSERT ALL
INTO mytable (column1, column2, column3) VALUES ('val1.1', 'val1.2', 'val1.3')
INTO mytable (column1, column2, column3) VALUES ('val2.1', 'val2.2', 'val2.3')
INTO mytable (column1, column2, column3) VALUES ('val3.1', 'val3.2', 'val3.3')
SELECT * FROM dual;
If you intend to run this script automatically at intervals to then see the results of each disk, you will probably need additional columns to hold the date and time.
You might also look at sqlldr as you can specify a control file telling it what your data contains and then this will load the data into a table. It is more suited to the purpose if you are loading lots of data than SQL Plus.

Oracle DB won't allow users to query tables

I am on Windows XP running Oracle 10G XE Edition.
After running a defrag & cleanup process, I have not been able to access any of the objects on the database.
A quick check
set lines110
col strtd hea 'STARTED'
col instance_name for a8 hea 'INSTANCE'
col host_name for a15 hea 'HOSTNAME'
col version for a10
select instance_name, version, host_name, status
, database_status, to_char(startup_time,'DD-MON-YYYY HH:MI:SS') strtd
from v$instance;
returns this
INSTANCE VERSION HOSTNAME STATUS DATABASE_STATUS STARTED
-------- ---------- --------------- ------------ ----------------- ----------------------------------------------------
xe 10.2.0.1.0 DT8775C MOUNTED ACTIVE 03-DEC-2010 11:38:00
If I use this command, it throws the following error.
SQL> ALTER DATABASE OPEN;
ALTER DATABASE OPEN
*
*ERROR at line 1:*
ORA-16014: log 2 sequence# 679 not archived, no available destinations
ORA-00312: online log 2 thread 1:
'D:\ORACLEEXE\APP\ORACLE\FLASH_RECOVERY_AREA\XE\ONLINELOG\O1_MF_2_4JD5RZC0_.LOG'
How can I fix this situation?
There are zero files in the
"D:\ORACLEEXE\APP\ORACLE\FLASH_RECOVERY_AREA\XE\ONLINELOG\" folder.
I'm pretty sure this belongs on SERVERFAULT, but to get you going for now:
It appears the database is in ARCHIVELOG mode and you have not supplied a location to store the archived log files. A quick fix, assuming you don't need the recovery protection that archive logging gives you is to try this:
sqlplus / as sysdba
SQL> shutdown immediate;
SQL> startup mount;
SQL> ALTER DATABASE NOARCHIVELOG;
SQL> ALTER DATABASE OPEN;
If you do want to keep your archived redo logs, then you'll need entries like this in your database parameters:
alter system set log_archive_dest_1='location=d:\oraclexe\app\oracle\...';
alter system set log_archive_dest_state_1=enable;
Sounds like in your cleanup process you may have deleted the .LOG files. I assume you've emptied the trash and can't restore them?

Resources