Transpose rows to columns in Oracle 10g : naming of the columns - sql

My select query is as follows :
SELECT
R.ID_REQUEST, R.ID_PROJET, J.NAME, L.DATE_ACTION,L.NAME_ACTION
, LEAD(L.DATE_ACTION) OVER (PARTITION BY R.ID_REQUEST ORDER BY L.DATE_ACTION)- L.DATE_ACTION AS TOTAL_DAYS
FROM (REQUEST R LEFT JOIN LOG_TABLE L ON R.ID_REQUEST = L.ID_REQUEST)
LEFT JOIN JOB_TABLE J ON R.ID_JOB = J.ID_JOB
WHERE D.ID_REQUEST = 10
The result is something like this :
ID_REQUEST ID_PROJET NAME DATE_ACTION NAME_ACTION TOTAL_DAYS
10 152 pr1 01/01/2005 arbitrary_name1 3
10 152 pr1 04/01/2005 arbitrary_name2 1
10 152 pr1 05/01/2005 arbitrary_name3 null
what I want is to put the names of the actions as columns. I know that i can do it using DECODE (since there is no pivotin 10g). but how to use the same name of the action as the name of the column ? The list of actions vary depending on the request. (the table log_table contains the actions per request, the number of actions is variable).
I hope my question is clear enough ! thanks.

