Can I call a global variable in source variable in ODI? - sql

I am trying to build a ODI procedure, which will take schema name, db procedure name and parameters from a oracle database metadata table. The parameter field contains a name of a ODI global variable.The source command is like this
SELECT SCHEMA_NAME VAR_SCHEMA, PROCEDURE_NAME VAR_PROCEDURE, PARAMETER_NAME
VAR_PARAMETER FROM SCHEMA-NAME.TABLE_NAME
the output of the source command is like this:
VAR_SCHEMA_NAME VAR_TABLE_NAME VAR_PARAMETER
ABC PROC_LIST TO_DATE('#VAR_ETL_LOAD_DATE','DD/MM/RRRR')
Here, #VAR_ETL_LOAD_DATE is a global variable in ODI.
In the target command of the procedure, I want to use these information from source command to execute procedures listed in metadata table. I wrote a command like this:
DECLARE
VVC_SQL_STMT LONG;
BEGIN
VVC_SQL_STMT := 'BEGIN
#VAR_SCHEMA_NAME.#VAR_PROCEDURE_NAME(#VAR_PARAMETER);
END;';
INSERT INTO AK_TST2 VALUES(VVC_SQL_STMT,SYSDATE);
COMMIT;
EXECUTE IMMEDIATE (VVC_SQL_STMT);
END;
This code gives the following error in ODI:
ODI-1228: Task PROC_SP_HANDLER (Procedure) fails on the target ORACLE
connection OCDM_SYS.
Caused By: java.sql.SQLException: ORA-06550: line 8, column 61:
PLS-00103: Encountered the symbol "#" when expecting one of the following:
* & = - + ; < / > at in is mod remainder not rem
<an exponent (**)> <> or != or ~= >= <= <> and or like like2
like4 likec between || multiset member submultiset
What is the reasons for this and how can I execute stored procedures in ODI by reading procedure names and parameters from a metadata table?

If you select data from a table and use the result as a code for further execution, normally you cannot use ODI variables there. Because it too late for ODI to recognse that it is a variable and substitute it by a variable. This is the same for both global and project variables.
If you could print "#"+variable_name from ?- or %-substitution than it will work. But if #-substitution prints variable name or if variable appears as a final code after fetching values from Source it is too late. In this cases it remains as a plain text #VAR.
In your particular case you can do the following:
Declare all variables like #VAR_ETL_LOAD_DATE in a package. I mean all variables that could potentially appear in the metadata table. Bacause scenario should know all variables in advance.
Select and fetch records within ?-substitution using odiRef.getJDBCConnection('SRC'). Collect all results into a java-variable in the form of executable code.
E.g., source code could look like this:
select 1 from dual;
<?
import java.sql.*;
String crlf = System.getProperty("line.separator");
String result = "begin"+crlf+"null;"+crlf;
PreparedStatement stmt = odiRef.getJDBCConnection("SRC").prepareStatement("select schema||'.'||proc||'('||param||')' from metatable");
ResultSet rs = stmt.executeQuery();
while(rs.next()){
result += "insert into ak_tst2 values('"+rs.getString(1).replaceAll("'",'"'.toString())+"');"+crlf;
result += "commit;"+crlf;
result += rs.getString(1)+";"+crlf;
}
result += "end;";
rs.close();
stmt.close();
?>
Target code should be very simple
<?=result?>
At runtime target code will appear like this
begin
null;
insert into ak_tst2 values('qwe.asd("param_using_#var")');
commit;
qwe.asd('param_using_#var');
insert into ak_tst2 values('qwe2.asd2("param2_using_#var")');
commit;
qwe2.asd2('param2_using_#var');
insert into ak_tst2 values('qwe3.asd3("param3_using_#var")');
commit;
qwe3.asd3('param3_using_#var');
end;
And ODI variables will be successfully substituted by values.

Related

Dynamic Column on SQL doesn't work (APEX,Interactive Report)

I tried to implement a page on APEX(19.2) , where the user has to make an input , which is the column name. This input shall restrict the select statement on the where clause and is the following:
select * FROM UEBERSICHT where
:P904_COLUMN = :P904_AUSDRUCK;
:P904_COLUMN and :P904_AUSDRUCK; are both APEX items, which is needed for the user input.
When I write the column name instead of :P904_COLUMN, I get an output, otherwise not.
But as the headline says, I want to implement a dynamic column.
I also tried it with PL/SQL , which returns a SQL - statement like the following:
declare
statement varchar2(4000);
begin
statement:= 'SELECT * FROM UEBERSICHT where
:P904_COLUMN = :P904_AUSDRUCK;';
return statement;
end;
Another approach was , to save the input on a variable first and write the variable name into the SQL - Statement:
declare
statement varchar2(4000);
spalte varchar2(50);
begin
if :P904_COLUMN = '"Gesellschaft"' then spalte := '"Gesellschaft"'; end if;
statement:= 'SELECT * FROM UEBERSICHT where
'||spalte||' = :P904_AUSDRUCK;';
return statement;
end;
Here i get this syntax error, which shouldn't appear normally: "ORA-20999: Parsing returned query results in "ORA-20999: Failed to parse SQL query! ORA-06550: line 5, column 6: ORA-00936: missing expression"."
How can I solve this problem ?
PS: Yes I am submitting all APEX items.
Update: The debug shows me that I get the Input, but the interactive Report doesn't give me any output though.
IF all the columns in :P904_COLUMN is of same data type you can use something like below where A and B are column names
select * FROM UEBERSICHT where
DECODE(:P904_COLUMN,'A',A,'B',B) = :P904_AUSDRUCK;

