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

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;

Related

How to check that a value is NOT IN a %ROWTYPE from an SQL statement

Im writing a PLSQL stored procedure. Note that the below is only a part of it and the actual SP is complex than this. All I want to know is that in my nested query below, how i can check a certain value is not in the ROWTYPE that i named as 'l_05_data' ? Is there a way to do it without running thourgh a loop. Currently i have no idea on how to make this check in my nested query because im getting the below error when compiling. Someone please provide a solution for this.
**
Error(52,7): PL/SQL: SQL Statement ignored
Error(66,41): PL/SQL: ORA-00904: "l_05_data"."A2_ID_FK": invalid identifier
Error(66,51): PLS-00302: component 'A2_ID_FK' must be declared
**
stored procedure
create or replace PROCEDURE TEST_SP()
AS
TYPE r05_array IS TABLE OF A2_TBL%ROWTYPE;
l_05_data r05_array;
CURSOR r5_cur
IS
SELECT a2.*
FROM A2_TBL a2;
BEGIN
OPEN r5_cur;
LOOP
BEGIN
FETCH r5_cur BULK COLLECT INTO l_05_data LIMIT batch_limit;
EXIT WHEN l_05_data.count() = 0;
FOR indx IN l_05_data.FIRST ..l_05_data.LAST
LOOP
--some logic
END LOOP;
SELECT A1 BULK COLLECT
INTO l_01_id_data
FROM
( SELECT distinct column_value AS A1 FROM TABLE(l_01_id_data)
MINUS
(
SELECT distinct a1.A1_ID
FROM A1_TBL a1
INNER JOIN A2_TBL a2
ON a1.A1_ID = a2.A2_A1_ID_FK
WHERE a2.A2_STATUS !='X'
OR (a2.A2_A1_ID_FK NOT IN (l_05_data.A2_A1_ID_FK) AND a2.A2_STATUS = 'X')
)
);
COMMIT;
EXCEPTION
--exception is handled here
END;
END LOOP;
CLOSE r5_cur;
END TEST_SP;
below is the two table schema used in the SP

Declaring variables and select statement in a procedure

I'm writing a SQL procedure which should use calculated date stored as a local variable in a select statement. I'm using Oracle SQL developer. My code is:
create or replace PROCEDURE
my_procedure
AS
BEGIN
DECLARE
l_max_dt DATE;
BEGIN
SELECT MAX(TRX_DT)
INTO l_max_dt
FROM TABLE
WHERE 1=1;
end;
select * from TABLE where trx_dt = l_max_dt;
end;
This code gives me an error : " Error(14,48): PL/SQL: ORA-00904: "L_MAX_DT": invalid identifier" when select statement is present.
How can I store variables to use them in statements?
This is how you write a Procedure. Syntax is incorrect. Read about syntax Here
CREATE OR REPLACE PROCEDURE my_procedure
AS
l_max_dt DATE;
v_var TABLE2%ROWTYPE;
BEGIN
SELECT MAX (TRX_DT)
INTO l_max_dt
FROM TABLE1
WHERE 1 = 1;
-- Assuming the query will retrun only 1 row.
SELECT *
INTO v_var
FROM TABLE2
WHERE trx_dt = l_max_dt;
END;
Your issue is one of scope. In your procedure, you have a nested block, in which you declare the l_max_dt variable. Once the code has exited that block, the l_max_dt variable is no longer in scope - i.e. the outer block does not know anything about it.
There is no need to have a nested block in this instance - you can do it all in the same block, like so:
create or replace PROCEDURE my_procedure
AS
l_max_dt DATE;
BEGIN
SELECT MAX(TRX_DT)
INTO l_max_dt
FROM TABLE
WHERE 1=1;
-- commented out as this isn't valid syntax; there is a missing INTO clause
-- select *
-- from TABLE where trx_dt = l_max_dt;
END my_procedure;
However, you could simply do the query in one fell swoop - e.g.:
select *
from your_table
where trx_dt = (select max(trx_dt) from your_table);
A couple of points about your procedure:
In PL/SQL, if you use an implicit cursor (i.e. when you put a select statement directly in the body of the code) you need to have something to put the results into. You could bulk collect the results into an array, or you could ensure that you will receive exactly one row (or code error handling for NO_DATA_FOUND and TOO_MANY_ROWS) into a record or corresponding scalar variables.
You shouldn't use select * in your procedure - instead, you should explicitly state the columns being returned, because someone adding a column to that table could cause your procedure to error. There are exceptions to this "rule", but explicitly stating the columns is a good habit to get into.

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

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.

Using variables in PLSQL SELECT statement

