Change from Default Date to preferred date in this DBMS_SQL? - sql

This code is from the proposed solution:
https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:9541646100346616701
My query is 'select * from table'
The second column is a DATE and this routine writes it as appears in my IDE session ('DD-MON-YY');
How can I report the values in DATE columns to 'YYYY-MM-DD'?
procedure clob_maker(p_query varchar2) is
l_theCursor integer default dbms_sql.open_cursor;
l_columnValue varchar2(4000);
l_status integer;
l_descTbl dbms_sql.desc_tab;
l_colCnt number;
n number := 0;
l_data clob;
begin
dbms_sql.parse( l_theCursor, p_query, dbms_sql.native );
dbms_sql.describe_columns( l_theCursor, l_colCnt, l_descTbl );
for i in 1 .. l_colCnt loop
dbms_sql.define_column(l_theCursor, i, l_columnValue, 4000);
end loop;
l_status := dbms_sql.execute(l_theCursor);
while ( dbms_sql.fetch_rows(l_theCursor) > 0 ) loop
for i in 1 .. l_colCnt loop
dbms_sql.column_value( l_theCursor, i, l_columnValue );
--dbms_output.put_line(l_columnValue); --this puts every column on a separate line
l_data := l_data || l_columnValue ||',';
end loop;
dbms_output.put_line(l_data);
n := n + 1;
end loop;
--dbms_output.put_line(l_data);
end clob_maker;
clob_maker('select * from mlb_catcher_birthdays fetch first 10 rows only');

The default format in which dates are represented is controlled by NLS parameter ns_date_format. You can just change this parameter at session level:
alter session set nls_date_format = 'YYYY-MM-DD';
You could also use TO_CHAR(), with the same format specifier as second argument - but this does not fit very well to your use case, since you would then need to check the datatype of each column before printing its value.

Related

Oracle pl/sql Change Array Size and Members After Delete

