Put select result in a ksh variable - oracle

using sql loader, I know I can reference a ksh variable in my ctl file. For example I can write
LOAD DATA
INFILE '$PATH_IN_KSH/my_file.dat'
...
I would like to add a WHEN clause like this
WHEN (125:125) = '$P_NUMBER'
P_NUMBER would have the value of a column in a table that I would retrieve with a select query.
Is it possible to do that ? retrieve a value from a column with a select and somehow put it in the ksh variable so the ctl file can see it. (something with sql plus?)
Thank you

As a basic outline you can run SQL*Plus with a heredoc to perform the query, and assign the output to a variable:
P_NUMBER=`sqlplus -s /nolog <<!EOF
connect username/password
whenever sqlerror exit failure
set pagesize 0
set feedback off
select your_value from your_table where your_key = 'something';
exit 0
!EOF`
Enclosing in backticks assigns the result to the variable. $P_NUMBER will then hold whatever value your query got (or an error message if the credentials were wrong, say). It helps if you're sure the query will return exactly one result. You can also test the return code with $? to look for errors, before you try to use your variable.
Including the -s flag, turning off feedback and setting the pagesize to zero collectively suppress all the noise so you only get the result and don't have to strip out banners, headings etc.
And finally I've used /nolog and put the connect statement inside the heredoc so that the credentials don't appear in the process list, which is an often-overlooked security issue. If you don't want to do that and do put the credentials as sqlplus username/passwd, you can add the -l flag so that it only tries to log in once; otherwise if login fails for some reason it'll try to use the rest of the heredoc as further credentials, and can appear to get hung up with short scripts.

Related

Hive - How to store a query result in a variable in a Bash script

I need to store the result of a Hive query in a variable whose value will be used later. So, something like:
$var = select col1 from table;
$var_to_used_later = $var;
All this is part of a bash shell script. How to form the query so as to get the desired result?
Hive should provide command line support for you. I am not familiar with hive but I found this: https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Cli, you can check whether that works.
Personally, I used mysql to achieve similar goal before. The command is:
mysql -u root -p`[script to generate the key]` -N -B -e "use XXXDB; select aaa, bbb, COUNT(*) from xxxtable where some_attribute='$CertainValue';"
I used the method shown here and got it! Instead of calling a file as shown, I run the query directly and use the value stored in the variable.

How to create a "one-liner" for oracle that includes "set" commands as well as sql statements