I have a query that queries on ReportStartDate and ReportEndDate so I thought I would use variables in PLSQL. Not sure what I am missing here, but I get an error:
CLEAR;
DECLARE
varReportStartDate Date := to_date('05/01/2010', 'mm/dd/yyyy');
varReportEndDate Date := to_date('05/31/2010', 'mm/dd/yyyy');
BEGIN
SELECT
'Value TYPE',
1 AS CountType1,
2 AS CountType2,
3 AS CountType3
FROM DUAL;
SELECT COUNT (*)
FROM CDR.MSRS_E_INADVCH
WHERE 1=1
AND ReportStartDate = varReportStartDate
AND ReportEndDate = varReportEndDate
;
END;
/
The Error is:
Error starting at line 2 in command:
Error report:
ORA-06550: line 6, column 5:
PLS-00428: an INTO clause is expected in this SELECT statement
ORA-06550: line 8, column 5:
PLS-00428: an INTO clause is expected in this SELECT statement
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
This happens in Toad as well as in SQL Developer.
What is the proper way of using the variables in my WHERE clause?
You cannot use SQL statements directly in a PL/SQL block ( unless you use EXECUTE IMMEDIATE). The columns will need to be fetched into variables ( which is what PL/SQL is telling you with PLS-00428: an INTO clause is expected in this SELECT statement error). So you'll have to rewrite your statements as below.
SELECT
'Value TYPE',
1 AS CountType1,
2 AS CountType2,
3 AS CountType3
INTO
V_VALUE_TYPE,
V_CountType1,
V_CountType2,
V_CountType3
FROM DUAL;
SELECT COUNT(*)
INTO V_COUNT
FROM CDR.MSRS_E_INADVCH
WHERE 1=1
AND ReportStartDate = varReportStartDate
AND ReportEndDate = varReportEndDate
Be sure to add Exception Handlers, since PL/SQL expects only 1 row to be returned. If the statement returns no rows, you'll hit a NO_DATA_FOUND exception - and if the statement fetches too many rows, you'll hit a TOO_MANY_ROWS exception.
The question you have to answer is what do you want to do with the data that has been selected?
Sathya gave you one approach - declare variables in your PL/SQL block and select the columns INTO those variables. Note that this requires that the SELECT statement returns exactly one row - any more or less rows will throw an error. Another way is to declare collection types using the BULK COLLECT option: http://oracletoday.blogspot.com/2005/11/bulk-collect_15.html
Yet another option is to have the procedure return a cursor. This is useful in the case where the calling code expects to be able to fetch the data that the procedure has selected:
PROCEDURE GET_MY_REPORT( varReportStartDate in date, varReportEndDate in date, cur out sys_refcursor) is
begin
OPEN cur FOR SELECT *
FROM CDR.MSRS_E_INADVCH
WHERE 1=1
AND ReportStartDate = varReportStartDate
AND ReportEndDate = varReportEndDate;
END GET_MY_REPORT;

Get Column names with Delphi (Dbexpress)

I'm using this sql command to get column names :
select COLUMN_NAME from
INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = 'MyTableName'
but i don't know how can i using the executed SQL command results !
for example , this way doesn't work to extract the column names as a string value and i got this error = Operation Not Supported :
for i := 1 to Qry1.RecordCount do
begin
end;
Another way you can do this is to query the table itself to get an empty dataset, and then loop through the fields in that dataset.
A query like this will return the table structure with no records in it:
Qry1.SQL.Text := 'SELECT * FROM MyTableName WHERE 1<>1';
Qry1.Open;
And a loop like this will iterate through each field
for I := 0 to Qry1.FieldCount-1 do
begin
X := Qry1.Fields[I].FieldName;
// and do whatever you want with X
end;
Something like this would work for a TADOQuery (not sure if it's different for dbExpress):
Qry1.Open;
while not Qry1.Eof do begin
// do whatever with Qry1.Fields[0].AsString here
Qry1.Next;
end;
Qry1.Close;
From what I understand you are unable to retreive the retults.
Qry1.First;
while not Qry1.Eof do
begin
X := Qry1.FieldByName('column_name').AsString;
Qry1.Next;
end;
This is a piece of code which has always worked for me
Or you can read this link which explains why the exception is thrown when calling .RecordCount (http://edn.embarcadero.com/article/28494)
To sum it up it suggests that your query is case-sensitive and you should probably check the table name (MyTableName)
agree with Rob McDonell, in order to list the column name of a field, I'll use that
as in my code I wrote something like this
Procedure blablabla;
var i:integer;
begin
..... {some code here}
SQLQuery1.Open;
for i := 0 to SQLQuery1.FieldCount-1 do
begin;
Memo1.Lines.Append(SQLQuery1.Fields[i].DisplayName);
end;
SQLQuery1.Close;
.... {some code here}
end;