Fetch cursor with a variable column number
Hello guys,
this is the first time I write to this forum, as far as I remember. hence, if this is not the right place to ask this question, please point me to the right resource.
I have the following Procedure (the function split splits a string into an array):
BEGIN
/* SPLIT IN GROUPS AND BUILD THE PARAMETER STRINGS */
tokens_in := string_fnc.split(in_groups, '.');
for i in 1..tokens_in.count loop
IDX_REM := i;
sql_par1 := sql_par1 || ', GRP' || i || '.NAME "GROUP_' || i || '"';
sql_par2 := sql_par2 || ', DEV_XCSA.WFA_GROUP GRP' || i;
IF i = 1 THEN
sql_par3 := sql_par3 || ' AND S.ID = GRP1.FK_PARENT_SEC_ID ';
ELSE
sql_par3 := sql_par3 || ' AND GRP' || i || '.FK_PARENT_GROUP_ID ( + ) = GRP' || (i-1) || '.ID';
END IF;
end loop;
sql_par3 := sql_par3 || ' AND SGQ.FK_GROUP_ID ( + ) = GRP' || IDX_REM || '.ID';
/* BUILD THE QUERY STRING */
sql_stmt := 'SELECT A.NAME "APPRAISAL" , AQ.NAME "PROJECT" , S.NAME "SECTION"';
sql_stmt := sql_stmt || sql_par1;
sql_stmt := sql_stmt || ', SGQ.NAME "QUESTION" , SGQ.VALUE "ANSWER" FROM DEV_XCSA.WFA_APPRAISAL A, DEV_XCSA.WFA_QUESTIONNAIRE AQ, DEV_XCSA.WFA_SECTION S';
sql_stmt := sql_stmt || sql_par2;
sql_stmt := sql_stmt || ', DEV_XCSA.WFA_QUESTION SGQ WHERE A.CPHID = ''' ||USER_NAME || ''' AND A.ID = AQ.FK_APPRAISAL_ID AND AQ.ID = S.FK_QUESTIONNAIRE_ID';
sql_stmt := sql_stmt || sql_par3;
/* RUN THE QUERY */
OPEN QUEST_CUR FOR sql_stmt;
You can see that now the select statement has a variable number of return columns.
I would like to fetch the result of the query in a loop assigning the records to variables or to a record variable.
But after reading the documentation it looks that I can only declare record variables before the query string is built and there is not an easy way to fetch a cursor into a variable number of variables.
Is it possible to do what I am trying to do? Can you suggest a better approach?
Please help me,
TN
Tremal Naik wrote:
Ok, thanks to you both.
Please, bear in mind that I am really a PL/SQL novice and I may have misunderstood BluShadow's hints.
I will have a closer look at it and let you know my thoughts.Here's a cleaner commented example that should help you to understand what it's doing...
SQL> CREATE OR REPLACE PROCEDURE run_query(p_sql IN VARCHAR2) IS
2 v_v_val VARCHAR2(4000);
3 v_n_val NUMBER;
4 v_d_val DATE;
5 v_ret NUMBER;
6 c NUMBER;
7 d NUMBER;
8 col_cnt INTEGER;
9 f BOOLEAN;
10 rec_tab DBMS_SQL.DESC_TAB;
11 col_num NUMBER;
12 v_rowcount NUMBER := 0;
13 BEGIN
14 -- create a cursor
15 c := DBMS_SQL.OPEN_CURSOR;
16 -- parse the SQL statement into the cursor
17 DBMS_SQL.PARSE(c, p_sql, DBMS_SQL.NATIVE);
18 -- execute the cursor
19 d := DBMS_SQL.EXECUTE(c);
20 --
21 -- Describe the columns returned by the SQL statement
22 DBMS_SQL.DESCRIBE_COLUMNS(c, col_cnt, rec_tab);
23 --
24 -- Bind local return variables to the various columns based on their types
25 FOR j in 1..col_cnt
26 LOOP
27 CASE rec_tab(j).col_type
28 WHEN 1 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_v_val,2000); -- Varchar2
29 WHEN 2 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_n_val); -- Number
30 WHEN 12 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_d_val); -- Date
31 ELSE
32 DBMS_SQL.DEFINE_COLUMN(c,j,v_v_val,2000); -- Any other type return as varchar2
33 END CASE;
34 END LOOP;
35 --
36 -- Display what columns are being returned...
37 FOR j in 1..col_cnt
38 LOOP
39 DBMS_OUTPUT.PUT_LINE(rec_tab(j).col_name||' - '||case rec_tab(j).col_type when 1 then 'VARCHAR2'
40 when 2 then 'NUMBER'
41 when 12 then 'DATE'
42 else 'Other' end);
43 END LOOP;
44 --
45 -- This part outputs the DATA
46 LOOP
47 -- Fetch a row of data through the cursor
48 v_ret := DBMS_SQL.FETCH_ROWS(c);
49 -- Exit when no more rows
50 EXIT WHEN v_ret = 0;
51 v_rowcount := v_rowcount + 1;
52 DBMS_OUTPUT.PUT_LINE('Row: '||v_rowcount);
53 DBMS_OUTPUT.PUT_LINE('--------------');
54 -- Fetch the value of each column from the row
55 FOR j in 1..col_cnt
56 LOOP
57 -- Fetch each column into the correct data type based on the description of the column
58 CASE rec_tab(j).col_type
59 WHEN 1 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_v_val);
60 DBMS_OUTPUT.PUT_LINE(rec_tab(j).col_name||' : '||v_v_val);
61 WHEN 2 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_n_val);
62 DBMS_OUTPUT.PUT_LINE(rec_tab(j).col_name||' : '||v_n_val);
63 WHEN 12 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_d_val);
64 DBMS_OUTPUT.PUT_LINE(rec_tab(j).col_name||' : '||to_char(v_d_val,'DD/MM/YYYY HH24:MI:SS'));
65 ELSE
66 DBMS_SQL.COLUMN_VALUE(c,j,v_v_val);
67 DBMS_OUTPUT.PUT_LINE(rec_tab(j).col_name||' : '||v_v_val);
68 END CASE;
69 END LOOP;
70 DBMS_OUTPUT.PUT_LINE('--------------');
71 END LOOP;
72 --
73 -- Close the cursor now we have finished with it
74 DBMS_SQL.CLOSE_CURSOR(c);
75 END;
76 /
Procedure created.
SQL> exec run_query('select empno, ename, deptno from emp where deptno = 10');
EMPNO - NUMBER
ENAME - VARCHAR2
DEPTNO - NUMBER
Row: 1
EMPNO : 7782
ENAME : CLARK
DEPTNO : 10
Row: 2
EMPNO : 7839
ENAME : KING
DEPTNO : 10
Row: 3
EMPNO : 7934
ENAME : MILLER
DEPTNO : 10
PL/SQL procedure successfully completed.
SQL> exec run_query('select * from emp where deptno = 10');
EMPNO - NUMBER
ENAME - VARCHAR2
JOB - VARCHAR2
MGR - NUMBER
HIREDATE - DATE
SAL - NUMBER
COMM - NUMBER
DEPTNO - NUMBER
Row: 1
EMPNO : 7782
ENAME : CLARK
JOB : MANAGER
MGR : 7839
HIREDATE : 09/06/1981 00:00:00
SAL : 2450
COMM :
DEPTNO : 10
Row: 2
EMPNO : 7839
ENAME : KING
JOB : PRESIDENT
MGR :
HIREDATE : 17/11/1981 00:00:00
SAL : 5000
COMM :
DEPTNO : 10
Row: 3
EMPNO : 7934
ENAME : MILLER
JOB : CLERK
MGR : 7782
HIREDATE : 23/01/1982 00:00:00
SAL : 1300
COMM :
DEPTNO : 10
PL/SQL procedure successfully completed.
SQL> exec run_query('select * from dept where deptno = 10');
DEPTNO - NUMBER
DNAME - VARCHAR2
LOC - VARCHAR2
Row: 1
DEPTNO : 10
DNAME : ACCOUNTING
LOC : NEW YORK
PL/SQL procedure successfully completed.
SQL>As you can see, you can use DBMS_SQL to query any SQL string you like, regardless of the number of returned columns and their datatypes and the DBMS_SQL package can tell your code all the information it needs to know so that it can read the names, datatypes and data from that query.
Similar Messages
-
Slow performance when using cursor with bind variable
i'm facing the problem mentioned in the subject.
whenever i use the bind variable it would take more than 5mins to fetch 157 records, but if i hardcode the value ( not using variable ) it would take only 10sec to fetch 157 records.
can anyone give me some guide to solve this problem? thank you..
Code :
DECLARE
cursor cur1(l_startdate IN varchar2,l_enddate IN varchar2) IS
select * from shipment ship where ship.insertion_date >= to_date(l_startdate,'DD-MM-YYYY HH24:MI:SS') and ship.insertion_date < to_date(l_enddate ,'DD-MM-YYYY HH24:MI:SS')
TYPE shipment_aat IS TABLE OF cur1%ROWTYPE INDEX BY PLS_INTEGER;
l_shpt shipment_aat;
limit_in INTEGER := 100;
BEGIN
v_startdate := '10-06-2008 14:00:00';
v_enddate := '10-06-2008 17:00:00';
OPEN C_shpt(v_startdate,v_enddate);
LOOP --start shipment loop
FETCH C_shpt BULK COLLECT INTO l_shpt LIMIT limit_in;
FOR indx IN 1 .. l_shpt.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE('l_shpt value ' || l_shpt(indx).ship_number || '/' || l_shpt(indx).insertion_date);
END LOOP;
EXIT WHEN l_shpt.COUNT < limit_in;
END LOOP; -- end of shipment loop
CLOSE cur1;
END;When your query takes too long ...
-
How to trigger n number of jobs by processing using fetch cursor.
We have report which retrieves all the data from the master table using the open fetch cursor with the packet size 10,000
FOR EXAMPLE:
If there are 50,000 records(total)
For each 10,000 records it should trigger a job (we are trying to call a common program and submit the program in background through the main program ) were all the validation will be done only through the program
Totally we are expecting 5 job's to be trieggered.
Purpose : we want all the records validation to be completed Simultaneously with fraction of difference.Hi,
You might need to rethink on your scenario.
Where are the values for Vendor Region are getting stored for a PO? You might not be able to handle N number of Vendor regions for N number of Plants....You actually have to come to a 1:1 mapping. -
How to generate report with dynamic variable number of columns?
How to generate report with dynamic variable number of columns?
I need to generate a report with varying column names (state names) as follows:
SELECT AK, AL, AR,... FROM States ;
I get these column names from the result of another query.
In order to clarify my question, Please consider following table:
CREATE TABLE TIME_PERIODS (
PERIOD VARCHAR2 (50) PRIMARY KEY
CREATE TABLE STATE_INCOME (
NAME VARCHAR2 (2),
PERIOD VARCHAR2 (50) REFERENCES TIME_PERIODS (PERIOD) ,
INCOME NUMBER (12, 2)
I like to generate a report as follows:
AK CA DE FL ...
PERIOD1 1222.23 2423.20 232.33 345.21
PERIOD2
PERIOD3
Total 433242.23 56744.34 8872.21 2324.23 ...
The TIME_PERIODS.Period and State.Name could change dynamically.
So I can't specify the state name in Select query like
SELECT AK, AL, AR,... FROM
What is the best way to generate this report?SQL> -- test tables and test data:
SQL> CREATE TABLE states
2 (state VARCHAR2 (2))
3 /
Table created.
SQL> INSERT INTO states
2 VALUES ('AK')
3 /
1 row created.
SQL> INSERT INTO states
2 VALUES ('AL')
3 /
1 row created.
SQL> INSERT INTO states
2 VALUES ('AR')
3 /
1 row created.
SQL> INSERT INTO states
2 VALUES ('CA')
3 /
1 row created.
SQL> INSERT INTO states
2 VALUES ('DE')
3 /
1 row created.
SQL> INSERT INTO states
2 VALUES ('FL')
3 /
1 row created.
SQL> CREATE TABLE TIME_PERIODS
2 (PERIOD VARCHAR2 (50) PRIMARY KEY)
3 /
Table created.
SQL> INSERT INTO time_periods
2 VALUES ('PERIOD1')
3 /
1 row created.
SQL> INSERT INTO time_periods
2 VALUES ('PERIOD2')
3 /
1 row created.
SQL> INSERT INTO time_periods
2 VALUES ('PERIOD3')
3 /
1 row created.
SQL> INSERT INTO time_periods
2 VALUES ('PERIOD4')
3 /
1 row created.
SQL> CREATE TABLE STATE_INCOME
2 (NAME VARCHAR2 (2),
3 PERIOD VARCHAR2 (50) REFERENCES TIME_PERIODS (PERIOD),
4 INCOME NUMBER (12, 2))
5 /
Table created.
SQL> INSERT INTO state_income
2 VALUES ('AK', 'PERIOD1', 1222.23)
3 /
1 row created.
SQL> INSERT INTO state_income
2 VALUES ('CA', 'PERIOD1', 2423.20)
3 /
1 row created.
SQL> INSERT INTO state_income
2 VALUES ('DE', 'PERIOD1', 232.33)
3 /
1 row created.
SQL> INSERT INTO state_income
2 VALUES ('FL', 'PERIOD1', 345.21)
3 /
1 row created.
SQL> -- the basic query:
SQL> SELECT SUBSTR (time_periods.period, 1, 10) period,
2 SUM (DECODE (name, 'AK', income)) "AK",
3 SUM (DECODE (name, 'CA', income)) "CA",
4 SUM (DECODE (name, 'DE', income)) "DE",
5 SUM (DECODE (name, 'FL', income)) "FL"
6 FROM state_income, time_periods
7 WHERE time_periods.period = state_income.period (+)
8 AND time_periods.period IN ('PERIOD1','PERIOD2','PERIOD3')
9 GROUP BY ROLLUP (time_periods.period)
10 /
PERIOD AK CA DE FL
PERIOD1 1222.23 2423.2 232.33 345.21
PERIOD2
PERIOD3
1222.23 2423.2 232.33 345.21
SQL> -- package that dynamically executes the query
SQL> -- given variable numbers and values
SQL> -- of states and periods:
SQL> CREATE OR REPLACE PACKAGE package_name
2 AS
3 TYPE cursor_type IS REF CURSOR;
4 PROCEDURE procedure_name
5 (p_periods IN VARCHAR2,
6 p_states IN VARCHAR2,
7 cursor_name IN OUT cursor_type);
8 END package_name;
9 /
Package created.
SQL> CREATE OR REPLACE PACKAGE BODY package_name
2 AS
3 PROCEDURE procedure_name
4 (p_periods IN VARCHAR2,
5 p_states IN VARCHAR2,
6 cursor_name IN OUT cursor_type)
7 IS
8 v_periods VARCHAR2 (1000);
9 v_sql VARCHAR2 (4000);
10 v_states VARCHAR2 (1000) := p_states;
11 BEGIN
12 v_periods := REPLACE (p_periods, ',', ''',''');
13 v_sql := 'SELECT SUBSTR(time_periods.period,1,10) period';
14 WHILE LENGTH (v_states) > 1
15 LOOP
16 v_sql := v_sql
17 || ',SUM(DECODE(name,'''
18 || SUBSTR (v_states,1,2) || ''',income)) "' || SUBSTR (v_states,1,2)
19 || '"';
20 v_states := LTRIM (SUBSTR (v_states, 3), ',');
21 END LOOP;
22 v_sql := v_sql
23 || 'FROM state_income, time_periods
24 WHERE time_periods.period = state_income.period (+)
25 AND time_periods.period IN (''' || v_periods || ''')
26 GROUP BY ROLLUP (time_periods.period)';
27 OPEN cursor_name FOR v_sql;
28 END procedure_name;
29 END package_name;
30 /
Package body created.
SQL> -- sample executions from SQL:
SQL> VARIABLE g_ref REFCURSOR
SQL> EXEC package_name.procedure_name ('PERIOD1,PERIOD2,PERIOD3','AK,CA,DE,FL', :g_ref)
PL/SQL procedure successfully completed.
SQL> PRINT g_ref
PERIOD AK CA DE FL
PERIOD1 1222.23 2423.2 232.33 345.21
PERIOD2
PERIOD3
1222.23 2423.2 232.33 345.21
SQL> EXEC package_name.procedure_name ('PERIOD1,PERIOD2','AK,AL,AR', :g_ref)
PL/SQL procedure successfully completed.
SQL> PRINT g_ref
PERIOD AK AL AR
PERIOD1 1222.23
PERIOD2
1222.23
SQL> -- sample execution from PL/SQL block
SQL> -- using parameters derived from processing
SQL> -- cursors containing results of other queries:
SQL> DECLARE
2 CURSOR c_period
3 IS
4 SELECT period
5 FROM time_periods;
6 v_periods VARCHAR2 (1000);
7 v_delimiter VARCHAR2 (1) := NULL;
8 CURSOR c_states
9 IS
10 SELECT state
11 FROM states;
12 v_states VARCHAR2 (1000);
13 BEGIN
14 FOR r_period IN c_period
15 LOOP
16 v_periods := v_periods || v_delimiter || r_period.period;
17 v_delimiter := ',';
18 END LOOP;
19 v_delimiter := NULL;
20 FOR r_states IN c_states
21 LOOP
22 v_states := v_states || v_delimiter || r_states.state;
23 v_delimiter := ',';
24 END LOOP;
25 package_name.procedure_name (v_periods, v_states, :g_ref);
26 END;
27 /
PL/SQL procedure successfully completed.
SQL> PRINT g_ref
PERIOD AK AL AR CA DE FL
PERIOD1 1222.23 2423.2 232.33 345.21
PERIOD2
PERIOD3
PERIOD4
1222.23 2423.2 232.33 345.21 -
Can I retrieve cursor's value with variable columns?
I have a loop to check a bunch of columns in a cursor, I'd like to use a variable columns like following:
cursor cur
while ....
loop
cur.XXX
end loop;
here XXX are dynamical generated VARCHAR2.
Could you please tell me is it possible, or not?
Thanks alotThanks for reply, first. I have couple of columns like abc_1 to abc_100 in the table, I need to check their value one by one. I want to check them using something like abc_X, in the cursor. my thought is like below,
while i<= 100
loop
cur_name.abc_X
end loop
Just replace X with 1 to 100. -
Dynamic REF Cursor with Dynamic Fetch - Urgent
i have a pl/sql package with generates dynamic SQL statments. my problem is i want to open this SQL statment dynamically and fetch data in dynamic variable.
declare
type type_temp is REF CURSOR;
cur_temp type_temp;
mv_sql varchar2(4000);
begin
-- this will be dunamically generated and
-- hence could have any no. of columns.
mv_sql := select f1, f2, f3, f4 from table_temp;
open cur_temp for mv_sql;
fetch cur_temp into c1, c2, c3, c4;
close cur_temp;
end;
problem is my sql statment will have N no. of columns how can i fetch this N no. of columns.Very hard problem, because ref cursors do not (directly) support description!
Se mine (non-ideal) solution (it may be doable, but it isn't very practical
or easily maintainable):
1. "Generic" package
CREATE OR REPLACE PACKAGE dyn_fetch IS
TYPE ref_cur_t IS REF CURSOR;
g_query VARCHAR2 (32000);
g_count NUMBER;
g_desc_tab DBMS_SQL.DESC_TAB;
varchar2_type CONSTANT PLS_INTEGER := 1;
number_type CONSTANT PLS_INTEGER := 2;
date_type CONSTANT PLS_INTEGER := 12;
rowid_type CONSTANT PLS_INTEGER := 11;
char_type CONSTANT PLS_INTEGER := 96;
long_type CONSTANT PLS_INTEGER := 8;
raw_type CONSTANT PLS_INTEGER := 23;
mlslabel_type CONSTANT PLS_INTEGER := 106;
clob_type CONSTANT PLS_INTEGER := 112;
blob_type CONSTANT PLS_INTEGER := 113;
bfile_type CONSTANT PLS_INTEGER := 114;
PROCEDURE describe_columns;
FUNCTION record_def RETURN VARCHAR2;
END;
CREATE OR REPLACE PACKAGE BODY dyn_fetch IS
PROCEDURE describe_columns IS
l_cur INTEGER;
BEGIN
l_cur := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE (l_cur, g_query, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS (l_cur, g_count, g_desc_tab);
DBMS_SQL.CLOSE_CURSOR (l_cur);
EXCEPTION
WHEN OTHERS THEN
IF DBMS_SQL.IS_OPEN (l_cur) THEN
DBMS_SQL.CLOSE_CURSOR (l_cur);
END IF;
RAISE;
END;
FUNCTION record_def RETURN VARCHAR2 IS
l_record_def VARCHAR2 (32000);
l_type VARCHAR2 (100);
l_col_type PLS_INTEGER;
l_col_max_len PLS_INTEGER;
l_col_precision PLS_INTEGER;
l_col_scale PLS_INTEGER;
BEGIN
FOR i IN 1..g_count LOOP
l_col_type := g_desc_tab(i).col_type;
l_col_max_len := g_desc_tab(i).col_max_len;
l_col_precision := g_desc_tab(i).col_precision;
l_col_scale := g_desc_tab(i).col_scale;
IF l_col_type = varchar2_type THEN
l_type := 'VARCHAR2(' || l_col_max_len || ')';
ELSIF l_col_type = number_type THEN
l_type := 'NUMBER(' || l_col_precision || ',' || l_col_scale || ')';
ELSIF l_col_type = date_type THEN
l_type := 'DATE';
ELSIF l_col_type = rowid_type THEN
l_type := 'ROWID';
ELSIF l_col_type = char_type THEN
l_type := 'CHAR(' || l_col_max_len || ')';
-- ELSIF l_col_type = ...
-- long_type, raw_type ...
END IF;
l_record_def := l_record_def || ' col_' || i || ' ' || l_type || ',';
END LOOP;
l_record_def := RTRIM (l_record_def, ',');
RETURN l_record_def;
END;
END;
Note that procedure "record_def" creates columns names as col_1 (col_2 ...)
because SELECT clause in your query can be without aliases, for example
"SELECT deptno || dname FROM dept".
2. Your package which returns query nad ref cursor
CREATE OR REPLACE PACKAGE test IS
PROCEDURE set_query (p_query VARCHAR2 := NULL);
FUNCTION ref_cur RETURN dyn_fetch.ref_cur_t;
END;
CREATE OR REPLACE PACKAGE BODY test IS
PROCEDURE set_query (p_query VARCHAR2 := NULL) IS
l_query VARCHAR2 (32000) :=
' SELECT e.empno, e.ename,' ||
' e.deptno, d.dname' ||
' FROM emp e,' ||
' dept d' ||
' WHERE e.deptno = d.deptno';
BEGIN
IF p_query IS NULL THEN
dyn_fetch.g_query := l_query;
ELSE
dyn_fetch.g_query := p_query;
END IF;
END;
FUNCTION ref_cur RETURN dyn_fetch.ref_cur_t IS
l_ref_cur dyn_fetch.ref_cur_t;
BEGIN
OPEN l_ref_cur FOR dyn_fetch.g_query;
RETURN l_ref_cur;
END;
END;
Why we need two separate procedures (functions) in your package ?
a) Receiving program must use dynamic SQL, but in dynamic block we can access
only PL/SQL code elements that have global scope (standalone functions and procedures,
and elements defined in the specification of a package).
Unfortunately, cursor variables cannot be defined in the specification of a package
(cannot be global variables).
b) Receiving program must get the column list before ref cursor.
So, we have two options: call (in receiving program) the same function two times
(once to get the column list and once to return a ref cursor)
or use one procedure (or function) for returning query (to get the column list)
and second function for returning a ref cursor.
3. Your receiving program
CREATE OR REPLACE PROCEDURE test_fetch_ref_cur (p_query VARCHAR2 := NULL) IS
l_statement VARCHAR2 (32000);
FUNCTION process_def RETURN VARCHAR2 IS
l_process_def VARCHAR2 (32000);
BEGIN
l_process_def := 'DBMS_OUTPUT.PUT_LINE (';
FOR i IN 1 .. dyn_fetch.g_count LOOP
l_process_def := l_process_def || ' l_record.col_' || i || ' || ''>>'' || ';
END LOOP;
l_process_def := RTRIM (l_process_def, ' || ''>>'' || ') || ');';
RETURN l_process_def;
END;
BEGIN
test.set_query (p_query);
dyn_fetch.describe_columns;
l_statement :=
' DECLARE' ||
' TYPE record_t IS RECORD (' ||
dyn_fetch.record_def || ');' ||
' l_record record_t;' ||
' l_ref_cur dyn_fetch.ref_cur_t;' ||
' BEGIN' ||
' l_ref_cur := test.ref_cur;' ||
' LOOP' ||
' FETCH l_ref_cur INTO l_record;' ||
' EXIT WHEN l_ref_cur%NOTFOUND;' ||
process_def ||
' END LOOP;' ||
' CLOSE l_ref_cur;' ||
' END;';
EXECUTE IMMEDIATE l_statement;
END;
You can test this with:
SET SERVEROUTPUT ON;
EXECUTE test_fetch_ref_cur;
Note that we can try to use more generic solution:
CREATE OR REPLACE PACKAGE dyn_fetch IS
-- SAME AS BEFORE, PLUS:
PROCEDURE fetch_ref_cur (
p_function_ref_cur VARCHAR2,
p_process_def VARCHAR2);
END;
CREATE OR REPLACE PACKAGE BODY dyn_fetch IS
-- SAME AS BEFORE, PLUS:
PROCEDURE fetch_ref_cur (
p_function_ref_cur VARCHAR2,
p_process_def VARCHAR2)
IS
l_statement VARCHAR2 (32000);
BEGIN
l_statement :=
' DECLARE' ||
' TYPE record_t IS RECORD (' ||
record_def || ');' ||
' l_record record_t;' ||
' l_ref_cur dyn_fetch.ref_cur_t;' ||
' BEGIN' ||
' l_ref_cur := ' ||
p_function_ref_cur || ';' ||
' LOOP' ||
' FETCH l_ref_cur INTO l_record;' ||
' EXIT WHEN l_ref_cur%NOTFOUND;' ||
p_process_def ||
' END LOOP;' ||
' CLOSE l_ref_cur;' ||
' END;';
EXECUTE IMMEDIATE l_statement;
END;
END;
CREATE OR REPLACE PROCEDURE test_fetch_ref_cur (p_query VARCHAR2 := NULL) IS
FUNCTION process_def RETURN VARCHAR2 IS
-- SAME AS BEFORE
END;
BEGIN
test.set_query (p_query);
dyn_fetch.describe_columns;
dyn_fetch.fetch_ref_cur (
p_function_ref_cur => 'test.ref_cur',
p_process_def => process_def);
END;
Regards,
Zlatko Sirotic -
Dynamic Ref Cursor with Dynamic Fetch
Hi,
I'm using dynamic sql (DBMS_SQL) to define columns of ref cursor.
It works Ok but the problem is when i'm using PL/SQL CURSOR in the REF CURSOR. Then,
I'm getting :
Error at line 3
ORA-00932: inconsistent datatypes: expected NUMBER got CURSER
ORA-06512: at "SYS.DBMS_SQL", line 1830
ORA-06512: at "TW.PRINT_REF_CURSOR", line 28
ORA-06512: at line 9
Here is my code:
set serveroutput on
exec DBMS_OUTPUT.ENABLE(1000000);
declare
l_cursor sys_refcursor;
begin
OPEN l_cursor FOR
SELECT SERVICE_TABLE.SERVICE, SERVICE_TABLE.SERVICE_GROUP, SERVICE_TABLE.SERVICE_DESC,
CURSOR(SELECT SERVICE_TABLE.SERVICE_CD FROM SERVICE_TABLE) SERVICE_CD_CURSOR
FROM SERVICE_TABLE ;
print_ref_cursor( l_cursor );
end;
=========================
CREATE OR REPLACE procedure print_ref_cursor
( p_query in out sys_refcursor,
p_date_fmt in varchar2 default 'dd-mon-yyyy hh24:mi:ss' )
is
l_theCursor integer;
l_columnValue varchar2(4000);
l_descTbl dbms_sql.desc_tab2;
l_colCnt number;
l_date date;
l_cursor SYS_REFCURSOR;
begin
l_theCursor := dbms_sql.to_cursor_number( p_query );
dbms_sql.describe_columns2
( l_theCursor, l_colCnt, l_descTbl );
-- define all columns to be cast to varchar2's, we
-- are just printing them out
for i in 1 .. l_colCnt loop
if ( l_descTbl(i).col_type in ( 12, 178, 179, 180, 181, 231 ) )
then
dbms_sql.define_column
(l_theCursor, i, l_date );
else
dbms_sql.define_column
(l_theCursor, i, l_columnValue, 4000);
end if;
end loop;
while ( dbms_sql.fetch_rows(l_theCursor) > 0 )
loop
for i in 1 .. l_colCnt loop
if ( l_descTbl(i).col_type in ( 12, 178, 179, 180, 181, 231 ) )
then
dbms_sql.column_value( l_theCursor, i, l_date );
l_columnValue := to_char( l_date, p_date_fmt );
else
dbms_sql.column_value( l_theCursor, i, l_columnValue );
end if;
dbms_output.put_line
( rpad( l_descTbl(i).col_schema_name || '.' ||
l_descTbl(i).col_name, 30 ) || ': ' || l_columnValue );
end loop;
dbms_output.put_line( '-----------------' );
end loop;
dbms_sql.close_cursor( l_theCursor );
end;
Is there a solution or bypass?
Regards,
Tamir GevaNo. The problem is that one cannot use DBMS_SQL.define_column() to define that column in the SQL projection as a cursor, and then use DBMS_SQL.column_value() to read it into a ref cursor variable.
You can however detect the cursor column - the DBMS_SQL.describe_columns3() call will return a col_type value of 102. In which case you can treat it as an exception (i.e. not process that column in the projection).
As a general issue - a cursor as a SQL column projection does not make sense to me. I have never used this in any production code. Nor do I see any reasons why.
If you want that column in the projection to contain a "list" of sorts (the results of the cursor), then a nested table type can be used as projected type and the MultiSet() function used to execute the in-line SQL and provide that SQL cursor's result as an array/nested table.
But even this approach raises the question why a standard relational join is not used? -
Is there any way to spool with variable column size?
Hi, I'm spooling to a CSV file with the following script (the real SELECT is different but similar, Oracle 10.2.0.3.0):
SET COLSEP ';'
SET FEEDBACK OFF
SET LINESIZE 2000
SET PAGESIZE 0
SET TERMOUT OFF
SET TRIMSPOOL ON
SET VERIFY OFF
SPOOL test.csv REPLACE
SELECT 'COLUMN1', 'COLUMN2', 'COLUMN3' FROM dual UNION ALL
SELECT 'value1', NULL, NULL FROM dual UNION ALL
SELECT 'value2', NULL, NULL FROM dual;
SPOOL OFF
EXIT SUCCESS COMMITThis produces the following output:
COLUMN1;COLUMN2;COLUMN3
value1 ; ;
value2 ; ;Is there any way to get the following output with variable column size
COLUMN1;COLUMN2;COLUMN3
value1;;
value2;;I've tried SET NULL '' but I see no difference. Thanks in advance!
MarkusIn short, No, because SQL*Plus is laying out the data in columns.
You could either combine the data into a single column by concatenating as strings or use some other method e.g.
As sys user:
CREATE OR REPLACE DIRECTORY TEST_DIR AS '\tmp\myfiles'
GRANT READ, WRITE ON DIRECTORY TEST_DIR TO myuser
/As myuser:
CREATE OR REPLACE PROCEDURE run_query(p_sql IN VARCHAR2
,p_dir IN VARCHAR2
,p_header_file IN VARCHAR2
,p_data_file IN VARCHAR2 := NULL) IS
v_finaltxt VARCHAR2(4000);
v_v_val VARCHAR2(4000);
v_n_val NUMBER;
v_d_val DATE;
v_ret NUMBER;
c NUMBER;
d NUMBER;
col_cnt INTEGER;
f BOOLEAN;
rec_tab DBMS_SQL.DESC_TAB;
col_num NUMBER;
v_fh UTL_FILE.FILE_TYPE;
v_samefile BOOLEAN := (NVL(p_data_file,p_header_file) = p_header_file);
BEGIN
c := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(c, p_sql, DBMS_SQL.NATIVE);
d := DBMS_SQL.EXECUTE(c);
DBMS_SQL.DESCRIBE_COLUMNS(c, col_cnt, rec_tab);
FOR j in 1..col_cnt
LOOP
CASE rec_tab(j).col_type
WHEN 1 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_v_val,2000);
WHEN 2 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_n_val);
WHEN 12 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_d_val);
ELSE
DBMS_SQL.DEFINE_COLUMN(c,j,v_v_val,2000);
END CASE;
END LOOP;
-- This part outputs the HEADER
v_fh := UTL_FILE.FOPEN(upper(p_dir),p_header_file,'w',32767);
FOR j in 1..col_cnt
LOOP
v_finaltxt := ltrim(v_finaltxt||','||lower(rec_tab(j).col_name),',');
END LOOP;
-- DBMS_OUTPUT.PUT_LINE(v_finaltxt);
UTL_FILE.PUT_LINE(v_fh, v_finaltxt);
IF NOT v_samefile THEN
UTL_FILE.FCLOSE(v_fh);
END IF;
-- This part outputs the DATA
IF NOT v_samefile THEN
v_fh := UTL_FILE.FOPEN(upper(p_dir),p_data_file,'w',32767);
END IF;
LOOP
v_ret := DBMS_SQL.FETCH_ROWS(c);
EXIT WHEN v_ret = 0;
v_finaltxt := NULL;
FOR j in 1..col_cnt
LOOP
CASE rec_tab(j).col_type
WHEN 1 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_v_val);
v_finaltxt := ltrim(v_finaltxt||',"'||v_v_val||'"',',');
WHEN 2 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_n_val);
v_finaltxt := ltrim(v_finaltxt||','||v_n_val,',');
WHEN 12 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_d_val);
v_finaltxt := ltrim(v_finaltxt||','||to_char(v_d_val,'DD/MM/YYYY HH24:MI:SS'),',');
ELSE
v_finaltxt := ltrim(v_finaltxt||',"'||v_v_val||'"',',');
END CASE;
END LOOP;
-- DBMS_OUTPUT.PUT_LINE(v_finaltxt);
UTL_FILE.PUT_LINE(v_fh, v_finaltxt);
END LOOP;
UTL_FILE.FCLOSE(v_fh);
DBMS_SQL.CLOSE_CURSOR(c);
END;This allows for the header row and the data to be written to seperate files if required.
e.g.
SQL> exec run_query('select * from emp','TEST_DIR','output.txt');
PL/SQL procedure successfully completed.Output.txt file contains:
empno,ename,job,mgr,hiredate,sal,comm,deptno
7369,"SMITH","CLERK",7902,17/12/1980 00:00:00,800,,20
7499,"ALLEN","SALESMAN",7698,20/02/1981 00:00:00,1600,300,30
7521,"WARD","SALESMAN",7698,22/02/1981 00:00:00,1250,500,30
7566,"JONES","MANAGER",7839,02/04/1981 00:00:00,2975,,20
7654,"MARTIN","SALESMAN",7698,28/09/1981 00:00:00,1250,1400,30
7698,"BLAKE","MANAGER",7839,01/05/1981 00:00:00,2850,,30
7782,"CLARK","MANAGER",7839,09/06/1981 00:00:00,2450,,10
7788,"SCOTT","ANALYST",7566,19/04/1987 00:00:00,3000,,20
7839,"KING","PRESIDENT",,17/11/1981 00:00:00,5000,,10
7844,"TURNER","SALESMAN",7698,08/09/1981 00:00:00,1500,0,30
7876,"ADAMS","CLERK",7788,23/05/1987 00:00:00,1100,,20
7900,"JAMES","CLERK",7698,03/12/1981 00:00:00,950,,30
7902,"FORD","ANALYST",7566,03/12/1981 00:00:00,3000,,20
7934,"MILLER","CLERK",7782,23/01/1982 00:00:00,1300,,10The procedure allows for the header and data to go to seperate files if required. Just specifying the "header" filename will put the header and data in the one file.
Adapt to output different datatypes and styles are required. -
Pivot table with variables columns
I need a helo to pivot table with variable columns,
I have a pivot table :
SELECT a.*
FROM (SELECT codigo_aluno,nome_aluno , id_curso,dia FROM c_frequencia where dia like '201308%') PIVOT (sum(null) FOR dia IN ('20130805' ,'20130812','20130819','20130826')) a
but I need to run the select with values for dia , getting from a other table :
SELECT a.*
FROM (SELECT codigo_aluno,nome_aluno , id_curso,dia FROM c_frequencia where dia like '201308%') PIVOT (sum(null) FOR dia IN (
select dia from v_dia_mes )) a
thank youThe correct answer should be "Use the Pivoted Report Region Plugin".
But, as far as I know, nobody has created/posted that type of APEX plugin.
You may have to use a Basic Report (not an IR) so that you can use "Function returning SELECT" for your Source.
You would need two functions:
One that dynamically generates the Column Names
One that dynamically generates the SELECT statement
These should be in a PL/SQL Package so that the later can call the former to ensure that the column data matches the column names.
i.e. -- no 'SELECT *'
MK -
Can we specify the next screen number with a variable?
hi
can we specify the next screen number with a variable?yes, dynamicaly u can. i.e using set screen or call screen.
but u cant obviously set a variable in the attributes. -
Need help with Fluid Grid Layout and variable column balance.
I'm using the fluid grid layout. I have multiple columns that are actually fluid grid layout columns done by Dreamweaver. I'd like them to extend as high as each other (all to the maximum height of each other) within the same section. An added catch is that in the desktop layout, I have three side by side under one that takes the whole width of the page. On tablet size, it's 2x2 in a square grid. On mobile, they're vertically stacked. I'm trying to get it so that background colour and/or borders looks decent and is fully balanced, no matter which layout is hit with the fluid layout. The columns reflow, no problem. But the height of any background and/or border is variable.
Any help on fixing this?
Example at: https://music2help.thoughtburst.net/
The example doesn't have borders or colours, as it looked silly unbalanced. The music2help.css is the only one I'm modifying manually.
Love the fluid grid layout, but I need a way to make it behave decently with backgrounds/borders. Any help would be hugely appreciated!
Thanks!
mark->I tried the solution Nancy posted. It altered things, but doesn't seem to do the trick.
Just some quick background. I did HTML from 1994 through about five years ago by hand in vi on *nix systems. I learned HTML through 4.01, and never bothered with XHTML at all. I learned CSS through most of CSS2. The CSS3 and HTML5 stuff is all new to me, but it can't be that hard. I'm not exactly a novice in JS (I've done a fair bit of AJAX programming), but it's not even close to my primary language (I'm a Perl guy).
I'm "stuck on" wanting to use Fluid Grid Layouts. It's billed as one of the selling points of DW CS6, and I really like the concept and results. I just want the results embellished a little, namely with sensible identical heights on grid containers set in the same row, so that you can apply background colours, dropshadows, and borders. That's really all I want to do that it doesn't already do.
I have a test page at: http://music2help.thoughtburst.net/ that you can try with your Quick Columns. I'd be interested to know if you can get it to work.
Here's the catch, though... Resize the browser, shrinking it inwards. (I suggest Firefox, as Chrome only shrinks so far, and you won't get to Mobile width.) As you can see, on a Tablet, one of the columns that should be equal height actually moves up a row and should be equal height with the row that, on a desktop, would take the entire width of the page area. So that's like a 4-up output in printing terms. At Mobile size, the entire thing is vertical, so none of the columns should be resized.
If your product works and can accomodate these conditions, I think I would be interested in spending the $35 it costs.
Let me know? Thanks!
EDIT: Changed URL to be non-SSL. The server has multiple vhosts on it, and I keep forgetting that I don't have a cert on this new one. Sorry about that. You can just add anything to one of the the three middle columns, if you're pulling it down to test. -
Problem with fetch cursor statement
Hi,
I am using FETCH CURSOR statement to fetch the data from a database table with package size. For the fetched records I am doing parallel processing using parallel processing frame work in banking system.
Here the problem is for the first iteration it works fine but when it comes to FETCH NEXT CURSOR in the second iteration , programs gets dumping by saying that 'CURSOR already closed'.
I am not closing the cursor in the program but some how it got closed some where in the standard function module which I used for parallel processing.
I used WITHHOLD also along with FETCH CURSOR but no use. Please let me know how to avoid the cursor to get close.
Below is my code
IF NOT l_tab_product IS INITIAL.
OPEN CURSOR WITH HOLD lv_cursor FOR
SELECT contract_int prodint cn_currency mig_grp
INTO TABLE gt_cont
FROM bca_contract
FOR ALL ENTRIES IN l_tab_product
WHERE prodint = l_tab_product-prodint
AND mig_grp IN s_migrp.
DO.
FETCH NEXT CURSOR lv_cursor
INTO TABLE gt_cont
PACKAGE SIZE lv_size.
IF sy-subrc <> 0.
CLOSE CURSOR lv_cursor.
EXIT.
ELSE.
parallel processing logic
ENDDO.
ENDIF.Using Withhold will not make sure that the cursor will not get closed because of commits.
SAP Doc says
If the addition WITH HOLD is specified, the database cursor is not closed by a database commit executed using Native SQL. The addition does not have an influence, however, on implicit database commits or on any rollbacks which always close the database cursor.
You have to check the part written in your parallel processing logic.
As Brad said please donot dump your old threads like this. -
Using column number inplace of column name in SQL Select statement
Is there a way to run sql select statements with column numbers in
place of column names?
Current SQL
select AddressId,Name,City from AddressIs this possible
select 1,2,5 from AddressThanks in Advanceuser10962462 wrote:
well, ok, it's not possible with SQL, but how about PL/SQL?As mentioned, using DBMS_SQL you can only really use positional notation... and you can also use those positions to get the other information such as what the column is called, what it's datatype is etc.
CREATE OR REPLACE PROCEDURE run_query(p_sql IN VARCHAR2) IS
v_v_val VARCHAR2(4000);
v_n_val NUMBER;
v_d_val DATE;
v_ret NUMBER;
c NUMBER;
d NUMBER;
col_cnt INTEGER;
f BOOLEAN;
rec_tab DBMS_SQL.DESC_TAB;
col_num NUMBER;
v_rowcount NUMBER := 0;
BEGIN
-- create a cursor
c := DBMS_SQL.OPEN_CURSOR;
-- parse the SQL statement into the cursor
DBMS_SQL.PARSE(c, p_sql, DBMS_SQL.NATIVE);
-- execute the cursor
d := DBMS_SQL.EXECUTE(c);
-- Describe the columns returned by the SQL statement
DBMS_SQL.DESCRIBE_COLUMNS(c, col_cnt, rec_tab);
-- Bind local return variables to the various columns based on their types
FOR j in 1..col_cnt
LOOP
CASE rec_tab(j).col_type
WHEN 1 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_v_val,2000); -- Varchar2
WHEN 2 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_n_val); -- Number
WHEN 12 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_d_val); -- Date
ELSE
DBMS_SQL.DEFINE_COLUMN(c,j,v_v_val,2000); -- Any other type return as varchar2
END CASE;
END LOOP;
-- Display what columns are being returned...
DBMS_OUTPUT.PUT_LINE('-- Columns --');
FOR j in 1..col_cnt
LOOP
DBMS_OUTPUT.PUT_LINE(rec_tab(j).col_name||' - '||case rec_tab(j).col_type when 1 then 'VARCHAR2'
when 2 then 'NUMBER'
when 12 then 'DATE'
else 'Other' end);
END LOOP;
DBMS_OUTPUT.PUT_LINE('-------------');
-- This part outputs the DATA
LOOP
-- Fetch a row of data through the cursor
v_ret := DBMS_SQL.FETCH_ROWS(c);
-- Exit when no more rows
EXIT WHEN v_ret = 0;
v_rowcount := v_rowcount + 1;
DBMS_OUTPUT.PUT_LINE('Row: '||v_rowcount);
DBMS_OUTPUT.PUT_LINE('--------------');
-- Fetch the value of each column from the row
FOR j in 1..col_cnt
LOOP
-- Fetch each column into the correct data type based on the description of the column
CASE rec_tab(j).col_type
WHEN 1 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_v_val);
DBMS_OUTPUT.PUT_LINE(rec_tab(j).col_name||' : '||v_v_val);
WHEN 2 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_n_val);
DBMS_OUTPUT.PUT_LINE(rec_tab(j).col_name||' : '||v_n_val);
WHEN 12 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_d_val);
DBMS_OUTPUT.PUT_LINE(rec_tab(j).col_name||' : '||to_char(v_d_val,'DD/MM/YYYY HH24:MI:SS'));
ELSE
DBMS_SQL.COLUMN_VALUE(c,j,v_v_val);
DBMS_OUTPUT.PUT_LINE(rec_tab(j).col_name||' : '||v_v_val);
END CASE;
END LOOP;
DBMS_OUTPUT.PUT_LINE('--------------');
END LOOP;
-- Close the cursor now we have finished with it
DBMS_SQL.CLOSE_CURSOR(c);
END;
SQL> exec run_query('select empno, ename, deptno, sal from emp where deptno = 10');
-- Columns --
EMPNO - NUMBER
ENAME - VARCHAR2
DEPTNO - NUMBER
SAL - NUMBER
Row: 1
EMPNO : 7782
ENAME : CLARK
DEPTNO : 10
SAL : 2450
Row: 2
EMPNO : 7839
ENAME : KING
DEPTNO : 10
SAL : 5000
Row: 3
EMPNO : 7934
ENAME : MILLER
DEPTNO : 10
SAL : 1300
PL/SQL procedure successfully completed.
SQL> exec run_query('select * from emp where deptno = 10');
-- Columns --
EMPNO - NUMBER
ENAME - VARCHAR2
JOB - VARCHAR2
MGR - NUMBER
HIREDATE - DATE
SAL - NUMBER
COMM - NUMBER
DEPTNO - NUMBER
Row: 1
EMPNO : 7782
ENAME : CLARK
JOB : MANAGER
MGR : 7839
HIREDATE : 09/06/1981 00:00:00
SAL : 2450
COMM :
DEPTNO : 10
Row: 2
EMPNO : 7839
ENAME : KING
JOB : PRESIDENT
MGR :
HIREDATE : 17/11/1981 00:00:00
SAL : 5000
COMM :
DEPTNO : 10
Row: 3
EMPNO : 7934
ENAME : MILLER
JOB : CLERK
MGR : 7782
HIREDATE : 23/01/1982 00:00:00
SAL : 1300
COMM :
DEPTNO : 10
PL/SQL procedure successfully completed.
SQL> exec run_query('select * from dept where deptno = 10');
-- Columns --
DEPTNO - NUMBER
DNAME - VARCHAR2
LOC - VARCHAR2
Row: 1
DEPTNO : 10
DNAME : ACCOUNTING
LOC : NEW YORK
PL/SQL procedure successfully completed.
SQL> -
Create collection from query with bind variable
Apex 4.0.2
Per Joel Re: Collection with bind variable the apex_collection.create_collection_from_query_b supports queries containing bind variable references (:P1_X) but I am not sure how to use this feature, the documentation doesn't have an example, just the API signature for the overloaded version has changed.
If the query contains 2 bind variable references to session state (:P1_X and :P1_Y), can someone please show an example of what to pass in for the p_names and p_values parameters to the API?
Thanks
procedure create_collection_from_query_b(
-- Create a named collection from the supplied query using bulk operations. The query will
-- be parsed as the application owner. If a collection exists with the same name for the current
-- user in the same session for the current Flow ID, an application error will be raised.
-- This procedure uses bulk dynamic SQL to perform the fetch and insert operations into the named
-- collection. Two limitations are imposed by this procedure:
-- 1) The MD5 checksum for the member data will not be computed
-- 2) No column value in query p_query can exceed 2,000 bytes
-- Arguments:
-- p_collection_name = Name of collection. Maximum length can be
-- 255 bytes. Note that collection_names are case-insensitive,
-- as the collection name will be converted to upper case
-- p_query = Query to be executed which will populate the members of the
-- collection. If p_query is numeric, it is assumed to be
-- a DBMS_SQL cursor.
-- example(s):
-- l_query := 'select make, model, caliber from firearms';
-- apex_collection.create_collection_from_query_b( p_collection_name => 'Firearm', p_query => l_query );
p_collection_name in varchar2,
p_query in varchar2,
p_names in wwv_flow_global.vc_arr2,
p_values in wwv_flow_global.vc_arr2,
p_max_row_count in number default null)
;VANJ wrote:
Apex 4.0.2
Per Joel Re: Collection with bind variable the apex_collection.create_collection_from_query_b supports queries containing bind variable references (:P1_X) but I am not sure how to use this feature, the documentation doesn't have an example, just the API signature for the overloaded version has changed.
If the query contains 2 bind variable references to session state (:P1_X and :P1_Y), can someone please show an example of what to pass in for the p_names and p_values parameters to the API?Not tried it, but guessing something like
apex_collection.create_collection_from_query_b(
p_collection_name => 'foobar'
, p_query => 'select f.foo_id, b.bar_id, b.baz from foo f, bar b where f.foo_id = b.foo_id and f.x = to_number(:p1_x) and b.y = :p1_y'
, p_names => apex_util.string_to_table('p1_x:p1_y')
, p_values => apex_util.string_to_table(v('p1_x') || ':' || v('p1_y'))) -
Cursor based on variable?
I posted this issue in the APEX forum since I call my procedure through APEX, but I'm including it in here as well since the issue is with my cursor/loop:
In APEX, I have a process that calls apex_mail. I have a cursor/loop that pulls records meeting my criteria and lists them in the body of the mail. This all works. However, I added another field (field b) which in the app is dependent on field a. Rather than having 11 cursors defined that run according to my 'if' statements, I would like one cursor that is equal to the end result of my variable (v_sql). When I run the code below, I receive the following error: ORA-06550: line 11, column 22: PLS-00382: expression is of wrong type ORA-06550: line 11, column 3: PL/SQL: Statement ignored ORA-06550: line 68, column 18: PLS-00221: 'GATHER_USRS_CUR' is not a procedure or is undefined ORA-06550: line 68, column 3: PL/SQL: Statement ignored.
Code:
declare
e_body_1 CLOB;
e_body_2 CLOB;
j_sql CLOB :=null;
v_sql varchar2(2000);
-- Define cursor as SYS_REFCURSOR?
gather_usrs_cur SYS_REFCURSOR;
BEGIN
-- make cursor equal to variable of v_sql
gather_usrs_cur := v_sql;
-- Generate body of e-mail
e_body_1 := 'This e-mail is being generated to inform you that ... Those users are: '||utl_tcp.crlf||utl_tcp.crlf;
e_body_1 := e_body_1||'USER ID, FIRST, LAST, PHONE, E-MAIL'||utl_tcp.crlf;
e_body_1 := e_body_1||'==================================='||utl_tcp.crlf;
e_body_2 := utl_tcp.crlf||'Please review the accounts identified above and inform us .... We appreciate your follow-up regarding the account activity in your State.'||utl_tcp.crlf||utl_tcp.crlf;
e_body_2 := e_body_2||'Should you have any concerns/questions, please respond to the e-mail members on this e-mail.'||utl_tcp.crlf||utl_tcp.crlf;
e_body_2 := e_body_2||' Sincerely,'||utl_tcp.crlf||utl_tcp.crlf;
e_body_2 := e_body_2||' Team'||utl_tcp.crlf;
-- Conditions for determing value of v_sql which would ultimately be reflected in cursor, gather_usrs_cur
v_sql := 'select Q_APEX_ID,
USER_ID,
Q_USER_TYPE,
Q_FIRST,
Q_LAST,
C_PHONE,
C_EMAIL,
C_STATE
from Q_AUDIT
where MATCH = ''Y'' and
UPDT_ID is null and
UPDT_TS is null and
COMMENTS is null and
Q_USER_TYPE = :P32_USER_TYPE ';
if :P32_RO_USER_TYPE <> 'ALL' then
if :P32_RO_USER_TYPE = 1 then
v_sql := v_sql ||' and C_STATE in (''CT'',''MA'',''ME'',''NH'',''RI'',''VT'') ';
end if;
if :P32_RO_USER_TYPE = 2 then
v_sql := v_sql ||' and C_STATE in (''NJ'',''NY'',''PR'',''VI'') ';
end if;
if :P32_RO_USER_TYPE = 3 then
v_sql := v_sql ||' and C_STATE in (''DE'',''DC'',''MD'',''PA'',''VA'',''WV'') ';
end if;
if :P32_RO_USER_TYPE = 4 then
v_sql := v_sql ||' and C_STATE in (''AL'',''FL'',''GA'',''KY'',''MS'',''NC'',''SC'',''TN'') ';
end if;
if :P32_RO_USER_TYPE = 5 then
v_sql := v_sql ||' and C_STATE in (''IL'',''IN'',''MI'',''MN'',''OH'',''WI'') ';
end if;
if :P32_RO_USER_TYPE = 6 then
v_sql := v_sql ||' and C_STATE in (''AR'',''LA'',''NM'',''OK'',''TX'') ';
end if;
if :P32_RO_USER_TYPE = 7 then
v_sql := v_sql ||' and C_STATE in (''IA'',''KS'',''MO'',''NE'') ';
end if;
if :P32_RO_USER_TYPE = 8 then
v_sql := v_sql ||' and C_STATE in (''CO'',''MT'',''ND'',''SD'',''UT'',''WY'') ';
end if;
if :P32_RO_USER_TYPE = 9 then
v_sql := v_sql ||' and C_STATE in (''AZ'',''CA'',''HI'',''NV'') ';
end if;
if :P32_RO_USER_TYPE = 10 then
v_sql := v_sql ||' and C_STATE in (''AK'',''ID'',''OR'',''WA'') ';
end if;
end if;
-- call and loop through cursor for body of e-mail
for usr_rec in gather_usrs_cur
loop
begin
j_sql := j_sql ||usr_rec.user_id||', '||usr_rec.Q_first||', '||usr_rec.Q_last||', '||usr_rec.C_phone||', '||usr_rec.C_email||utl_tcp.crlf;
end;
end loop;
commit;
-- Call mail procedure
apex_mail.send(
P_TO => :P32_E_RECIPIENT,
P_CC => '[email protected], [email protected]',
P_FROM => '[email protected]',
P_BODY => e_body_1||j_sql||e_body_2,
P_SUBJ => 'Q Accounts Requiring Review');
end;
Is it possible to create one cursor that is equal to the 11 possible combinations, based on v_sql? Note that the :P32_X variables are set via buttons/fields in my APEX application. Thanks in advance for your help.I went ahead and rewrote this for you. Obviously I can't test it so no guarantees....
Are you putting this code directly in APEX? If so, notice how I took ":P32_USER_TYPE" out from being a literal in your string and put in a bind variable.
DECLARE
e_body_1 CLOB;
e_body_2 CLOB;
j_sql CLOB := NULL;
v_sql VARCHAR2 (2000);
usr_rec q_audit%ROWTYPE;
TYPE auditcurtype IS REF CURSOR;
v_audit_cur auditcurtype;
BEGIN
-- Generate body of e-mail
e_body_1 :=
'This e-mail is being generated to inform you that ... Those users are: '
|| UTL_TCP.crlf
|| UTL_TCP.crlf;
e_body_1 :=
e_body_1 || 'USER ID, FIRST, LAST, PHONE, E-MAIL' || UTL_TCP.crlf;
e_body_1 :=
e_body_1 || '===================================' || UTL_TCP.crlf;
e_body_2 :=
UTL_TCP.crlf
|| 'Please review the accounts identified above and inform us .... We appreciate your follow-up regarding the account activity in your State.'
|| UTL_TCP.crlf
|| UTL_TCP.crlf;
e_body_2 :=
e_body_2
|| 'Should you have any concerns/questions, please respond to the e-mail members on this e-mail.'
|| UTL_TCP.crlf
|| UTL_TCP.crlf;
e_body_2 := e_body_2 || ' Sincerely,' || UTL_TCP.crlf || UTL_TCP.crlf;
e_body_2 := e_body_2 || ' Team' || UTL_TCP.crlf;
-- Conditions for determing value of v_sql which would ultimately be reflected in cursor, gather_usrs_cur
v_sql :=
'select *
from Q_AUDIT
where MATCH = ''Y'' and
UPDT_ID is null and
UPDT_TS is null and
COMMENTS is null and
Q_USER_TYPE = :1';
IF :p32_ro_user_type <> 'ALL'
THEN
IF :p32_ro_user_type = 1
THEN
v_sql :=
v_sql
|| ' and C_STATE in (''CT'',''MA'',''ME'',''NH'',''RI'',''VT'') ';
END IF;
IF :p32_ro_user_type = 2
THEN
v_sql := v_sql || ' and C_STATE in (''NJ'',''NY'',''PR'',''VI'') ';
END IF;
IF :p32_ro_user_type = 3
THEN
v_sql :=
v_sql
|| ' and C_STATE in (''DE'',''DC'',''MD'',''PA'',''VA'',''WV'') ';
END IF;
IF :p32_ro_user_type = 4
THEN
v_sql :=
v_sql
|| ' and C_STATE in (''AL'',''FL'',''GA'',''KY'',''MS'',''NC'',''SC'',''TN'') ';
END IF;
IF :p32_ro_user_type = 5
THEN
v_sql :=
v_sql
|| ' and C_STATE in (''IL'',''IN'',''MI'',''MN'',''OH'',''WI'') ';
END IF;
IF :p32_ro_user_type = 6
THEN
v_sql :=
v_sql || ' and C_STATE in (''AR'',''LA'',''NM'',''OK'',''TX'') ';
END IF;
IF :p32_ro_user_type = 7
THEN
v_sql := v_sql || ' and C_STATE in (''IA'',''KS'',''MO'',''NE'') ';
END IF;
IF :p32_ro_user_type = 8
THEN
v_sql :=
v_sql
|| ' and C_STATE in (''CO'',''MT'',''ND'',''SD'',''UT'',''WY'') ';
END IF;
IF :p32_ro_user_type = 9
THEN
v_sql := v_sql || ' and C_STATE in (''AZ'',''CA'',''HI'',''NV'') ';
END IF;
IF :p32_ro_user_type = 10
THEN
v_sql := v_sql || ' and C_STATE in (''AK'',''ID'',''OR'',''WA'') ';
END IF;
END IF;
OPEN v_audit_cur FOR v_sql using :P32_USER_TYPE;
LOOP
FETCH v_audit_cur
INTO usr_rec;
EXIT WHEN v_audit_cur%NOTFOUND;
j_sql :=
j_sql
|| usr_rec.user_id
|| ', '
|| usr_rec.q_first
|| ', '
|| usr_rec.q_last
|| ', '
|| usr_rec.c_phone
|| ', '
|| usr_rec.c_email
|| UTL_TCP.crlf;
END LOOP;
CLOSE v_audit_cur;
-- No need for this, you aren't changing anything
-- COMMIT;
-- Call mail procedure
apex_mail.send (p_to => :p32_e_recipient,
p_cc => '[email protected], [email protected]',
p_from => '[email protected]',
p_body => e_body_1 || j_sql || e_body_2,
p_subj => 'Q Accounts Requiring Review'
END;
Hope this helps,
Steve
Alliance Technologies
Maybe you are looking for
-
Teacher looking for solution to generating a document linked to class roster.
I'm looking for an electronic version of the label. I want to create a document (like a worksheet) that has fields for Name, Hour, Date at the top. Then, I'd like the PDF to generate a worksheet per student on my roster, automatically filling in th
-
Update termination error at the time of order creation
Dear gurus, Facing an error at the time of creation of order. system is giving update termination error & when we are going in change mode of that order system is giving an error message " SD document XXXX is not in the database or has been achieved"
-
I can't use my Siri for directions or anything related to map as this function is only available for US. What a big disappointment !!!
-
Removing Reader 8.1.2
How do I remove Reader 8.1.2 ? There is no option to remove, change, install or repair in Control Panel - Add Remove Programs, althought it is listed there. It also has a folder in Program Files / Adobe with 2 subfolders (Reader, Resource)
-
Browser Crashed Every Time It Finds Updates
Every time the Update during a browser session finds updates for the Add-Ons, the browser crashes seconds later after I receive a notification pop-up of the updates available.