Dynamic Pivot Usage in Oracle Query - sql

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:

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!!

How to convert clob data into multiple columns in Oracle?

In a Oracle table, I have a clob column (TEXT) which has data like below.
"Employee ID: 1
Hire Date: 24-Oct-2013
Name: XXXXX
Department: IT
Employee ID : 2
Name : YYYYY
Hire Date : 20-May-2014
Department: ITIS
Hire Date: 17-May-2017
Department:SMO
Name: ZZZZZ
Employee ID: 3"
The above CLOB data needs to be converted into multiple columns like below
Employee_ID Hire_Date Name Department
----------------------------------------------------
1 24-Oct-2013 XXXXX IT
2 20-May-2014 YYYYY ITIS
3 17-May-2017 ZZZZZ SMO
Please help me on this.
Code below is getting data from your string and insert column to temporary table, if you don't need temperory table you can use logic of getting data from string as you want
First create temperory table Employeeinfo like this
create global temporary table EmployeeInfo
(
EmployeeID varchar2(15),
HireDate varchar2(15),
Name varchar2(100),
Department varchar2(10)
)
on commit preserve rows;
Second use this code(this is pl/sql test script)
declare
lv_string varchar2(4000) := 'Employee ID: 1
Hire Date: 24-Oct-2013
Name: XXXXX
Department: IT
Employee ID : 2
Name : YYYYY
Hire Date : 20-May-2014
Department: ITIS
Hire Date: 17-May-2017
Department:SMO
Name: ZZZZZ
Employee ID: 3';
lv_Token varchar2(4000);
lv_Part varchar2(4000);
lv_FirstPart varchar2(4000);
lv_SecondPart varchar2(4000);
li pls_integer := 0;
lv_EmployeeID varchar2(15);
lv_HireDate varchar2(15);
lv_Name varchar2(100);
lv_Department varchar2(10);
function v_Partition(av_source long, av_separator varchar2,
ai_nth pls_integer) return varchar2 is
li_Sep pls_integer := length(av_Separator);
li_Begin pls_integer := 1 - li_Sep;
li_End pls_integer;
lv_Output long;
begin
li_End := instr(av_source, av_separator, 1, ai_nth);
if ai_Nth > 1 then
li_Begin := instr(av_source, av_separator, 1, ai_nth - 1);
if li_Begin = 0 then
return null;
end if;
end if;
if li_End > 0 then
lv_Output := substr(av_Source, li_Begin + li_Sep,
li_End - li_Begin - li_Sep);
elsif length(av_Source) >= li_Begin + li_Sep then
lv_Output := substr(av_Source, li_Begin + li_Sep,
length(av_Source) - li_Begin);
end if;
return lv_Output;
end;
function v_Token(av_source in out nocopy varchar2, av_separator varchar2)
return varchar2 is
lv_token varchar2(4000);
li_pos pls_integer;
begin
li_pos := instr(av_source, av_separator, 1, 1);
if li_pos > 0 then
lv_token := rtrim(substr(av_source, 1, li_pos - 1));
av_source := substr(av_source, li_pos + length(av_separator));
else
lv_token := rtrim(av_source);
av_source := '';
end if;
if av_Separator = ' ' then
av_Source := trim(av_Source);
end if;
return lv_token;
end;
begin
while lv_string is not null loop
lv_Token := v_Token(lv_string, chr(10));
if lv_Token is not null then
li := li + 1;
lv_FirstPart := trim(v_Partition(lv_Token, ':', 1));
put(lv_FirstPart);
lv_SecondPart := trim(v_Partition(lv_Token, ':', 2));
if lv_FirstPart like '%Employee ID%' then
lv_EmployeeID := lv_SecondPart;
elsif lv_FirstPart like '%Hire Date%' then
lv_HireDate := lv_SecondPart;
elsif lv_FirstPart like '%Name%' then
lv_Name := lv_SecondPart;
elsif lv_FirstPart like '%Department%' then
lv_Department := lv_SecondPart;
end if;
if li = 4 then
insert into EmployeeInfo
values
(lv_EmployeeID, lv_HireDate, lv_Name, lv_Department);
li := 0;
end if;
end if;
end loop;
--select * from EmployeeInfo; -- you can select from table
end;

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

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;
/

Need to Write CLOB file data into ORACLE table with PLSQL