This solution by someone much smarter than I am works well on 10 or 11 with a dynamic number of column. The only thing it doesn't do is order the columns.
And the implementation
SELECT *
FROM TABLE(DYNAMIC_PIVOT(
'SELECT emp_no,dept_no from emp group by emp_no'));
CREATE OR REPLACE TYPE PIVOTIMPL AS OBJECT
(
--from here https://technology.amis.nl/2006/05/24/dynamic-sql-pivoting-stealing-antons-thunder/
RET_TYPE ANYTYPE, -- The return type of the table function
STMT VARCHAR2(32767),
FMT VARCHAR2(32767),
CUR INTEGER,
STATIC FUNCTION ODCITABLEDESCRIBE(RTYPE OUT ANYTYPE,
P_STMT IN VARCHAR2,
P_FMT IN VARCHAR2 := 'upper(#p#)',
DUMMY IN NUMBER := 0) RETURN NUMBER,
STATIC FUNCTION ODCITABLEPREPARE(SCTX OUT PIVOTIMPL,
TI IN SYS.ODCITABFUNCINFO,
P_STMT IN VARCHAR2,
P_FMT IN VARCHAR2 := 'upper(#p#)',
DUMMY IN NUMBER := 0) RETURN NUMBER,
STATIC FUNCTION ODCITABLESTART(SCTX IN OUT PIVOTIMPL,
P_STMT IN VARCHAR2,
P_FMT IN VARCHAR2 := 'upper(#p#)',
DUMMY IN NUMBER := 0) RETURN NUMBER,
MEMBER FUNCTION ODCITABLEFETCH(SELF IN OUT PIVOTIMPL,
NROWS IN NUMBER,
OUTSET OUT ANYDATASET) RETURN NUMBER,
MEMBER FUNCTION ODCITABLECLOSE(SELF IN PIVOTIMPL) RETURN NUMBER
)
/
prompt
prompt Creating function DYNAMIC_PIVOT
prompt ===============================
prompt
CREATE OR REPLACE FUNCTION BROO1APP.DYNAMIC_PIVOT(P_STMT IN VARCHAR2,
P_FMT IN VARCHAR2 := 'upper(#p#)',
DUMMY IN NUMBER := 0)
RETURN ANYDATASET
PIPELINED USING PIVOTIMPL;
/
prompt
prompt Creating type body PIVOTIMPL
prompt ============================
prompt
CREATE OR REPLACE TYPE BODY BROO1APP.PIVOTIMPL AS
STATIC FUNCTION ODCITABLEDESCRIBE(RTYPE OUT ANYTYPE,
P_STMT IN VARCHAR2,
P_FMT IN VARCHAR2 := 'upper(#p#)',
DUMMY IN NUMBER) RETURN NUMBER IS
ATYP ANYTYPE;
CUR INTEGER;
NUMCOLS NUMBER;
DESC_TAB DBMS_SQL.DESC_TAB2;
RC SYS_REFCURSOR;
T_C2 VARCHAR2(32767);
T_FMT VARCHAR2(1000);
BEGIN
CUR := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(CUR, P_STMT, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS2(CUR, NUMCOLS, DESC_TAB);
DBMS_SQL.CLOSE_CURSOR(CUR);
--
ANYTYPE.BEGINCREATE(DBMS_TYPES.TYPECODE_OBJECT, ATYP);
FOR I IN 1 .. NUMCOLS - 2 LOOP
ATYP.ADDATTR(DESC_TAB(I).COL_NAME,
CASE DESC_TAB(I).COL_TYPE
WHEN 1 THEN
DBMS_TYPES.TYPECODE_VARCHAR2
WHEN 2 THEN
DBMS_TYPES.TYPECODE_NUMBER
WHEN 9 THEN
DBMS_TYPES.TYPECODE_VARCHAR2
WHEN 11 THEN
DBMS_TYPES.TYPECODE_VARCHAR2 -- show rowid as varchar2
WHEN 12 THEN
DBMS_TYPES.TYPECODE_DATE
WHEN 208 THEN
DBMS_TYPES.TYPECODE_VARCHAR2 -- show urowid as varchar2
WHEN 96 THEN
DBMS_TYPES.TYPECODE_CHAR
WHEN 180 THEN
DBMS_TYPES.TYPECODE_TIMESTAMP
WHEN 181 THEN
DBMS_TYPES.TYPECODE_TIMESTAMP_TZ
WHEN 231 THEN
DBMS_TYPES.TYPECODE_TIMESTAMP_LTZ
WHEN 182 THEN
DBMS_TYPES.TYPECODE_INTERVAL_YM
WHEN 183 THEN
DBMS_TYPES.TYPECODE_INTERVAL_DS
END,
DESC_TAB(I).COL_PRECISION,
DESC_TAB(I).COL_SCALE,
CASE DESC_TAB(I).COL_TYPE
WHEN 11 THEN
18 -- for rowid col_max_len = 16, and 18 characters are shown
ELSE
DESC_TAB(I).COL_MAX_LEN
END,
DESC_TAB(I).COL_CHARSETID,
DESC_TAB(I).COL_CHARSETFORM);
END LOOP;
IF INSTR(P_FMT, '#p#') > 0 THEN
T_FMT := P_FMT;
ELSE
T_FMT := '#p#';
END IF;
OPEN RC FOR REPLACE('select distinct ' || T_FMT || '
from( ' || P_STMT || ' )
order by ' || T_FMT,
'#p#',
DESC_TAB(NUMCOLS - 1).COL_NAME);
LOOP
FETCH RC
INTO T_C2;
EXIT WHEN RC%NOTFOUND;
ATYP.ADDATTR(T_C2,
CASE DESC_TAB(NUMCOLS).COL_TYPE WHEN 1 THEN
DBMS_TYPES.TYPECODE_VARCHAR2 WHEN 2 THEN
DBMS_TYPES.TYPECODE_NUMBER WHEN 9 THEN
DBMS_TYPES.TYPECODE_VARCHAR2 WHEN 11 THEN
DBMS_TYPES.TYPECODE_VARCHAR2 -- show rowid as varchar2
WHEN 12 THEN DBMS_TYPES.TYPECODE_DATE WHEN 208 THEN
DBMS_TYPES.TYPECODE_UROWID WHEN 96 THEN
DBMS_TYPES.TYPECODE_CHAR WHEN 180 THEN
DBMS_TYPES.TYPECODE_TIMESTAMP WHEN 181 THEN
DBMS_TYPES.TYPECODE_TIMESTAMP_TZ WHEN 231 THEN
DBMS_TYPES.TYPECODE_TIMESTAMP_LTZ WHEN 182 THEN
DBMS_TYPES.TYPECODE_INTERVAL_YM WHEN 183 THEN
DBMS_TYPES.TYPECODE_INTERVAL_DS END,
DESC_TAB(NUMCOLS).COL_PRECISION,
DESC_TAB(NUMCOLS).COL_SCALE,
CASE DESC_TAB(NUMCOLS).COL_TYPE WHEN 11 THEN 18 -- for rowid col_max_len = 16, and 18 characters are shown
ELSE DESC_TAB(NUMCOLS).COL_MAX_LEN END,
DESC_TAB(NUMCOLS).COL_CHARSETID,
DESC_TAB(NUMCOLS).COL_CHARSETFORM);
END LOOP;
CLOSE RC;
ATYP.ENDCREATE;
ANYTYPE.BEGINCREATE(DBMS_TYPES.TYPECODE_TABLE, RTYPE);
RTYPE.SETINFO(NULL,
NULL,
NULL,
NULL,
NULL,
ATYP,
DBMS_TYPES.TYPECODE_OBJECT,
0);
RTYPE.ENDCREATE();
RETURN ODCICONST.SUCCESS;
EXCEPTION
WHEN OTHERS THEN
RETURN ODCICONST.ERROR;
END;
--
STATIC FUNCTION ODCITABLEPREPARE(SCTX OUT PIVOTIMPL,
TI IN SYS.ODCITABFUNCINFO,
P_STMT IN VARCHAR2,
P_FMT IN VARCHAR2 := 'upper(#p#)',
DUMMY IN NUMBER) RETURN NUMBER IS
PREC PLS_INTEGER;
SCALE PLS_INTEGER;
LEN PLS_INTEGER;
CSID PLS_INTEGER;
CSFRM PLS_INTEGER;
ELEM_TYP ANYTYPE;
ANAME VARCHAR2(30);
TC PLS_INTEGER;
BEGIN
TC := TI.RETTYPE.GETATTRELEMINFO(1,
PREC,
SCALE,
LEN,
CSID,
CSFRM,
ELEM_TYP,
ANAME);
--
IF INSTR(P_FMT, '#p#') > 0 THEN
SCTX := PIVOTIMPL(ELEM_TYP, P_STMT, P_FMT, NULL);
ELSE
SCTX := PIVOTIMPL(ELEM_TYP, P_STMT, '#p#', NULL);
END IF;
RETURN ODCICONST.SUCCESS;
END;
--
STATIC FUNCTION ODCITABLESTART(SCTX IN OUT PIVOTIMPL,
P_STMT IN VARCHAR2,
P_FMT IN VARCHAR2 := 'upper(#p#)',
DUMMY IN NUMBER) RETURN NUMBER IS
CUR INTEGER;
NUMCOLS NUMBER;
DESC_TAB DBMS_SQL.DESC_TAB2;
T_STMT VARCHAR2(32767);
TYPE_CODE PLS_INTEGER;
PREC PLS_INTEGER;
SCALE PLS_INTEGER;
LEN PLS_INTEGER;
CSID PLS_INTEGER;
CSFRM PLS_INTEGER;
SCHEMA_NAME VARCHAR2(30);
TYPE_NAME VARCHAR2(30);
VERSION VARCHAR2(30);
ATTR_COUNT PLS_INTEGER;
ATTR_TYPE ANYTYPE;
ATTR_NAME VARCHAR2(100);
DUMMY2 INTEGER;
FIRST_COL VARCHAR2(30);
BEGIN
CUR := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(CUR, P_STMT, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS2(CUR, NUMCOLS, DESC_TAB);
DBMS_SQL.CLOSE_CURSOR(CUR);
--
FOR I IN 1 .. NUMCOLS - 2 LOOP
T_STMT := T_STMT || ', "' || DESC_TAB(I).COL_NAME || '"';
END LOOP;
--
TYPE_CODE := SCTX.RET_TYPE.GETINFO(PREC,
SCALE,
LEN,
CSID,
CSFRM,
SCHEMA_NAME,
TYPE_NAME,
VERSION,
ATTR_COUNT);
FOR I IN NUMCOLS - 1 .. ATTR_COUNT LOOP
TYPE_CODE := SCTX.RET_TYPE.GETATTRELEMINFO(I,
PREC,
SCALE,
LEN,
CSID,
CSFRM,
ATTR_TYPE,
ATTR_NAME);
T_STMT := T_STMT ||
REPLACE(', max( decode( ' || SCTX.FMT || ', ''' ||
ATTR_NAME || ''', ' || DESC_TAB(NUMCOLS)
.COL_NAME || ' ) )',
'#p#',
DESC_TAB(NUMCOLS - 1).COL_NAME);
END LOOP;
T_STMT := 'select ' || SUBSTR(T_STMT, 2) || ' from ( ' || SCTX.STMT || ' )';
FOR I IN 1 .. NUMCOLS - 2 LOOP
IF I = 1 THEN
T_STMT := T_STMT || ' group by "' || DESC_TAB(I).COL_NAME || '"';
FIRST_COL := DESC_TAB(I).COL_NAME;
ELSE
T_STMT := T_STMT || ', "' || DESC_TAB(I).COL_NAME || '"';
END IF;
END LOOP;
T_STMT := T_STMT || ' ORDER BY "' || FIRST_COL || '"';
--
DBMS_OUTPUT.PUT_LINE(T_STMT);
SCTX.CUR := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(SCTX.CUR, T_STMT, DBMS_SQL.NATIVE);
FOR I IN 1 .. ATTR_COUNT LOOP
TYPE_CODE := SCTX.RET_TYPE.GETATTRELEMINFO(I,
PREC,
SCALE,
LEN,
CSID,
CSFRM,
ATTR_TYPE,
ATTR_NAME);
CASE TYPE_CODE
WHEN DBMS_TYPES.TYPECODE_CHAR THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR, I, 'x', 32767);
WHEN DBMS_TYPES.TYPECODE_VARCHAR2 THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR, I, 'x', 32767);
WHEN DBMS_TYPES.TYPECODE_NUMBER THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR, I, CAST(NULL AS NUMBER));
WHEN DBMS_TYPES.TYPECODE_DATE THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR, I, CAST(NULL AS DATE));
WHEN DBMS_TYPES.TYPECODE_UROWID THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR, I, CAST(NULL AS UROWID));
WHEN DBMS_TYPES.TYPECODE_TIMESTAMP THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR, I, CAST(NULL AS TIMESTAMP));
WHEN DBMS_TYPES.TYPECODE_TIMESTAMP_TZ THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR, I, CAST(NULL AS TIMESTAMP WITH TIME ZONE));
WHEN DBMS_TYPES.TYPECODE_TIMESTAMP_LTZ THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR, I, CAST(NULL AS TIMESTAMP WITH LOCAL TIME ZONE));
WHEN DBMS_TYPES.TYPECODE_INTERVAL_YM THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR,
I,
CAST(NULL AS INTERVAL YEAR TO MONTH));
WHEN DBMS_TYPES.TYPECODE_INTERVAL_DS THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR,
I,
CAST(NULL AS INTERVAL DAY TO SECOND));
END CASE;
END LOOP;
DUMMY2 := DBMS_SQL.EXECUTE(SCTX.CUR);
RETURN ODCICONST.SUCCESS;
END;
--
MEMBER FUNCTION ODCITABLEFETCH(SELF IN OUT PIVOTIMPL,
NROWS IN NUMBER,
OUTSET OUT ANYDATASET) RETURN NUMBER IS
C1_COL_TYPE PLS_INTEGER;
TYPE_CODE PLS_INTEGER;
PREC PLS_INTEGER;
SCALE PLS_INTEGER;
LEN PLS_INTEGER;
CSID PLS_INTEGER;
CSFRM PLS_INTEGER;
SCHEMA_NAME VARCHAR2(30);
TYPE_NAME VARCHAR2(30);
VERSION VARCHAR2(30);
ATTR_COUNT PLS_INTEGER;
ATTR_TYPE ANYTYPE;
ATTR_NAME VARCHAR2(100);
V1 VARCHAR2(32767);
N1 NUMBER;
D1 DATE;
UR1 UROWID;
IDS1 INTERVAL DAY TO SECOND;
IYM1 INTERVAL YEAR TO MONTH;
TS1 TIMESTAMP;
TSTZ1 TIMESTAMP WITH TIME ZONE;
TSLTZ1 TIMESTAMP WITH LOCAL TIME ZONE;
BEGIN
OUTSET := NULL;
IF NROWS < 1 THEN
-- is this possible???
RETURN ODCICONST.SUCCESS;
END IF;
--
DBMS_OUTPUT.PUT_LINE('fetch');
IF DBMS_SQL.FETCH_ROWS(SELF.CUR) = 0 THEN
RETURN ODCICONST.SUCCESS;
END IF;
--
DBMS_OUTPUT.PUT_LINE('done');
TYPE_CODE := SELF.RET_TYPE.GETINFO(PREC,
SCALE,
LEN,
CSID,
CSFRM,
SCHEMA_NAME,
TYPE_NAME,
VERSION,
ATTR_COUNT);
ANYDATASET.BEGINCREATE(DBMS_TYPES.TYPECODE_OBJECT,
SELF.RET_TYPE,
OUTSET);
OUTSET.ADDINSTANCE;
OUTSET.PIECEWISE();
FOR I IN 1 .. ATTR_COUNT LOOP
TYPE_CODE := SELF.RET_TYPE.GETATTRELEMINFO(I,
PREC,
SCALE,
LEN,
CSID,
CSFRM,
ATTR_TYPE,
ATTR_NAME);
DBMS_OUTPUT.PUT_LINE(ATTR_NAME);
CASE TYPE_CODE
WHEN DBMS_TYPES.TYPECODE_CHAR THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, V1);
OUTSET.SETCHAR(V1);
WHEN DBMS_TYPES.TYPECODE_VARCHAR2 THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, V1);
OUTSET.SETVARCHAR2(V1);
WHEN DBMS_TYPES.TYPECODE_NUMBER THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, N1);
OUTSET.SETNUMBER(N1);
WHEN DBMS_TYPES.TYPECODE_DATE THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, D1);
OUTSET.SETDATE(D1);
WHEN DBMS_TYPES.TYPECODE_UROWID THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, UR1);
OUTSET.SETUROWID(UR1);
WHEN DBMS_TYPES.TYPECODE_INTERVAL_DS THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, IDS1);
OUTSET.SETINTERVALDS(IDS1);
WHEN DBMS_TYPES.TYPECODE_INTERVAL_YM THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, IYM1);
OUTSET.SETINTERVALYM(IYM1);
WHEN DBMS_TYPES.TYPECODE_TIMESTAMP THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, TS1);
OUTSET.SETTIMESTAMP(TS1);
WHEN DBMS_TYPES.TYPECODE_TIMESTAMP_TZ THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, TSTZ1);
OUTSET.SETTIMESTAMPTZ(TSTZ1);
WHEN DBMS_TYPES.TYPECODE_TIMESTAMP_LTZ THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, TSLTZ1);
OUTSET.SETTIMESTAMPLTZ(TSLTZ1);
END CASE;
END LOOP;
OUTSET.ENDCREATE;
RETURN ODCICONST.SUCCESS;
END;
--
MEMBER FUNCTION ODCITABLECLOSE(SELF IN PIVOTIMPL) RETURN NUMBER IS
C INTEGER;
BEGIN
C := SELF.CUR;
DBMS_SQL.CLOSE_CURSOR(C);
RETURN ODCICONST.SUCCESS;
END;
END;
/

Related

How to write "in" claus in select query when ever in_put param has some values..?

whenever users pass a list of values then we need to pause "in" condition.
the jin_son_doc will be like this "India,American Samoa"
create or replace PROCEDURE test_attendee (
out_chr_err_code OUT VARCHAR2,
out_chr_err_msg OUT VARCHAR2,
out_attendee_tab OUT return_attendee_arr_result,
in_json_doc IN VARCHAR2
) IS
l_chr_srcstage VARCHAR2(200);
l_chr_biqtab VARCHAR2(200);
l_chr_srctab VARCHAR2(200);
l_chr_bistagtab VARCHAR2(200);
l_chr_err_code VARCHAR2(255);
l_chr_err_msg VARCHAR2(255);
l_out_chr_errbuf VARCHAR2(2000);
lrec return_attendee_report;
l_num_counter NUMBER := 0;
json_doc CHAR_ARRAY(1000) := in_json_doc;
CURSOR cur_attendee_data IS
SELECT
*
FROM
(
SELECT
a.*,
ROWNUM rn
FROM
(SELECT * FROM (
SELECT
r.id request_id,
c.designation ext_att_title,
DECODE(c.attendee_type, 'externalattendees', 'External', 'Internal') attendee_type
FROM
bi_request r
LEFT JOIN bi_request_activity_day a ON a.request_id = r.id
LEFT JOIN bi_request_catering_activity b ON b.request_activity_day_id = a.id
LEFT JOIN bi_request_attendees c ON c.request_id = r.id
LEFT JOIN bi_request_act_day_room d ON d.request_activity_day_id = a.id
AND d.room = b.room
WHERE
r.state = 'CONFIRMED'
AND a.event_date BETWEEN l_start_date AND l_end_date
AND r.location_id = (
SELECT UNIQUE
( id )
FROM
bi_location
WHERE
unique_id = l_location_id
)
AND d.room_type = 'MAIN_ROOM'
AND country IN (
SELECT
column_value
FROM
TABLE ( json_doc )
)
)
WHERE
1=1
) a
WHERE
ROWNUM <= l_end_row
)
WHERE
rn >= l_start_row;
TYPE rec_attendee_data IS
TABLE OF cur_attendee_data%rowtype INDEX BY PLS_INTEGER;
l_cur_attendee_data rec_attendee_data;
BEGIN
dbms_output.put_line(l_country_array.count);
out_attendee_tab := return_attendee_arr_result();
OPEN cur_attendee_data;
LOOP
FETCH cur_attendee_data BULK COLLECT INTO l_cur_attendee_data;
EXIT WHEN l_cur_attendee_data.count = 0;
dbms_output.put_line('here in first insert');
lrec := return_attendee_report();
out_attendee_tab := return_attendee_arr_result(return_attendee_report());
out_attendee_tab.DELETE;
FOR i IN 1..l_cur_attendee_data.count LOOP
-- dbms_output.put_line('Inside cursor ' );
BEGIN
l_num_counter := l_num_counter + 1;
lrec := return_attendee_report();
lrec.requestid := l_cur_attendee_data(i).request_id;
lrec.attendeetype := l_cur_attendee_data(i).attendee_type;
lrec.attendeetype := json_doc;
IF l_num_counter > 1 THEN
out_attendee_tab.extend();
out_attendee_tab(l_num_counter) := return_attendee_report();
ELSE
out_attendee_tab := return_attendee_arr_result(return_attendee_report());
END IF;
out_attendee_tab(l_num_counter) := lrec;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Error occurred : ' || sqlerrm);
END;
END LOOP;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('HERE INSIIDE OTHERS' || sqlerrm);
END;
Whenever j"son_doc" is null we need to skip the in clause. Is this possible, let me know if we have any solution.
user will pass jin_son_doc will be like this "India, America".
by using the following function i'm converting string to array,
create or replace FUNCTION fn_varchar_to_array(p_list IN VARCHAR2)
RETURN CHAR_ARRAY
AS
l_string VARCHAR2(32767) := p_list || ',';
l_comma_index PLS_INTEGER;
l_index PLS_INTEGER := 1;
l_tab CHAR_ARRAY := CHAR_ARRAY();
BEGIN
LOOP
l_comma_index := INSTR(l_string, ',', l_index);
EXIT WHEN l_comma_index = 0;
l_tab.EXTEND;
l_tab(l_tab.COUNT) := SUBSTR(l_string, l_index, l_comma_index - l_index);
l_index := l_comma_index + 1;
END LOOP;
RETURN l_tab;
END fn_varchar_to_array;
You can use OR condition as following:
....
AND (json_doc is null
OR country IN (
SELECT
column_value
FROM
TABLE ( json_doc )
)
)
...
Cheers!!

Dynamic Pivot Usage in Oracle Query

Number of rows in table = number of columns
I want to group each row and convert each characteristic value into a column.
I don't want to manually add pivot column values ​​or use XML data. I have to write how I made them. Because it might be useful for understanding.
First query:
SELECT So.Order_No,
So.Release_No,
So.Sequence_No,
So.Part_No,
Csv.Characteristic_Id,
Csv.Characteristic_Id || '-' || Config_Characteristic_Api.Get_Description(Csv.Characteristic_Id) Characteristic_Desc,
Csv.Characteristic_Value,
Csv.Characteristic_Value || ' - ' || Config_Option_Value_Api.Get_Description(Csv.Characteristic_Id, Csv.Characteristic_Value) Characteristic_Value_Desc
FROM Shop_Ord So, Config_Spec_Value Csv
WHERE So.Part_No = Csv.Part_No AND So.Configuration_Id = Csv.Configuration_Id AND So.Configuration_Id != '*' AND So.Need_Date > '01.01.2019' AND
So.Part_No LIKE 'XL%'
ORDER BY So.Order_No, Csv.Characteristic_Value;
Result:
ORDER_NO RELEASE_NO SEQUENCE_NO PART_NO CHARACTERISTIC_ID CHARACTERISTIC_DESC CHARACTERISTIC_VALUE CHARACTERISTIC_VALUE_DESC
--------- ----------- ----------- -------- ------------------ ------------------------------ --------------------- ----------------------------
E1196 1 1 XL106 KK-001 KK-001-Abkant Kontrol Ünitesi KK-001-002 KK-001-002 - Esa S 630 CNC 2D Grafik Ekran - Dokunmatik
E1196 1 1 XL106 KK-005 KK-005-Elektrik Sistemi KK-005-002 KK-005-002 - 380 V-660 V, 50-60 Hz, 3 Ph
E1196 1 1 XL106 KK-006 KK-006-Elektrik Panosu Soğutma Sistemi KK-006-001 KK-006-001 - Fanlı
E1196 1 1 XL106 KK-008 KK-008-Abkant Ön Destek Sayısı KK-008-001 KK-008-001 - Standart
...
PIVOT:
WITH Pivot_ AS
(SELECT So.Order_No,
So.Release_No,
So.Sequence_No,
So.Part_No,
Csv.Characteristic_Id,
Csv.Characteristic_Value
FROM Shop_Ord So, Config_Spec_Value Csv
WHERE So.Part_No = Csv.Part_No AND So.Configuration_Id = Csv.Configuration_Id
AND So.Configuration_Id != '*' AND So.Need_Date > '01.01.2019' AND So.Part_No LIKE 'XL%'
ORDER BY So.Order_No)
SELECT *
FROM Pivot_
Pivot (MAX(Characteristic_Value) FOR(Characteristic_Id) IN('KK-001', 'KK-002'));
Result:
ORDER_NO RELEASE_NO SEQUENCE_NO PART_NO 'KK-001' 'KK-002'
--------- --------- ------------ ------- --------- ---------
E1196 1 1 XL106 KK-001-002 00
E1334 1 1 XL107 KK-001-002 00
E1379 1 1 XL106 KK-001-002 KK-002-001
E1470 2 1 XL107 KK-001-002 KK-002-001
...
PIVOT XML:
WITH Pivot_ AS
(SELECT So.Order_No, So.Release_No, So.Sequence_No, So.Part_No, Csv.Characteristic_Id, Csv.Characteristic_Value
FROM Shop_Ord So, Config_Spec_Value Csv
WHERE So.Part_No = Csv.Part_No AND So.Configuration_Id = Csv.Configuration_Id AND So.Configuration_Id != '*' AND So.Need_Date > '01.01.2019' AND
So.Part_No LIKE 'XL%'
ORDER BY So.Order_No)
SELECT *
FROM Pivot_
Pivot Xml (MAX(Characteristic_Value) FOR(Characteristic_Id) IN (SELECT Cs_.Characteristic_Id
FROM Config_Spec_Value Cs_
WHERE Cs_.Part_No = '1065821'
GROUP BY Cs_.Characteristic_Id));
Result:
ORDER_NO RELEASE_NO SEQUENCE_NO PART_NO CHARACTERISTIC_ID_XML
---------- ---------- ----------- --------- ------------
*1642 1 1 XL106 <XMLTYPE>
*1643 1 1 XL106 <XMLTYPE>
*1644 1 1 XL106 <XMLTYPE>
...
I want to see the columns directly after all on XML Pivot.
ORDER_NO RELEASE_NO SEQUENCE_NO PART_NO KK-001 KK-002 KK-003 ....
---------- ---------- ----------- --------- --------- --------- --------- ---------
*1642 1 1 XL106 KK-001-01 NULL NULL ...
*1643 1 1 XL106 KK-001-04 KK-002-00 KK-003-08 ...
*1644 1 1 XL106 KK-001-02 KK-002-10 NULL ...
...
Best regards.
I found a solution to this problem like this. And i want to share.
Since it has been a long time since my question, I can explain it through a different example.
CREATE OR REPLACE TYPE pivotimpl AS OBJECT
(
ret_type anytype, -- The return type of the table function
stmt VARCHAR2(32767),
fmt VARCHAR2(32767),
cur INTEGER,
STATIC FUNCTION odcitabledescribe
(
rtype OUT anytype,
p_stmt IN VARCHAR2,
p_fmt IN VARCHAR2 := 'upper(#p#)',
dummy IN NUMBER := 0
) RETURN NUMBER,
STATIC FUNCTION odcitableprepare
(
sctx OUT pivotimpl,
ti IN sys.odcitabfuncinfo,
p_stmt IN VARCHAR2,
p_fmt IN VARCHAR2 := 'upper(#p#)',
dummy IN NUMBER := 0
) RETURN NUMBER,
STATIC FUNCTION odcitablestart
(
sctx IN OUT pivotimpl,
p_stmt IN VARCHAR2,
p_fmt IN VARCHAR2 := 'upper(#p#)',
dummy IN NUMBER := 0
) RETURN NUMBER,
MEMBER FUNCTION odcitablefetch
(
SELF IN OUT pivotimpl,
nrows IN NUMBER,
outset OUT anydataset
) RETURN NUMBER,
MEMBER FUNCTION odcitableclose(SELF IN pivotimpl) RETURN NUMBER
);
CREATE OR REPLACE TYPE BODY pivotimpl AS
STATIC FUNCTION odcitabledescribe
(
rtype OUT anytype,
p_stmt IN VARCHAR2,
p_fmt IN VARCHAR2 := 'upper(#p#)',
dummy IN NUMBER
) RETURN NUMBER IS
atyp anytype;
cur INTEGER;
numcols NUMBER;
desc_tab dbms_sql.desc_tab2;
rc SYS_REFCURSOR;
t_c2 VARCHAR2(32767);
t_fmt VARCHAR2(1000);
BEGIN
cur := dbms_sql.open_cursor;
dbms_sql.parse(cur, p_stmt, dbms_sql.native);
dbms_sql.describe_columns2(cur, numcols, desc_tab);
dbms_sql.close_cursor(cur);
--
anytype.begincreate(dbms_types.typecode_object, atyp);
FOR i IN 1 .. numcols - 2
LOOP
atyp.addattr(desc_tab(i).col_name,
CASE desc_tab(i).col_type
WHEN 1 THEN
dbms_types.typecode_varchar2
WHEN 2 THEN
dbms_types.typecode_number
WHEN 9 THEN
dbms_types.typecode_varchar2
WHEN 11 THEN
dbms_types.typecode_varchar2 -- show rowid as varchar2
WHEN 12 THEN
dbms_types.typecode_date
WHEN 208 THEN
dbms_types.typecode_varchar2 -- show urowid as varchar2
WHEN 96 THEN
dbms_types.typecode_char
WHEN 180 THEN
dbms_types.typecode_timestamp
WHEN 181 THEN
dbms_types.typecode_timestamp_tz
WHEN 231 THEN
dbms_types.typecode_timestamp_ltz
WHEN 182 THEN
dbms_types.typecode_interval_ym
WHEN 183 THEN
dbms_types.typecode_interval_ds
END, desc_tab(i).col_precision, desc_tab(i).col_scale,
CASE desc_tab(i).col_type
WHEN 11 THEN
18 -- for rowid col_max_len = 16, and 18 characters are shown
ELSE
desc_tab(i).col_max_len
END, desc_tab(i).col_charsetid, desc_tab(i).col_charsetform);
END LOOP;
IF instr(p_fmt, '#p#') > 0 THEN
t_fmt := p_fmt;
ELSE
t_fmt := '#p#';
END IF;
OPEN rc FOR REPLACE('select distinct ' || t_fmt || '
from( ' || p_stmt || ' )
order by ' || t_fmt, '#p#', desc_tab(numcols - 1).col_name);
LOOP
FETCH rc
INTO t_c2;
EXIT WHEN rc%NOTFOUND;
atyp.addattr(t_c2,
CASE desc_tab(numcols).col_type WHEN 1 THEN dbms_types.typecode_varchar2 WHEN 2 THEN dbms_types.typecode_number WHEN 9 THEN
dbms_types.typecode_varchar2 WHEN 11 THEN dbms_types.typecode_varchar2 -- show rowid as varchar2
WHEN 12 THEN dbms_types.typecode_date WHEN 208 THEN dbms_types.typecode_urowid WHEN 96 THEN dbms_types.typecode_char WHEN 180 THEN
dbms_types.typecode_timestamp WHEN 181 THEN dbms_types.typecode_timestamp_tz WHEN 231 THEN dbms_types.typecode_timestamp_ltz WHEN 182 THEN
dbms_types.typecode_interval_ym WHEN 183 THEN dbms_types.typecode_interval_ds END, desc_tab(numcols).col_precision,
desc_tab(numcols).col_scale,
CASE desc_tab(numcols).col_type WHEN 11 THEN 18 -- for rowid col_max_len = 16, and 18 characters are shown
ELSE desc_tab(numcols).col_max_len END, desc_tab(numcols).col_charsetid, desc_tab(numcols).col_charsetform);
END LOOP;
CLOSE rc;
atyp.endcreate;
anytype.begincreate(dbms_types.typecode_table, rtype);
rtype.setinfo(NULL, NULL, NULL, NULL, NULL, atyp, dbms_types.typecode_object, 0);
rtype.endcreate();
RETURN odciconst.success;
EXCEPTION
WHEN OTHERS THEN
RETURN odciconst.error;
END;
--
STATIC FUNCTION odcitableprepare
(
sctx OUT pivotimpl,
ti IN sys.odcitabfuncinfo,
p_stmt IN VARCHAR2,
p_fmt IN VARCHAR2 := 'upper(#p#)',
dummy IN NUMBER
) RETURN NUMBER IS
prec PLS_INTEGER;
scale PLS_INTEGER;
len PLS_INTEGER;
csid PLS_INTEGER;
csfrm PLS_INTEGER;
elem_typ anytype;
aname VARCHAR2(30);
tc PLS_INTEGER;
BEGIN
tc := ti.rettype.getattreleminfo(1, prec, scale, len, csid, csfrm, elem_typ, aname);
--
IF instr(p_fmt, '#p#') > 0 THEN
sctx := pivotimpl(elem_typ, p_stmt, p_fmt, NULL);
ELSE
sctx := pivotimpl(elem_typ, p_stmt, '#p#', NULL);
END IF;
RETURN odciconst.success;
END;
--
STATIC FUNCTION odcitablestart
(
sctx IN OUT pivotimpl,
p_stmt IN VARCHAR2,
p_fmt IN VARCHAR2 := 'upper(#p#)',
dummy IN NUMBER
) RETURN NUMBER IS
cur INTEGER;
numcols NUMBER;
desc_tab dbms_sql.desc_tab2;
t_stmt VARCHAR2(32767);
type_code PLS_INTEGER;
prec PLS_INTEGER;
scale PLS_INTEGER;
len PLS_INTEGER;
csid PLS_INTEGER;
csfrm PLS_INTEGER;
schema_name VARCHAR2(30);
type_name VARCHAR2(30);
version VARCHAR2(30);
attr_count PLS_INTEGER;
attr_type anytype;
attr_name VARCHAR2(100);
dummy2 INTEGER;
BEGIN
cur := dbms_sql.open_cursor;
dbms_sql.parse(cur, p_stmt, dbms_sql.native);
dbms_sql.describe_columns2(cur, numcols, desc_tab);
dbms_sql.close_cursor(cur);
--
FOR i IN 1 .. numcols - 2
LOOP
t_stmt := t_stmt || ', "' || desc_tab(i).col_name || '"';
END LOOP;
--
type_code := sctx.ret_type.getinfo(prec, scale, len, csid, csfrm, schema_name, type_name, version, attr_count);
FOR i IN numcols - 1 .. attr_count
LOOP
type_code := sctx.ret_type.getattreleminfo(i, prec, scale, len, csid, csfrm, attr_type, attr_name);
t_stmt := t_stmt || REPLACE(', max( decode( ' || sctx.fmt || ', ''' || attr_name || ''', ' || desc_tab(numcols).col_name || ' ) )', '#p#',
desc_tab(numcols - 1).col_name);
END LOOP;
t_stmt := 'select ' || substr(t_stmt, 2) || ' from ( ' || sctx.stmt || ' )';
FOR i IN 1 .. numcols - 2
LOOP
IF i = 1 THEN
t_stmt := t_stmt || ' group by "' || desc_tab(i).col_name || '"';
ELSE
t_stmt := t_stmt || ', "' || desc_tab(i).col_name || '"';
END IF;
END LOOP;
--
dbms_output.put_line(t_stmt);
sctx.cur := dbms_sql.open_cursor;
dbms_sql.parse(sctx.cur, t_stmt, dbms_sql.native);
FOR i IN 1 .. attr_count
LOOP
type_code := sctx.ret_type.getattreleminfo(i, prec, scale, len, csid, csfrm, attr_type, attr_name);
CASE type_code
WHEN dbms_types.typecode_char THEN
dbms_sql.define_column(sctx.cur, i, 'x', 32767);
WHEN dbms_types.typecode_varchar2 THEN
dbms_sql.define_column(sctx.cur, i, 'x', 32767);
WHEN dbms_types.typecode_number THEN
dbms_sql.define_column(sctx.cur, i, CAST(NULL AS NUMBER));
WHEN dbms_types.typecode_date THEN
dbms_sql.define_column(sctx.cur, i, CAST(NULL AS DATE));
WHEN dbms_types.typecode_urowid THEN
dbms_sql.define_column(sctx.cur, i, CAST(NULL AS UROWID));
WHEN dbms_types.typecode_timestamp THEN
dbms_sql.define_column(sctx.cur, i, CAST(NULL AS TIMESTAMP));
WHEN dbms_types.typecode_timestamp_tz THEN
dbms_sql.define_column(sctx.cur, i, CAST(NULL AS TIMESTAMP WITH TIME ZONE));
WHEN dbms_types.typecode_timestamp_ltz THEN
dbms_sql.define_column(sctx.cur, i, CAST(NULL AS TIMESTAMP WITH LOCAL TIME ZONE));
WHEN dbms_types.typecode_interval_ym THEN
dbms_sql.define_column(sctx.cur, i, CAST(NULL AS INTERVAL YEAR TO MONTH));
WHEN dbms_types.typecode_interval_ds THEN
dbms_sql.define_column(sctx.cur, i, CAST(NULL AS INTERVAL DAY TO SECOND));
END CASE;
END LOOP;
dummy2 := dbms_sql.execute(sctx.cur);
RETURN odciconst.success;
END;
--
MEMBER FUNCTION odcitablefetch
(
SELF IN OUT pivotimpl,
nrows IN NUMBER,
outset OUT anydataset
) RETURN NUMBER IS
c1_col_type PLS_INTEGER;
type_code PLS_INTEGER;
prec PLS_INTEGER;
scale PLS_INTEGER;
len PLS_INTEGER;
csid PLS_INTEGER;
csfrm PLS_INTEGER;
schema_name VARCHAR2(30);
type_name VARCHAR2(30);
version VARCHAR2(30);
attr_count PLS_INTEGER;
attr_type anytype;
attr_name VARCHAR2(100);
v1 VARCHAR2(32767);
n1 NUMBER;
d1 DATE;
ur1 UROWID;
ids1 INTERVAL DAY TO SECOND;
iym1 INTERVAL YEAR TO MONTH;
ts1 TIMESTAMP;
tstz1 TIMESTAMP WITH TIME ZONE;
tsltz1 TIMESTAMP WITH LOCAL TIME ZONE;
BEGIN
outset := NULL;
IF nrows < 1 THEN
-- is this possible???
RETURN odciconst.success;
END IF;
--
dbms_output.put_line('fetch');
IF dbms_sql.fetch_rows(self.cur) = 0 THEN
RETURN odciconst.success;
END IF;
--
dbms_output.put_line('done');
type_code := self.ret_type.getinfo(prec, scale, len, csid, csfrm, schema_name, type_name, version, attr_count);
anydataset.begincreate(dbms_types.typecode_object, self.ret_type, outset);
outset.addinstance;
outset.piecewise();
FOR i IN 1 .. attr_count
LOOP
type_code := self.ret_type.getattreleminfo(i, prec, scale, len, csid, csfrm, attr_type, attr_name);
dbms_output.put_line(attr_name);
CASE type_code
WHEN dbms_types.typecode_char THEN
dbms_sql.column_value(self.cur, i, v1);
outset.setchar(v1);
WHEN dbms_types.typecode_varchar2 THEN
dbms_sql.column_value(self.cur, i, v1);
outset.setvarchar2(v1);
WHEN dbms_types.typecode_number THEN
dbms_sql.column_value(self.cur, i, n1);
outset.setnumber(n1);
WHEN dbms_types.typecode_date THEN
dbms_sql.column_value(self.cur, i, d1);
outset.setdate(d1);
WHEN dbms_types.typecode_urowid THEN
dbms_sql.column_value(self.cur, i, ur1);
outset.seturowid(ur1);
WHEN dbms_types.typecode_interval_ds THEN
dbms_sql.column_value(self.cur, i, ids1);
outset.setintervalds(ids1);
WHEN dbms_types.typecode_interval_ym THEN
dbms_sql.column_value(self.cur, i, iym1);
outset.setintervalym(iym1);
WHEN dbms_types.typecode_timestamp THEN
dbms_sql.column_value(self.cur, i, ts1);
outset.settimestamp(ts1);
WHEN dbms_types.typecode_timestamp_tz THEN
dbms_sql.column_value(self.cur, i, tstz1);
outset.settimestamptz(tstz1);
WHEN dbms_types.typecode_timestamp_ltz THEN
dbms_sql.column_value(self.cur, i, tsltz1);
outset.settimestampltz(tsltz1);
END CASE;
END LOOP;
outset.endcreate;
RETURN odciconst.success;
END;
--
MEMBER FUNCTION odcitableclose(SELF IN pivotimpl) RETURN NUMBER IS
c INTEGER;
BEGIN
c := self.cur;
dbms_sql.close_cursor(c);
RETURN odciconst.success;
END;
END;
CREATE OR REPLACE FUNCTION pivot
(
p_stmt IN VARCHAR2,
p_fmt IN VARCHAR2 := 'upper(#p#)',
dummy IN NUMBER := 0
) RETURN anydataset
PIPELINED USING pivotimpl;
--grant execute on pivot to '&USER';
SELECT results.*
FROM (TABLE(pivot('SELECT sc.st_id,
sc.full_name,
sc.lesson_name,
MAX(sc.score) price
FROM (SELECT ss.st_id,
student_api.get_full_name(ss.st_id),
replace(trim(substr(upper(lesson_api.get_name(ss.lesson_name)), 0, 15)), '' '', ''_'') lesson_name,
ss.score
FROM student_score ss
WHERE ss.st_id like ''&st_id_'' AND ss.score IS NOT NULL) sc
GROUP BY sc.st_id,
sc.full_name,
sc.lesson_name
ORDER BY sc.st_id'))) results;
Resutls:

How to split data from CSV file with UTF_FILE Oracle

I'm new at using UTF_FILE in Oracle. I have a CSV-file with over 300K records and 6 columns, the columns are separated by comma ",".
I'm looking to split all this data and set that to some variables and insert in some tables or columns by Pl/SQL but how can I do that?
For now the time of execution of the pl/sql is not important
[Oracle 11gR2 XE]
Solution to you question:
DECLARE
v_row VARCHAR2(200) := 'a,b,c';
BEGIN
FOR v_col IN (SELECT REGEXP_SUBSTR (v_row, '[^,]+', 1, LEVEL) cell FROM DUAL CONNECT BY REGEXP_SUBSTR (v_row, '[^,]+', 1, LEVEL) IS NOT NULL)
LOOP
DBMS_OUTPUT.PUT_LINE (v_col.cell);
END LOOP;
END;
But like the comments say: You shouldn't do this. Use SQL Loader: Oracle: Import CSV file
Hi I've used this code years ago and it works
you can change it to use regexp instead of complicated substrs
you can use index-by tables instead of nested table type I've used, the nested can be inserted in a table but index-by is only usable on pl/sql and cannot be passed as parameter to other stored programs(which nested can).
CREATE OR REPLACE TYPE ARRAY_OF_TEXTS AS TABLE OF VARCHAR2 (4000);
CREATE OR REPLACE TYPE ARRAY_OF_ARRAYS AS TABLE OF ARRAY_OF_TEXTS;
CREATE OR REPLACE FUNCTION SPLIT (
TEXT IN CLOB,
C_SEPARATOR IN VARCHAR2,
IGNORE_EMBTY_BLOCKS IN BOOLEAN DEFAULT FALSE)
RETURN ARRAY_OF_TEXTS
IS
S_LINE VARCHAR2 (4000);
S_TABLE ARRAY_OF_TEXTS;
I INTEGER;
OFFSET1 INTEGER := 1;
OFFSET2 INTEGER;
TEXT_LEN INTEGER;
BEGIN
S_TABLE := ARRAY_OF_TEXTS ();
OFFSET2 := INSTR (TEXT, C_SEPARATOR, OFFSET1);
TEXT_LEN := DBMS_LOB.GETLENGTH (TEXT);
IF OFFSET2 < 1 --if there is no c_separator (if offset2 is 0) or there is not any c_separator at the end of text
THEN
OFFSET2 := TEXT_LEN;
END IF;
WHILE (OFFSET2 = OFFSET1 + LENGTH (C_SEPARATOR) OR OFFSET2 = OFFSET1)
AND DBMS_LOB.SUBSTR (TEXT, LENGTH (C_SEPARATOR), OFFSET1) =
C_SEPARATOR -- if there are 2 c_separator sequentially
LOOP
IF NOT IGNORE_EMBTY_BLOCKS
THEN
S_TABLE.EXTEND;
S_TABLE (S_TABLE.LAST) := NULL;
END IF;
OFFSET1 := OFFSET2 + LENGTH (C_SEPARATOR);
OFFSET2 := DBMS_LOB.INSTR (TEXT, C_SEPARATOR, OFFSET1);
END LOOP;
IF OFFSET2 > OFFSET1 + LENGTH (C_SEPARATOR)
THEN
S_TABLE.EXTEND;
S_LINE := DBMS_LOB.SUBSTR (TEXT, OFFSET2 - OFFSET1, OFFSET1);
S_TABLE (S_TABLE.LAST) := S_LINE;
OFFSET1 := OFFSET2 + LENGTH (C_SEPARATOR);
END IF;
OFFSET2 := DBMS_LOB.INSTR (TEXT, C_SEPARATOR, OFFSET1);
WHILE OFFSET2 > 1
LOOP
S_TABLE.EXTEND;
S_LINE := DBMS_LOB.SUBSTR (TEXT, OFFSET2 - OFFSET1, OFFSET1);
S_TABLE (S_TABLE.LAST) := S_LINE;
OFFSET1 := OFFSET2 + LENGTH (C_SEPARATOR);
OFFSET2 := DBMS_LOB.INSTR (TEXT, C_SEPARATOR, OFFSET1);
WHILE ( OFFSET2 = OFFSET1 + LENGTH (C_SEPARATOR)
OR OFFSET2 = OFFSET1)
AND DBMS_LOB.SUBSTR (TEXT, LENGTH (C_SEPARATOR), OFFSET1) =
C_SEPARATOR -- if there are 2 c_separator sequentially
LOOP
IF NOT IGNORE_EMBTY_BLOCKS
THEN
S_TABLE.EXTEND;
S_TABLE (S_TABLE.LAST) := NULL;
END IF;
OFFSET1 := OFFSET2 + LENGTH (C_SEPARATOR);
OFFSET2 := DBMS_LOB.INSTR (TEXT, C_SEPARATOR, OFFSET1);
END LOOP;
END LOOP;
IF OFFSET1 < TEXT_LEN
THEN
S_TABLE.EXTEND;
S_LINE :=
DBMS_LOB.SUBSTR (
TEXT,
TEXT_LEN - OFFSET1 + LENGTH (C_SEPARATOR),
OFFSET1
);
S_TABLE (S_TABLE.LAST) := S_LINE;
ELSIF OFFSET1 = TEXT_LEN
AND DBMS_LOB.SUBSTR (TEXT, LENGTH (C_SEPARATOR), OFFSET1) <>
C_SEPARATOR
THEN
S_TABLE.EXTEND;
S_LINE.TEXT := DBMS_LOB.SUBSTR (TEXT, LENGTH (C_SEPARATOR), OFFSET1);
S_TABLE (S_TABLE.LAST) := S_LINE;
END IF;
RETURN S_TABLE;
END;
CREATE OR REPLACE FUNCTION LOAD_CSV_FILE (
P_DIRECTORY IN VARCHAR2,
P_FILENAME IN VARCHAR2
)
RETURN ARRAY_OF_ARRAYS
AS
SEPARATOR1 VARCHAR2 (2) := CHR (10);
-- In Some Cases you should use: CHR (13) || CHR (10);
SEPARATOR2 VARCHAR2 (1) := ',';
--if csv separator is ; or | use it here
V_TEXT CLOB;
V_BFILE BFILE;
V_LINES ARRAY_OF_TEXTS;
V_LINE ARRAY_OF_TEXTS;
V_ARRAY ARRAY_OF_ARRAYS;
BEGIN
SELECT EMPTY_CLOB () INTO V_TEXT FROM DUAL;
--V_TEXT := EMPTY_CLOB ();
DBMS_LOB.CREATETEMPORARY(V_TEXT, TRUE);
V_BFILE := BFILENAME (P_DIRECTORY, P_FILENAME);
IF DBMS_LOB.FILEEXISTS (V_BFILE) <> 1
THEN
RETURN NULL;
END IF;
DBMS_LOB.FILEOPEN (V_BFILE, DBMS_LOB.FILE_READONLY);
DBMS_LOB.LOADFROMFILE (V_TEXT, V_BFILE, DBMS_LOB.GETLENGTH (V_BFILE));
DBMS_LOB.FILECLOSE (V_BFILE);
V_LINES := SPLIT2 (V_TEXT, SEPARATOR1);
V_ARRAY := ARRAY_OF_ARRAYS ();
FOR R_LINE IN (SELECT *
FROM TABLE (V_LINES))
LOOP
V_LINE := SPLIT(R_LINE.COLUMN_VALUE, SEPARATOR2);
V_ARRAY.EXTEND ();
V_ARRAY (V_ARRAY.LAST) := V_LINE;
END LOOP;
RETURN V_ARRAY;
END;
now you can use it like this:
DECLARE
V_ARR ARRAY_OF_ARRAYS;
V_LINE VARCHAR2 (4000);
BEGIN
V_ARR := LOAD_CSV_FILE ('MY_DIR', 'file.csv');
FOR LINE IN (SELECT *
FROM TABLE (V_ARR))
LOOP
FOR FIELD IN (SELECT *
FROM TABLE (LINE.COLUMN_VALUE))
LOOP
DBMS_OUTPUT.PUT_LINE ('field:' || FIELD.COLUMN_VALUE);
END LOOP;
DBMS_OUTPUT.PUT_LINE ('end of line');
END LOOP;
END;

is it possible to have alphanumeric sequence generator in sql

I need to write a SQL query to print the following aphanumberic sequence in SQL
0001,
0002,
... ,
0009,
000A,
... ,
000Z,
... ,
0010,
0011,
... ,
001A,
... and so on till... ,
ZZZZ
please note: all characters are UPPERCASE.
Thanks in advance
You could create a function like this:
create function to_base_36 (n integer) return varchar2
is
q integer;
r varchar2(100);
begin
q := n;
while q >= 36 loop
r := chr(mod(q,36)+case when mod(q,36) < 10 then 48 else 55 end) || r;
q := floor(q/36);
end loop;
r := chr(mod(q,36)+case when mod(q,36) < 10 then 48 else 55 end) || r;
return lpad(r,4,'0');
end;
and then use it like this:
select rownum, to_base_36(rownum)
from dual
connect by level < 36*36*36*36;
Or, without creating a function:
with digits as
( select n, chr(mod(n,36)+case when mod(n,36) < 10 then 48 else 55 end) d
from (Select rownum-1 as n from dual connect by level < 37)
)
select d1.n*36*36*36 + d2.n*36*36 + d3.n*36 + d4.n, d1.d||d2.d||d3.d||d4.d
from digits d1, digits d2, digits d3, digits d4
You could use this function:
create or replace FUNCTION SEQGEN(vinp in varchar2, iSeq in INTEGER)
RETURN VARCHAR2 is vResult VARCHAR2(32);
iBas INTEGER; iRem INTEGER; iQuo INTEGER; lLen CONSTANT INTEGER := 2;
BEGIN
iBas := length(vInp);
iQuo := iSeq;
WHILE iQuo > 0 LOOP
iRem := iQuo mod iBas;
--dbms_output.put_line('Now we divide ' || lpad(iQuo,lLen,'0') || ' by ' || lpad(iBas,lLen,'0') || ', yielding a quotient of ' || lpad( TRUNC(iQuo / iBas) ,lLen,'0') || ' and a remainder of ' || lpad(iRem,lLen,'0') || ' giving the char: ' || substr(vInp, iRem, 1));
iQuo := TRUNC(iQuo / iBas);
If iRem < 1 Then iRem := iBas; iQuo := iQuo - 1; End If;
vResult := substr(vInp, iRem, 1) || vResult;
END LOOP;
RETURN vResult;
END SEQGEN;
Try the function:
SELECT * FROM (
SELECT seqgen('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',rownum + 47989 --start value
) Output, level evt FROM dual CONNECT BY level < 1679618) --stop value
WHERE mod(evt,50000) = 0 OR output in ('0001','0002','0009','000A','000Z',
'0010','0011','001A','ZZZZ')
Note that if you change the string you must also change the start and stop value.
Read more about number systems here: Number System Conversion - Explanation
-- To get 00000 to ZZZZZ next auto alphanumeric sequence using this function [Please verify before use]
-- This starts from 0-9 then A-Z and then increase next digit from 0-9 then A-Z
-- You need to pass the starting/Last sequence as value to get next sequence
CREATE OR REPLACE FUNCTION return_next_seq (curr_sequence VARCHAR2)
RETURN VARCHAR2 IS
retval VARCHAR2(4000) := NULL;
retMaxval VARCHAR2(4000) := NULL;
eval_digit CHAR(1) := NULL;
original_sequence VARCHAR2(4000) := curr_sequence;
curr1_sequence VARCHAR2(4000) := curr_sequence;
BEGIN
retval := original_sequence;
FOR j IN REVERSE 1..LENGTH(curr1_sequence) LOOP -- Using reverse to know
-- the exact digit position
eval_digit := SUBSTR(curr1_sequence, LENGTH(curr1_sequence));
--IF (ASCII(eval_digit) BETWEEN 49 AND 56) OR
--(ASCII(eval_digit) BETWEEN 97 AND 121) THEN
IF (ASCII(eval_digit) BETWEEN 48 AND 56) OR
(ASCII(eval_digit) BETWEEN 65 AND 89) THEN
eval_digit := CHR(ASCII(eval_digit) +1);
curr1_sequence := SUBSTR(curr1_sequence,1,LENGTH(curr1_sequence)-1);
retval := curr1_sequence || eval_digit || SUBSTR(original_sequence,
LENGTH(curr1_sequence || eval_digit)+1);
EXIT;
ELSE -- move to the next digit leaving the evaluated digit untouched.
IF (ASCII(eval_digit) = 57) THEN
eval_digit := CHR(ASCII(eval_digit) +8);
curr1_sequence := SUBSTR(curr1_sequence,1,LENGTH(curr1_sequence)-1);
retval := curr1_sequence || eval_digit || SUBSTR(original_sequence,
LENGTH(curr1_sequence || eval_digit)+1);
EXIT;
END IF;
IF (ASCII(eval_digit) = 90) THEN
retMaxval := eval_digit;
eval_digit := CHR(ASCII(eval_digit) -42);
curr1_sequence := SUBSTR(curr1_sequence,1,LENGTH(curr1_sequence)-1);
FOR k IN REVERSE 1..LENGTH(curr1_sequence) LOOP
IF (ASCII(SUBSTR(curr1_sequence,LENGTH(curr1_sequence))) BETWEEN 48 AND 56) OR (ASCII(SUBSTR(curr1_sequence,LENGTH(curr1_sequence))) BETWEEN 65 AND 89) THEN
retval := SUBSTR(curr1_sequence,0,LENGTH(curr1_sequence)-1) || CHR(ASCII(SUBSTR(curr1_sequence,LENGTH(curr1_sequence)))+1) || eval_digit || SUBSTR(retval,
LENGTH(curr1_sequence || eval_digit)+1);
ELSE
IF ASCII(SUBSTR(curr1_sequence,LENGTH(curr1_sequence))) = 57 THEN
retval := SUBSTR(curr1_sequence,0,LENGTH(curr1_sequence)-1) || CHR(65) || eval_digit || SUBSTR(retval,
LENGTH(curr1_sequence || eval_digit)+1);
ELSE
IF ASCII(SUBSTR(curr1_sequence,LENGTH(curr1_sequence))) = 90 AND LENGTH(curr1_sequence)>1 THEN
retval := SUBSTR(curr1_sequence,0,LENGTH(curr1_sequence)-1) || CHR(48) || eval_digit || SUBSTR(retval,
LENGTH(curr1_sequence || eval_digit)+1);
curr1_sequence := SUBSTR(curr1_sequence,1,LENGTH(curr1_sequence)-1);
retMaxval := retMaxval||'Z';
ELSE
retMaxval := retMaxval||'Z';
EXIT;
END IF;
END IF;
END IF;
END LOOP;
EXIT;
ELSE
curr1_sequence := SUBSTR(curr1_sequence,1,LENGTH(curr1_sequence)-1);
END IF;
END IF;
END LOOP;
IF retval IS NULL OR (LENGTH(retval) = LENGTH(retMaxval)) THEN
RETURN 'MAX';
END IF;
RETURN retval;
END;
-- To verify, call this function like
SELECT return_next_seq('ZY9Z') FROM dual;
-- Any improvement suggestion is welcome!
--- Thanks!..Sanjiv

How to encode string in Oracle?

I have problem with encoding data in Oracle database.
I want to xor string with another string (mask) and then
encode it with base64.
In Python this looks like:
def encode_str(s, mask):
xor_mask = mask
while len(xor_mask) < len(s):
xor_mask += mask
chrs2 = []
for i in range(len(s)):
chrs2.append(chr(ord(s[i]) ^ ord(xor_mask[i])))
s2 = ''.join(chrs2)
return base64.b64encode(s2)
#return binascii.hexlify(s2).lower()
In PL/SQL I got:
create or replace function ht_encode(str in varchar2, mask in varchar2) return varchar2 as
xor_mask varchar2(2000);
result_s varchar2(2000);
i integer;
xx integer;
x char(10);
ch1 char(10);
ch2 char(10);
chrx varchar2(10);
begin
result_s := '';
xor_mask := mask;
while length(xor_mask) < length(str) loop
xor_mask := xor_mask || mask;
end loop;
for i in 1..length(str) loop
ch1 := substr(str, i, 1);
ch2 := substr(xor_mask, i, 1);
xx := BITXOR(ascii(ch1), ascii(ch2));
x := xx;
chrx := rawtohex(x);
--result_s := result_s || ':' || chrx;
--result_s := result_s || chrx;
-- HELP ME HERE!
end loop;
--return lower(utl_encode.base64_encode(result_s));
--return result_s || ' | ' || rawtohex(result_s);
-- HELP ME HERE!
return result_s;
end;
(bitxor comes from http://forums.oracle.com/forums/thread.jspa?threadID=496773 )
I don't know how to create "binary" string and then encode it to hex or preferable
to base64.
SELECT UTL_RAW.cast_to_varchar2(UTL_ENCODE.base64_encode(UTL_RAW.bit_xor(UTL_RAW.cast_to_raw('text'), UTL_RAW.cast_to_raw('mask'))))
FROM dual