I want to execute a dynamic sql containing some set commands. Is it possible to do so without embedding newlines?
set heading off ; set lines 1000 ; select * from my_table;
Note the above does not work due to the semicolons between the set commands:
SP2-0158: unknown SET option ";"'
Update The whole point of this question is to do it on one line.
The best I have found for my own purposes is to put my standard SET commands in a file called sql_settings.txt in a directory with an environment variable holding its path and another variable for the connect string:
sqlsets=/directory/where/sql_settings/stored/sql_settings.txt
db_conn=<ConnectStr>
& then execute a one-liner as such with a shell here-string:
sqlplus -s $db_conn #$sqlsets <<< "select * from my_table;" | less
(The "less" pipe will prevent from cluttering your shell session)
You could also get fancy and create a shell function to minimize typing to the SQL query:
function mydb { sqlplus -s $db_conn #$sqlsets <<< "$#;" ; }
Then call as such:
mydb 'select * from my_table;'
set command is a directive for sqlplus and is not related to sql and you can do it this way
set heading off lines 1000
select * from my_table;
After extensive research, I have concluded this is not possible to perform with oracle.

Passing Contents of File as Parameter to Sql*Plus Command

I'm trying to write a sqlplus command that creates a table from a query that is stored in an .sql file.
The particular .sql file that contains the query would be supplied to my sqlplus command as a variable (&v_InputQuery).
I've tried something like this, but it doesn't work.
CREATE TABLE &v_OutputTable AS
(
< &v_InputQuery
)
;
I get an error saying that there's a missing SELECT keyword.
What I'd really like is for &v_InputQuery to be replaced not with the name of the file specified by the user, but with the actual contents of the file. Is there a way to do that?
Thank you very much.
Yes, you can do that. If your query is in a file called v_InputQuery.sql, you can do this:
CREATE TABLE &v_OutputTable AS (
#v_InputQuery.sql
) ;
It's important that the # is the first character on the line. SQL*Plus will read the file and put its contents at that location. So make sure you don't have any terminating characters in the file such as ; or /.
Unfortunately, You cannot create a SQL*Plus command, but instead create a shell script to do it!
Lets say my_script.sh is below
#you can always complete the user interaction at unix/dos
USER=your_user
PASS=your_pass
DB=your_db
OUTPUT_TABLE=$1;
QUERY_FILE=$2;
SELECT_QUERY=`cat $QUERY_FILE`;
sqlplus -S ${USER}/${PASS}#${DB} << !
SET SERVEROUTPUT ON;
VAR EXITCODE NUMBER;
BEGIN
EXECUTE IMMEDIATE ' CREATE TABLE $OUTPUT_TABLE AS $SELECT_QUERY ';
:EXITCODE := SQLCODE;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
:EXITCODE := SQLCODE;
END;
/
exit :EXITCODE
!
Executing the script as below(Depends on OS)
ksh my_script MY_OUTPUT_TABLE my_sql.sql;
Expanding a comment, #MaheswaranRavisankar's approach will work, but the dynamic SQL (i.e. execute immediate) isn't necessary, so the anonymous block isn't necessary either. It can be simplified somewhat to:
USER=your_user
PASS=your_pass
DB=your_db
OUTPUT_TABLE=$1;
QUERY_FILE=$2;
SELECT_QUERY=`cat $QUERY_FILE`;
sqlplus -S ${USER}/${PASS}#${DB} << !
WHENEVER SQLERROR EXIT FAILURE
CREATE TABLE $OUTPUT_TABLE AS $SELECT_QUERY
!
This also allows you to use a query which is already terminated by a ; or /, which the execute immediate version wouldn't like - you just need to decide whether your wrapper script needs one to match what your query files will contain.
Even the whenever ... line isn't vital, but the other answer tried to exit with the error code so I've mimicked that too somewhat. This will always exit with a generic failure status though (1 in Unix, not sure what Windows does). You can then test if it was successful with $? in the script if you want to.
You can exit with the actual SQL error instead of the generic value, by using whenever sqlerror exit sql.sqlcode instead. The problem with doing that is that most (all?) shells limit the return code to the range 0-255, so most errors will wrap and give something unhelpful anyway - a fairly-likely ORA-00955: name is already used by an existing object error would give a shell exit value of 187, for example. And it's possible the wrapped value would be zero, which would mask that an error occurred at all; an also-plausible ORA-01536: space quota exceeded for tablespace '%s' error would give a shell exit code of zero, which is unhelpful. Using exit failure would at least stop that.

Config SQL*Plus to return nothing but data

I need to write a simple shell function that returns a single field from an Oracle DB. Think of it as for example SELECT 'ABC' FROM dual; and ABC is what I am after.
Here is my function:
function getSomeOraVal
{
sqlplus $USER/$PASSWD#$ORADB<<!!
SET sqlprompt ''
SET sqlnumber off
SET verify off
SET pages 0
SET echo off
SET head on
SET feedback off
SET feed off
SET serveroutput on
SET escape '\'
VARIABLE v_someVal VARCHAR2(30);
BEGIN
SELECT 'ABC' INTO v_someVal FROM dual;
END;
/
SELECT :v_someVal FROM dual;
!!
}
However, I want to pipe the sqlplus output (data only -> 'ABC') into a shell variable, which the function then returns and can be called from other shell scripts. Unfortunately, sqlplus returns a whole lot of garbage, such as "Welcome to Oracle" on top and "Disconnected..." in the bottom.
How can I extract just the data from a SQL result set, or in this case a single value and pass it into a UNIX variable for further manipulation within the shell?
Thanks
There are a few different approaches in this askTom thread on returning values from SQL*Plus to a shell script.
One common approach is to select a constant token in addition to the value that you want to return (in Tom's example, that is the string "KEEP") and then use sed (or your favorite command-line parser) to extract the data you're actually interested in
#!/bin/ksh
x=`sqlplus / <<endl | grep KEEP | sed 's/KEEP//;s/[ ]//g'
select 'KEEP' , max(sal) from emp;
exit
endl`
echo the answer is $x
Other approaches, such as approaches that allow you to read multiple lines of output are also discussed in that thread.
If you don't want the header to be printed, you should be specifying
set head off
in your SQL*Plus script-- I'm not sure why you're explicitly setting the header on in the script if you don't want the header... Do you want to keep some part of the header?
Based on Justin's answer (which is great), when you only need to select one number (or token), I consider this a little shorter, yet more readable version:
x=`sqlplus -S / <<< "select 'KEEP' , max(sal) from emp;" | awk '/KEEP/{print $2}'`

Parameterizing table name in sqlplus input file

I am trying to export some data using sqlplus and the Oracle spool functionality. The problem is that the SQL input file where I am defining my export is not letting me parameterize the table name from which I am exporting data -- it wants a literal :(
Calling sqlplus in a shell script:
sqlplus $USER/$PASSWD#$ORADB<<!
#export.sql $OUT_FILE $SOME_VAR $ENV
exit
!
export.sql:
set heading off
set head off
set term off
set tab off
set embedded on
set feedback off
set pagesize 0
set linesize 800
set trimspool on
set verify off
spool &1
SELECT '&2|' || some_col
FROM &3_TABLE
/
spool off
When $ENV is set to 'dev', I get
Enter value for 3_TABLE
whereas I want it to use dev_TABLE. When I unparameterize the table names in the sql file, the output runs fine. Also note that there is param &2, which is $SOME_VAR from the shell and it gets displayed evaluated fine. The only problem is in the FROM statement.
Is there any way to tell the sql input file to replace the parameterized table names before running SQL?
Thanks
The problem is that SQL*Plus is treating the whole string after the &, up to the next whitespace or simlar, as the substitution variable name. Clearly that isn't what you want here.
Fortunately they've thought of this, and you can denote the end of the variable name with a .:
FROM &3._TABLE
(At least, that works for named variables, and I'm almost sure it will for positional ones... if not then you'd need to define a new variable set to &3 as a workaround).
It is in the documentation, but blink and you'll miss it:
If you wish to append characters immediately after a substitution
variable, use a period to separate the variable from the character.
There's a related effect that you may want to bear in mind for the future. If the next character after the substitution variable is a . anyway - between the schema and table, or between table and column, for example - then that will be interpreted as the substitution terminator. Say you were passing the schema separately as &4, with value 'scott'; this:
FROM &4.&3._TABLE
looks reasonable but would be substituted as scottdev_TABLE, which won't be recognised. So in that instance you need to have an extra one:
FROM &4..&3._TABLE
which would be substituted as scott.dev_TABLE.

Resources