For example i have an array like
"a(1):=1 ,a(2):=2, a(3) := 3"
and now my array count =3 "(a.count)"
then i delete middle member "a.delete(2)" then i wanna make my array like this "a(1):=1;a(2):=3" and my array count = 2 ("a.count") how can i do this ?
ps:i need to this with big sized array so i think i should use, for or while loop but how...
The collection where you have deleted some element is called sparse collection. Below you have example how to iterate that type of collection and how to use it with forall.
declare
type a is table of number;
ar a;
v_idx number;
begin
select level bulk collect into ar from dual connect by level< 1000;
ar.delete(1);
ar.delete(4);
ar.delete(10);
ar.delete(88);
v_idx := ar.first;
while v_idx is not null loop
dbms_output.put_line('idx: '||v_idx ||' value:'|| ar(v_idx));
v_idx := ar.next(v_idx);
end loop;
-- FORALL i IN INDICES OF ar
-- INSERT INTO test_table VALUES ar(i);
end;
Thank you but i should change array too , i need to take same output when i print array members like
for i in ar.first..ar.last loop
dbms_output.put_line(ar(i));
end loop;
declare
type a is table of number;
ar a;
begin
select level bulk collect into ar from dual connect by level< 1000;
ar.delete(1);
ar.delete(4);
ar.delete(10);
ar.delete(88);
-- ar is sparse collection;
ar := ar MULTISET intersect ar;
-- ar is dense collection and for i in .... is possible
FOR i IN ar.first .. ar.last LOOP
DBMS_OUTPUT.put_line(ar(i));
END LOOP;
end;
you can try this approach assign values of first spared collection to second continues collection and use second collection for further processing...
declare
type num_arr is table of number;
v_num_arr1 num_arr; --first collection
v_num_arr2 num_arr := num_arr(); -- second collection initialization and declaration
v_idx number;
v_col_index number := 1;
begin
-- fill 10 element.
select level || '1' as num1 bulk collect into v_num_arr1 from dual connect by level < 10;
for x in v_num_arr1.first .. v_num_arr1.last loop
dbms_output.put_line('index: ' || x || ' value: ' || v_num_arr1(x));
end loop;
dbms_output.put_line('');
-- delete element
v_num_arr1.delete(3);
v_num_arr1.delete(7);
v_idx := v_num_arr1.first;
while v_idx is not null loop
dbms_output.put_line('index: ' || v_idx || ' value: ' || v_num_arr1(v_idx));
-- filling second collection with regular index by variable v_col_index
if v_num_arr1(v_idx) is not null then
v_num_arr2.extend(1);
v_num_arr2(v_col_index) := v_num_arr1(v_idx);
v_col_index := v_col_index + 1;
end if;
v_idx := v_num_arr1.next(v_idx);
end loop;
dbms_output.put_line('second collection elements
');
--check second colleciton
for x in v_num_arr2.first .. v_num_arr2.last loop
dbms_output.put_line('index: ' || x || ' value: ' || v_num_arr2(x));
end loop;
end;

how to find multiple of a number using goto sql statement?

Write a PL/SQL block to display the multiples of a Given Number
without including multiples of 10 for a given range (Start Value and
End Value), using GOTO.
This is my try, but I couldn't place the goto statement in correct place:
declare
start_value number; end_value number; n number;
result;
begin
start_value:=&start_value;
end_value:=&end_value;
n :=&n;
for x in start_value..end_value loop
<<calc>>
if((x mod n)=0 and (x mod 10)!=0) then
dbms_output.put_line(x);
end if;
goto calc;
end loop;
end;
First off, this is a really bad assignment. Teaching you to use GOTO's is like teaching a naval architect to build ships without watertight bulkheads - it's Just Wrong. (sigh) But, oh well...
DECLARE
start_value NUMBER;
end_value NUMBER;
n NUMBER;
BEGIN
start_value := &start_value;
end_value := &end_value;
n := &n;
FOR x IN start_value..end_value LOOP
IF MOD(x, 10) = 0 THEN
GOTO skip_calc;
END IF;
DBMS_OUTPUT.PUT_LINE(n * x);
<<skip_calc>>
NULL;
END LOOP;
END;
The way this would normally be written is:
DECLARE
start_value NUMBER;
end_value NUMBER;
n NUMBER;
BEGIN
start_value := &start_value;
end_value := &end_value;
n := &n;
FOR x IN start_value..end_value LOOP
IF MOD(x, 10) <> 0 THEN
DBMS_OUTPUT.PUT_LINE(n * x);
END IF;
END LOOP;
END;
Shorter and easier to read.

PL SQL : custom data type declaration of the type of this expression is incomplete or malformed function

I have create a package with a function like this :
create or replace
PACKAGE TRANSAC_ERRONNEES AS
TYPE dateArrayVar IS TABLE OF DATE;
FUNCTION calc_date_moyenne(dateArrayIn dateArrayVar
) RETURN DATE;
END TRANSAC_ERRONNEES;
Body :
CREATE OR REPLACE PACKAGE BODY TRANSAC_ERRONNEES AS
FUNCTION calc_date_moyenne(dateArrayIn datearrayvar) RETURN DATE IS
dateFinal DATE;
tempsEnSeconde NUMBER;
tempsMoyenEnSeconde NUMBER;
BEGIN
tempsEnSeconde := 0;
tempsMoyenEnSeconde := 0;
FOR i IN 1..dateArrayIn.count loop
tempsEnSeconde := to_number(to_char(dateArrayIn(i), 'HH24')) * 60 * 60 + to_number(to_char(dateArrayIn(i), 'MI')) * 60 + to_number(to_char(dateArrayIn(i), 'SS'));
tempsMoyenEnSeconde := tempsMoyenEnSeconde+tempsEnSeconde;
end loop;
tempsMoyenEnSeconde := tempsMoyenEnSeconde/dateArrayIn.count;
dateFinal := to_date(TO_CHAR(dateArrayIn(1),'DD-MM-YYYY') || ' ' || TO_CHAR(to_date(tempsMoyenEnSeconde,'sssss'), 'HH24:MI:SS'), 'DD-MM-YYYY HH24:MI:SS');
dbms_output.put_line(TO_CHAR(dateFinal,'DD-MM-YYYY HH24:MI:SS'));
RETURN dateFinal;
END calc_date_moyenne;
END TRANSAC_ERRONNEES;
/
I try to test this function like this :
DECLARE
dates dateArrayVar;
resultat DATE;
BEGIN
dates := dateArrayVar(SYSDATE, SYSDATE);
resultat := transac_erronnees.calc_date_moyenne(dates);
END;
I'm getting this following error :
PLS-00320: the declaration of the type of this expression is
incomplete or malformed
Please let me know the error. Thanks in advance.
You are using it in incorrect way. You need to use array with extend to assign memory and then assign value in it.
DECLARE
dates dateArrayVar;
resultat DATE;
BEGIN
dates.extend(2); -- Since you want to assign two values, extend by 2
dates(1) := SYSDATE;
dates(2) := SYSDATE;
resultat := transac_erronnees.calc_date_moyenne(dates);
END;
Update: Second thing is that DateArrayVar has scope only within the package that you have created, in the anonymous block, Oracle cannot see that declaration. One solution is to create external type that is visible to all other procedures and anonymous block or to test, create a procedure within the package and call it from out side.
create or replace
PACKAGE TRANSAC_ERRONNEES AS
TYPE dateArrayVar IS TABLE OF DATE;
FUNCTION calc_date_moyenne(dateArrayIn dateArrayVar
) RETURN DATE;
PROCEDURE test;
END TRANSAC_ERRONNEES;
/
CREATE OR REPLACE PACKAGE BODY TRANSAC_ERRONNEES AS
FUNCTION calc_date_moyenne(dateArrayIn datearrayvar) RETURN DATE IS
dateFinal DATE;
tempsEnSeconde NUMBER;
tempsMoyenEnSeconde NUMBER;
BEGIN
tempsEnSeconde := 0;
tempsMoyenEnSeconde := 0;
FOR i IN 1..dateArrayIn.count loop
tempsEnSeconde := to_number(to_char(dateArrayIn(i), 'HH24')) * 60 * 60 + to_number(to_char(dateArrayIn(i), 'MI')) * 60 + to_number(to_char(dateArrayIn(i), 'SS'));
tempsMoyenEnSeconde := tempsMoyenEnSeconde+tempsEnSeconde;
end loop;
tempsMoyenEnSeconde := tempsMoyenEnSeconde/dateArrayIn.count;
dateFinal := to_date(TO_CHAR(dateArrayIn(1),'DD-MM-YYYY') || ' ' || TO_CHAR(to_date(tempsMoyenEnSeconde,'sssss'), 'HH24:MI:SS'), 'DD-MM-YYYY HH24:MI:SS');
dbms_output.put_line(TO_CHAR(dateFinal,'DD-MM-YYYY HH24:MI:SS'));
RETURN dateFinal;
END calc_date_moyenne;
PROCEDURE test
dates dateArrayVar;
resultat DATE;
BEGIN
dates.extend(2); -- Since you want to assign two values, extend by 2
dates(1) := SYSDATE;
dates(2) := SYSDATE;
resultat := transac_erronnees.calc_date_moyenne(dates);
END;
END TRANSAC_ERRONNEES;
/
And to test, call it as
BEGIN
TRANSAC_ERRONNEES.TEST;
END;
/
DateArrayVar has scope only within the package
I found the solution : I had to specifiate the package : TRANSAC_ERRONNEES.dateArrayVar;
So :
DECLARE
dates TRANSAC_ERRONNEES.dateArrayVar;
resultat DATE;
BEGIN
dates := TRANSAC_ERRONNEES.dateArrayVar(SYSDATE, SYSDATE);
resultat := transac_erronnees.calc_date_moyenne(dates);
dbms_output.put_line(TO_CHAR(resultat,'DD-MM-YYYY HH24:MI:SS'));
END;
It's works now, Thanks

how can we get the value of of VARRAY from IN Parameter in procedure

I am new to PL/SQL... In Varray how can i get multiple value from IN parameter..... else Is there another ways to get the values...
I want to interate the values through VArray... if any other options then its fine..
coding:
CREATE OR REPLACE
PROCEDURE dynamic_query_build(
vr_plan_sku_id IN VARCHAR2 )
IS
type plan_sku_id_array IS VARRAY(999) OF VARCHAR2(5000);
plan_sku_id plan_sku_id_array;
total INTEGER;
vrx_plan_sku_id VARCHAR2(3000);
BEGIN
vrx_plan_sku_id:= REPLACE(vr_plan_sku_id,',',chr(39)||','||chr(39));
plan_sku_id := plan_sku_id_array(chr(39)||vrx_plan_sku_id||chr(39));
total := plan_sku_id.count;
FOR i IN 1 .. total
LOOP
dbms_output.put_line(plan_sku_id(i));
END LOOP;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
END dynamic_query_build;
Execution:
set serveroutput on;
declare
vr_plan_sku_id varchar2(200) := '5863314,5863315';
BEGIN
dynamic_query_build(vr_plan_sku_id);
END;
/
My Output:
anonymous block completed
'5863314','5863315'
Expected output:
5863314
5863315
now it is considering as single value....
I created anonymous block with procedure dynamic_query_build. Added there code, that will split VARCHAR2 variable into varray.
I think, the key to your question is this line - plan_sku_id.EXTEND();
You can extend varray dynamically, but only till it reaches defined maximum (in your case - 999).
DECLARE
vr_plan_sku_id varchar2(200) := '5863314,5863315';
PROCEDURE dynamic_query_build(
vr_plan_sku_id IN VARCHAR2 )
IS
type plan_sku_id_array IS VARRAY(999) OF VARCHAR2(5000);
plan_sku_id plan_sku_id_array;
total INTEGER;
position PLS_INTEGER := 0;
last_position PLS_INTEGER := 1;
tmp VARCHAR2(5000);
counter PLS_INTEGER := 1;
BEGIN
plan_sku_id := plan_sku_id_array();
LOOP
position := INSTR(vr_plan_sku_id, ',', last_position);
IF position > 0 THEN
tmp := SUBSTR(vr_plan_sku_id, last_position, position - last_position);
last_position := position + 1;
ELSE
tmp := SUBSTR(vr_plan_sku_id, last_position);
END IF;
plan_sku_id.EXTEND();
plan_sku_id(counter) := tmp;
counter := counter + 1;
EXIT WHEN position = 0 OR counter > 10;
END LOOP;
total := plan_sku_id.count;
FOR i IN 1 .. total
LOOP
dbms_output.put_line(plan_sku_id(i));
END LOOP;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
END dynamic_query_build;
BEGIN
dynamic_query_build(vr_plan_sku_id);
END;
/
Put a replace in the dbms_output statement this will eliminate the quotes from the string
....
dbms_output.put_line replace (replace (plan_sku_id(i), '''' ))',',chr(10);
.....

Oracle : how to fetch data from dynamic query?

I have a program to generate dynamic query string based on input. This query may select from any tables or joined tables in my DB, and the column names and number of columns are unknown.
Now with this query string as the only input, I want to fetch all data from the result and output them line by line, is there any way to do this ?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Thank Thinkjet for the reference. I have solved the problem, to help the others, here is the piece of code I used:
DECLARE
v_curid NUMBER;
v_desctab DBMS_SQL.DESC_TAB;
v_colcnt NUMBER;
v_name_var VARCHAR2(10000);
v_num_var NUMBER;
v_date_var DATE;
v_row_num NUMBER;
p_sql_stmt VARCHAR2(1000);
BEGIN
v_curid := DBMS_SQL.OPEN_CURSOR;
p_sql_stmt :='SELECT * FROM emp';
DBMS_SQL.PARSE(v_curid, p_sql_stmt, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS(v_curid, v_colcnt, v_desctab);
-- Define columns:
FOR i IN 1 .. v_colcnt LOOP
IF v_desctab(i).col_type = 2 THEN
DBMS_SQL.DEFINE_COLUMN(v_curid, i, v_num_var);
ELSIF v_desctab(i).col_type = 12 THEN
DBMS_SQL.DEFINE_COLUMN(v_curid, i, v_date_var);
ELSE
DBMS_SQL.DEFINE_COLUMN(v_curid, i, v_name_var, 50);
END IF;
END LOOP;
v_row_num := dbms_sql.execute(v_curid);
-- Fetch rows with DBMS_SQL package:
WHILE DBMS_SQL.FETCH_ROWS(v_curid) > 0 LOOP
FOR i IN 1 .. v_colcnt LOOP
IF (v_desctab(i).col_type = 1) THEN
DBMS_SQL.COLUMN_VALUE(v_curid, i, v_name_var);
ELSIF (v_desctab(i).col_type = 2) THEN
DBMS_SQL.COLUMN_VALUE(v_curid, i, v_num_var);
ELSIF (v_desctab(i).col_type = 12) THEN
DBMS_SQL.COLUMN_VALUE(v_curid, i, v_date_var);
END IF;
END LOOP;
END LOOP;
DBMS_SQL.CLOSE_CURSOR(v_curid);
END;
/
You can do that with DBMS_SQL package.
Update
To get more detailed reference about DBMS_SQL go here.
If you are building your string within PL/SQL, you can run it with EXECUTE IMMEDIATE. <- link. Use the BULK COLLECT INTO and output the collection.
<PRE>
DECLARE
RUN_S CLOB;
IGNORE NUMBER;
SOURCE_CURSOR NUMBER;
PWFIELD_COUNT NUMBER DEFAULT 0;
L_DESCTBL DBMS_SQL.DESC_TAB2;
Z_NUMBER NUMBER;
BEGIN
RUN_S := ' SELECT 1 AS VAL1,
2 AS VAL2,
CURSOR (SELECT 11 AS VAL11,
12 AS VAL12
FROM DUAL) AS CUR1,
CURSOR (SELECT 11 AS VAL11,
12 AS VAL12
FROM DUAL) AS CUR2
FROM DUAL';
SOURCE_CURSOR := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(SOURCE_CURSOR, RUN_S, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS2(SOURCE_CURSOR, PWFIELD_COUNT, L_DESCTBL); -- get record structure
FOR I IN 1 .. PWFIELD_COUNT LOOP
DBMS_OUTPUT.PUT_LINE('Col ' || I || ' Type:' || L_DESCTBL(I).COL_TYPE);
IF L_DESCTBL(I).COL_TYPE = 2 THEN
DBMS_SQL.DEFINE_COLUMN(SOURCE_CURSOR, I, Z_NUMBER);
END IF;
NULL;
END LOOP;
IGNORE := DBMS_SQL.EXECUTE(SOURCE_CURSOR);
LOOP
IF DBMS_SQL.FETCH_ROWS(SOURCE_CURSOR) > 0 THEN
FOR I IN 1 .. PWFIELD_COUNT LOOP
IF L_DESCTBL(I).COL_TYPE IN (2) THEN
DBMS_SQL.COLUMN_VALUE(SOURCE_CURSOR, I, Z_NUMBER);
DBMS_OUTPUT.PUT_LINE('Col ' || I || ' Value:' || Z_NUMBER);
END IF;
END LOOP;
ELSE
EXIT;
END IF;
END LOOP;
END;
</PRE>