I have flat file inside a clob field and structure of the flat-file something like as below. and flat files containx million of records.
col1,col2,col3,col4,col5,col6
A,B,C,,F,D
1,A,2,B,B,C
Traditional ways I can't use like
1-fetch the data from clob in excel or something and the load the data into table with sql-loader.
2-currently I am able to print clob file with below code.
OPEN c_clob;
LOOP
FETCH c_clob INTO c;
EXIT
WHEN c_clob%notfound;
printout(c);
but problem in above code is if I use this variable into insert statement then it gives error due to CLOB to VAR insertion.
INSERT INTO Table1 VALUES(c);
commit;
ORA-22835: Buffer too small for CLOB to CHAR or BLOB to RAW conversion (actual: 848239, maximum: 4000)
Is there any other option available to handle huge flat-file from clob field and dump into a table.
Currently I am using below code
declare
nStartIndex number := 1;
nEndIndex number := 1;
nLineIndex number := 0;
vLine varchar2(2000);
cursor c_clob is
select char_data from clob_table where seq=1022;
c clob;
procedure printout
(p_clob in out nocopy clob) is
offset number := 1;
amount number := 32767;
amount_last number := 0;
len number := dbms_lob.getlength(p_clob);
lc_buffer varchar2(32767);
line_seq pls_integer := 1;
-- For UNIX type file - replace CHR(13) to NULL
CR char := chr(13);
--CR char := NULL;
LF char := chr(10);
nCRLF number;
sCRLF varchar2(2);
b_finish boolean := true;
begin
sCRLF := CR || LF;
nCRLF := Length(sCRLF);
if ( dbms_lob.isopen(p_clob) != 1 ) then
dbms_lob.open(p_clob, 0);
end if;
amount := instr(p_clob, sCRLF, offset);
while ( offset < len )
loop
-- For without CR/LF on end file
If amount < 0 then
amount := len - offset + 1;
b_finish := false;
End If;
dbms_lob.read(p_clob, amount, offset, lc_buffer);
If b_finish then
lc_buffer := SUBSTR(lc_buffer,1,Length(lc_buffer)-1);
End If;
if (line_seq-1) > 0 then
amount_last := amount_last + amount;
offset := offset + amount;
else
amount_last := amount;
offset := amount + nCRLF;
end if;
amount := instr(p_clob, sCRLF, offset);
amount := amount - amount_last;
dbms_output.put_line('Line #'||line_seq||': '||lc_buffer);
line_seq := line_seq + 1;
end loop;
if ( dbms_lob.isopen(p_clob) = 1 ) then
dbms_lob.close(p_clob);
end if;
exception
when others then
dbms_output.put_line('Error : '||sqlerrm);
end printout;
begin
open c_clob;
loop
fetch c_clob into c;
exit when c_clob%notfound;
printout(c);
end loop;
close c_clob;
end;
Here line printout(c); (4th last line in code) showing me clob data line by line untill buffer gets overflow.
Expected result: To read data from clob flat-file and insert rows into table column wise, That's I am trying to achieve. Constraints is Flat-Files contains millions of records.
i'm using something like this
...
select * into ifile from clob_table where ...;
file_length := dbms_lob.getlength (ifile.char_data);
p_start :=1;
while p_start<>0 loop
end_pos := dbms_lob.instr (ifile.char_data, chr (10), p_start);
if end_pos > 0 then
strRow := dbms_lob.substr(ifile.char_data, least (end_pos - p_start, 240), p_start),chr (13)||chr (10);
p_start := end_pos + 1;
tabRow := strRow2tabRow(strRow);
else
strRow := dbms_lob.substr (ifile.char_data, file_length - p_start + 1, p_start);
p_start := 0;
tabRow := strRow2tabRow(strRow);
end if;
insert into myTable values tabRow;
end loop;
...
and functions
function strRow2tabRow(strRow varchar2) return myTable%rowtype is
tabRow myTable%rowtype;
begin
tabRow.col1:=valueIncolumn(strRow,1);
tabRow.col2:=valueIncolumn(strRow,2);
...
/*or maybe this may be better for you
select * into tabRow from (
select rownum rn, regexp_substr(strRow,'[^,]+', 1, level) hdn from dual connect by regexp_substr(strRow, '[^,]+', 1, level) is not null
) pivot (max(hdn) for rn in (1, 2, ...));
*/
return tabRow;
exception when others then
return tabRow;
end;
function valueIncolumn(strRow varchar2, pos in number) return varchar2 is
ret varchar2(1024);
begin
select hdn into ret from (
select rownum rn, regexp_substr(strRow,'[^,]+', 1, level) hdn from dual connect by regexp_substr(strRow, '[^,]+', 1, level) is not null
) where rownum=pos;
return ret;
exception when others then
return null;
end;
hope it helps

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