PostgreSQL variable in select and delete statements

The Problem: I have many delete lines in a PostgreSQL script where I am deleting data related to the same item in the database. Example:
delete from <table> where <column>=180;
delete from <anothertable> where <column>=180;
...
delete from <table> where <column>=180;
commit work;
There are about 15 delete statements deleting data that references <column>=180.
I have tried to replace the 180 with a variable so that I only have to change the variable, instead of all the lines in the code (like any good programmer would do). I can't seem to figure out how to do it, and it's not working.
NOTE: I am very much a SQL novice (I rarely use it), so I know there's probably a better way to do this, but please enlighten me on how I can fix this problem.
I have used these answers to try and fix it with no luck: first second third. I've even gone to the official PostgreSQL documentation, with no luck.
This is what I'm trying (these lines are just for testing and not in the actual script):
DO $$
DECLARE
variable INTEGER:
BEGIN
variable := 101;
SELECT * FROM <table> WHERE <column> = variable;
END $$;
I've also tried just delcaring it like this:
DECLARE variable INTEGER := 101;
Whenever I run the script after replacing one of the numbers with a variable this is the error I get:
SQL Error [42601]: ERROR: query has no destination for result data
Hint: If you want to discard the results of a SELECT, use PERFORM instead.
Where: PL/pgSQL function inline_code_block line 6 at SQL statement
Can someone tell me where I'm going wrong? It would be nice to only have to change the number in the variable, instead of in all the lines in the script, and I just can't seem to figure it out.
As #Vao Tsun said, you must define a destination to your SELECT statement. Use PERFORM otherwise:
--Test data
CREATE TEMP TABLE my_table (id, description) AS
VALUES (1, 'test 1'), (2, 'test 2'), (101, 'test 101');
--Example procedure
CREATE OR REPLACE FUNCTION my_procedure(my_arg my_table) RETURNS VOID AS $$
BEGIN
RAISE INFO 'Procedure: %,%', my_arg.id, my_arg.description;
END
$$ LANGUAGE plpgsql;
DO $$
DECLARE
variable INTEGER;
my_record my_table%rowtype;
BEGIN
variable := 101;
--Use your SELECT inside a LOOP to work with result
FOR my_record IN SELECT * FROM my_table WHERE id = variable LOOP
RAISE INFO 'Loop: %,%', my_record.id, my_record.description;
END LOOP;
--Use SELECT to populate a variable.
--In this case you MUST define a destination to your result data
SELECT * INTO STRICT my_record FROM my_table WHERE id = variable;
RAISE INFO 'Select: %,%', my_record.id, my_record.description;
--Use PERFORM instead of SELECT if you want to discard result data
--It's often used to call a procedure
PERFORM my_procedure(t) FROM my_table AS t WHERE id = variable;
END $$;
--DROP FUNCTION my_procedure(my_table);

Can't execute sql file

I'm trying to execute the following code using isql:
IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'SFPTB051_ABERTURARCLH'))
BEGIN
SELECT * FROM SFPTB051_ABERTURARCLH;
END
The way i'm doing:
isql -i sql_scripts/test.sql _input/mygdb.GDB -user SYSADM -pass masterkey
Output:
Statement failed, SQLSTATE = 42000
Dynamic SQL Error
-SQL error code = -104
-Token unknown - line 1, column 1
-IF
At line 1 in file sql_scripts/test.sql
Expected end of statement, encountered EOF
Any ideias?
Thanks!
UPDATE ---
I'm trying the following:
SET TERM # ;
EXECUTE BLOCK AS
BEGIN
SELECT * FROM SFPTB051_ABERTURARCLH
END#
SET TERM ; #
But it's returning:
Statement failed, SQLSTATE = 42000
Dynamic SQL Error
-SQL error code = -104
-Token unknown - line 4, column 1
-END
Usually, select statements within a block statement need to return their values. For example, you can return them into variables or return values, which are almost the same.
Furthermore, every statement within a block statement has to be terminated by a semi-colon (;).
Your block statement could look something like this:
SET TERM # ;
EXECUTE BLOCK AS
DECLARE VARIABLE FIELD1 TYPE OF COLUMN SFPTB051_ABERTURARCLH.FIELD1;
/* declare more variables as needed */
BEGIN
FOR
SELECT FIELD1
FROM SFPTB051_ABERTURARCLH
INTO :FIELD1
DO
BEGIN
/* do something with the variables values */
END
END#
SET TERM ; #

