So I am looking through a bit of code in an Oracle (PLSQL) stored procedure and I came across something that I don't understand.
if lv_var1= ' ' then
null;
else
begin.....
It's simply the line that says null
What does it do (If anything).
My guess is that it exists out of the whole procedure but I can't find any information on it.
It doesn't do anything. In PLSQL you can't have an empty condition, doing something like this simply wouldn't compile:
if lv_var1= ' ' then
--do nothing
else
begin.....`
By having null there the condition is not empty, so the procedure compiles but nothing happens if that branch is ever reached.
It could probably be written as this instead:
if lv_var1 != ' ' then
begin...
end if;
Edit: As Boneist correctly pointed out, the above alternative doesn't take into account null values, this could either be done with an nvl e.g. nvl(lv_var1,'empty') != ' ' or an OR condition e.g. lv_var1 != ' ' OR lv_var1 IS NULL
Related
I working on a stored procedure in redshift. I see that when parameters passed are NULL to the Execute statement in stored procedure. It fails with cannot execute a null string.
Please give me insights on how to solve the problem.
Stored Procedure:
CREATE OR REPLACE PROCEDURE outer_proc() LANGUAGE plpgsql
AS $$
DECLARE
cond_holder RECORD;
iter RECORD;
BEGIN
drop table if exists tmp_direction_comms;
create temporary table tmp_direction_comms as select distinct code from direction_coms;
DROP TABLE if exists final_direction_comms;
EXECUTE 'CREATE TEMP TABLE final_direction_comms
(
code varchar(100),
direction varchar(100),
dir_flg Boolean
)';
FOR iter IN select code from tmp_direction_comms LOOP
RAISE INFO 'code is %', iter.code;
SELECT INTO cond_holder distinct condition FROM mapping where code = iter.code;
RAISE INFO 'engmnt_cd is %', cond_holder.condition;
EXECUTE 'INSERT INTO final_direction_comms select code, direction, case when NVL('||cond_holder.condition||',false) then true else false end as dir_flg
from direction_coms where code = '''||iter.code||'''';
END LOOP;
END;
$$;
EXECUTE 'INSERT INTO final_direction_comms select code, direction,
case when NVL('||cond_holder.condition||',false) then true else false end as dir_flg
from acp_edw.stg_edw.direction_coms where code = '''||iter.code||'''';
There are two variables that can be NULL - iter.code or cond_holder.condition. The cond_holder.condition is wrapped by NVL, but NVL is inside in result string, not in generating expression.
Second big issue is a vulnerability against SQL injection. Probably you should to do:
EXECUTE 'INSERT INTO final_direction_comms select code, direction,
case when ' || NVL(cond_holder.condition, false) ' || then true else false end as dir_flg
from acp_edw.stg_edw.direction_coms where code = $1'
USING iter.code;
I am not sure if Redshift has support for USING clause. If not, then you should to use quote_literal function:
'... where code = ' || quote_literal(iter.code);
These are the question to the problem
Set echo on
2. SET SERVEROUT ON
3. Set up a spool file to receive your output for submission. I would suggest c:\CS4210\wa5spool.txt .
4. DECLARE a record variable (Emp_rec) using %ROWTYPE
5. In the BEGIN block add a select statement to read a record into the declared variable from HR.EMPLOYEES
6. Add If Statement to print record
7. Add DBMS_OUTPUT lines to print EMPLOYEE_ID, FIRST_NAME, LAST_NAME, and SALARY for the selected record
8. Use TO_CHAR to format the salary as $999,999
9. Add a EXCEPTION block to report when no data is found
10. Compile and run the procedure.
11. Close the spool file
CLARIFICATION: For this assignment, you can use your IF statement to do whatever you want. You can use it to determine the Department, like we did in the past with a CASE, or you can do it to print a message if they make over a certain amount of money, or maybe they are due a raise if they were hired before a certain date. Use your imagination.
:
set echo on
set SERVEROUTPUT ON
DECLARE
Emp_rec employee%rowtype;
BEGIN
SELECT * into emp_rec FROM HR.EMPLOYEES WHERE EMPLOYEE_ID = 5;
IF Emp_rec.EMPLOYEE_ID = 5 THEN
dbms_output.put_line('Employee ID : ' || Emp_rec.EMPLOYEE_ID);
dbms_output.put_line('First Name : ' || Emp_rec.FIRST_NAME);
dbms_output.put_line('Last Name : ' || Emp_rec.LAST_NAME);
dbms_output.put_line('Salary: ' || TO_CHAR(Emp_rec.salary,'$99,990.99'));
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO errors VALUES ('No record found in the table ' );
END;
spool off
As your table seems to be HR.EMPLOYEES, your declaration of a rowtype should be HR.EMPLOYEES%rowtype.
I am facing a tricky problem while I am trying to run stored procedure via Squirrel against DB2 database.
In the stored procedure have part where combine an sql statement like this:
SET V_SQL = 'SELECT DISTINCT ' || PARAM_COLUMNNAME || ' FROM '||PARAM_TABLENAME||' WHERE '||PARAM_COLUMNNAME||'<'||PARAM_NUMBER||';';
I changed the session statement paramater ; --> # to run properly the procedure call, but I get error message:
An unexpected token "" was found following "". Expected tokens may
include: "WHERE REP_ID<201506".. SQLCODE=-104, SQLSTATE=42601,
DRIVER=3.59.81 SQL Code: -104, SQL State: 42601
I guessed it is because of the delimeter ';' of the inside sql script so I changed the code like this:
SET V_SQL = 'SELECT DISTINCT ' || PARAM_COLUMNNAME || ' FROM '||PARAM_TABLENAME||' WHERE '||PARAM_COLUMNNAME||'<'||PARAM_NUMBER||'#';
Then I get this message:
The numeric literal "201506#" is not valid.. SQLCODE=-103,
SQLSTATE=42604, DRIVER=3.59.81 SQL Code: -103, SQL State: 42604
Do you have any idea?
Squirrel: SQuirreL SQL Client snapshot-20150623_2101 DB2: 9.5
Thanks and Cheers.
So finally what for me worked it was the comment sign:
SET V_SQL = 'SELECT DISTINCT ' || PARAM_COLUMNNAME || ' FROM '||PARAM_TABLENAME||' WHERE '||PARAM_COLUMNNAME||'<'||PARAM_NUMBER||';';--
The explanation I am not sure why pass through in this way the database engine, but worked.
Thanks!
is there a way how to beside of SQLCODE and SQLSTATE return the actual error message text?
Of course I can look for the error message in DBC.ERRORMSGS by SQLCODE but clearly I am not able to resolve the error-related object names from there.
Fe. all I can get from DBC.ERRORMSGS is 'Object '%VSTR' does not exist.'
Is there a way how to resolve the object name so I would get something like 'Object DATABASEXOXO.TABLEXOXO does not exist.'?
Thanks
Teradata supports Standard SQL's error handling, i.e there's a "diagnostic area" and one of it's fields is MESSAGE_TEXT which holds the error text. It's usually accessed in condition handler using the GET DIAGNOSTIC statement like this:
GET DIAGNOSTICS EXCEPTION 1 myval = MESSAGE_TEXT;
Check the Stored Procedure manual for further details.
Unfortunately MESSAGE_TEXT is limited to 128 characters. With newer versions of Teradata a single column/table name can be 128 characters. So from the diagnostics you cannot always get the full error message out. The only other way I know is through dbc.qrylog.ErrorText. But the qrylog is not always up to date and must be turned on.
create table log_table (log_msg varchar(2000), added_ts timestamp(0));
replace procedure sp_error_test
(
IN in_database varchar(50), IN in_table varchar(50), IN in_column varchar(50)
)
begin
declare l_sql varchar(2000);
declare l_err varchar(2000);
DECLARE EXIT HANDLER
FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS EXCEPTION 1 l_err = MESSAGE_TEXT;
INSERT INTO log_table VALUES ( 'State: ' || :SQLSTATE || ' Code:' || :SQLCODE ||
' Msg: ' || l_err, Current_Timestamp(0));
END;
-- dynamic sql to track execution of --
set l_sql = 'update ' || in_database || '.' || in_table ||
' set ' || in_column || '=' || in_column || ' ';
execute immediate l_sql;
end;
call sp_error_test('Dbc','NON_EXISTENT_TABLE','non_existent_column');
select top 100 * from log_table order by added_ts desc;
Output:
State: 42000 Code: 3807 Msg: Object 'DBC.NON_EXISTENT_TABLE' does not exist.
I really like SQuirreL SQL as a SQL query tool, but I've never been able to get it to call stored procedures in our AS/400 DB2 database. I always get the error "The number of parameter values set or registered does not match the number of parameters." I've double-checked the number of params and had no luck. This is the syntax I've tried for a procedure that takes one IN and one OUT:
call SOMESPROC(12345, ?);
It seems that SQuirrel currently is not capable of doing that on AS/400 DB2.
Using the open source "SQL Workbench/J" (http://www.sql-workbench.net/) I was able to call a procedure:
wbcall SOMESPROC(12345, ?);
It has its own command for calling a procedure "wbcall". Use ? for out parameters.
Note: While installing SQL Workbench/J make sure to download the right DB2 driver from IBM and also add the licence file while adding the driver inside SQL Workbench/J.
In Squirrel you can use something like this. You'll want to make sure the type of the declared variable matches the type of your out parameter in the stored procedure.
BEGIN
DECLARE outParam INT;
STORED_PROC_NAME(outParam);
END
If you also need to provide input for the procedure you could do this.
BEGIN
DECLARE outParam INT;
STORED_PROC_NAME('input', outParam);
END
You also need to change the statement separator to something other than ;. Otherwise it will break up the statement and try to send each piece individually.
In the pro version of DbVisualizer, with the "Process Parameter Markers in SQL" under the SQL Commander menu option enabled, it will allow the "?" param
call SOMESPROC(12345, ?);
through trial and error, I was able to see the results in Squirrel.
create or replace variable var4 char(1);
create or replace variable var5 decimal(3,0);
create or replace variable var6 char(60);
call getthedata('XXX',123456789,'1234567',var4,var5,var6);
select var4,var5,var6 from sysibm.sysdummy1; -- displays OUT parms
I would think that if there is one in then the call should be:
CALL SomeSProc(12345)
to get a result maybe try:
SELECT * FROM SomeSProc(12345)
Here is an tested example which works on Squirrel 3.7 with a db2 stored procedure . The trick is to passe with an transitional stored procedure MY_PROC_TEST to call the real stored procedure PROC_TEST.
change statement separator in squirrel > session > session properties > SQL : #
DROP PROCEDURE MY_PROC_TEST()#
CREATE PROCEDURE MY_PROC_TEST()
RESULT SETS 1 -- out resultset (call product)
LANGUAGE SQL
BEGIN
DECLARE flag SMALLINT; -- out parameter
CALL MY_PROC('2015', flag);
END #
CALL MY_PROC_TEST()#
END #
Then you can call the sored procedure like this :
CALL MY_PROC_TEST()#
This will work in Squirrel if you change the delimiter (as specified above). However, to see what the variable is, you need to do the following...
In my example, I will set the delimiter to a tildy (~). Include after last "end", before "select". Code begins here...
begin
declare inoutParm numeric(2,0);
call spMyStoredProcedure(
1234567
, inoutParm
);
declare global temporary table session.myTempTbl
(MyResult char(1024) )
with replace ;
insert into session.myTempTbl
(myResult)
values(inoutParm) ;
end
~
select myResult from session.myTempTbl
Mic Keeley
as400(db2) SQL Developer
I was able to cobble together some amalgamation of all of the above answers and came up with this which worked for me. I'm using Squirrel SQL 2018 connecting to an IBM AS/400 DB2 database. I did have to declare a statement separator, I used "#".
BEGIN
DECLARE success CHAR(1); -- output parameters
DECLARE message CHAR(300);
SET success = ' ';
SET message = ' ';
CALL myProc('some', 'params', 4, success, message);
DECLARE GLOBAL TEMPORARY TABLE session.myTmp(s_res CHAR(1), m_res CHAR(300)) WITH REPLACE;
INSERT INTO session.myTmp(s_res, m_res) VALUES(success, message);
END
# -- <- statement separator needs to be set to something other than ";" in this case it's set to "#"
SELECT * FROM session.myTmp;
change statement separator in squirrel > session > session properties > SQL : '#'
BEGIN
DECLARE inOutParam varchar(200);
set inOutParam = 'a value';
STORED_PROC_NAME(outParam);
END;
#