PL/SQL: how do I prompt user input in a procedure?

This is a question about a small part of a large project I'm doing. I tried the following but I just get the two errors below it:
SET SERVEROUTPUT ON
CREATE OR REPLACE PROCEDURE HELLO AS
DECLARE
variable1 NUMBER(1);
variable2 CHAR(1);
BEGIN
DBMS_OUTPUT.PUT_LINE('Hello World');
variable1 := &please_enter_1_or_0;
variable2 := &please_enter_y_or_n;
END;
/
Error(2,5): PLS-00103: Encountered the symbol "DECLARE" when expecting
one of the following: begin function pragma procedure subtype type
current
cursor delete exists prior external language The symbol "begin" was
substituted for "DECLARE" to continue.
Error(10,8): PLS-00103: Encountered the symbol "end-of-file" when
expecting one of the following: ( begin case declare end exception
exit for goto if loop mod null pragma raise return select update
while with
<< continue close current delete fetch lock
insert open rollback savepoint set sql execute commit forall merge
pipe purge
We were given a markscheme of how our code would be marked, and for this section, the relevant criteria would be:
"Does the script use a procedure?" and
"Does the script prompt for right/wrong and team/individual and handle the data provided correctly?".
The project brief quotes "Develop a procedure that prompts for RIGHT/WRONG (using &), then updates table" (where table is the name of a table).
The purpose of the variables was to update an existing record attribute. i.e. if user chose 1 and n then update the null in the record to 2. if it was 1 and y then update to 1, and if 0 and y/n then update to 0.
PL/SQL is a language for writing autonomous programs. It is not designed for user interactivity. Input values are passed as parameters.
So your program should look like this
CREATE OR REPLACE PROCEDURE hello
( p1 in number
, p2 in varchar2 )
AS
l_salutation varchar2(20) := 'Hello World';
BEGIN
DBMS_OUTPUT.PUT_LINE(l_salutation);
DBMS_OUTPUT.PUT_LINE('p1 = ' || p1);
DBMS_OUTPUT.PUT_LINE('p2 = ' || p2);
END;
/
Note there is no need for DECLARE with a named Procedure. The section between AS and BEGIN is for declaring variables, as I've done with l_salutation.
You can provide values for those parameters when invoking the program. In SQL*Plus it would work like this:
SET SERVEROUTPUT ON
accept p1 prompt "please enter 1 or 0: "
accept p2 prompt "please enter Y or N: "
exec HELLO (&p1, '&p2')
This piece of code works only in SQL*Plus and can't be used to produce a stored procedure!!!
DECLARE
variable1 NUMBER(1);
variable2 CHAR(1);
BEGIN
DBMS_OUTPUT.PUT_LINE('Hello World');
variable1 := &please_enter_1_or_0;
variable2 := '&please_enter_y_or_n';
END;
Mind the difference in the last statement where the last substitution variable is quoted in a string to be properly accepted by the PL/SQL syntax. Anyway, as I told you in the last comment to your question this is not a user interaction but just the result of a statement preprocessing. Every time you input different values the RDBMS executes a different source code.
Probably your requirement to use a "procedure" doesn't meant to use a STORED procedure(that is impossible to do so), but they just intended a SQL*Plus script, ask for clarifications.
You cannot directly receive messages from the client in a PL/SQL procedure or package.
The best you can do to emulate this is to interface with table data, and have users insert data into the table and react to that, or use Advanced Queueing (which amounts to pretty much the same thing).
Alternatively, accept the user input as parameters when the procedure is called.
You can just Remove the declare to remedy that ora error

Why is a semicolon expected in my SQL statement for inserting into two tables?

I'm trying to insert two sets of data into my database and it gives me an error saying that it is missing a semicolon at the end of the SQL statement.
Here is the code I've typed in:
procedure TForm9.Button1Click(Sender: TObject);
var
sNewTeam, sNewCountry : string;
begin
sNewTeam := InputBox('NEW','Insert The Name Of The New Team','',);
sNewCountry := InputBox ('NEW','Insert The New Country','');
qryAdmin.Active := false;
qryAdmin.SQL.Text := 'INSERT INTO Teams(Teams) VALUES("'+sNewTeam+'")' + 'Country(Teams) VALUES("'+sNewCountry+'")';
qryAdmin.ExecSQL;
end;
Thats 2 inserts into different tables so 2 INSERT INTO's are required.
Assuming your db supports delimiting statements with ; execute:
'INSERT INTO Teams(Teams) VALUES("'+sNewTeam+'"); INSERT INTO Country(Teams) VALUES("'+sNewCountry+'")';
You also should escape the input text to prevent injection/errors using whatever Paramaterization features are supported by your unnamed database client.