Function triggering: Encountered the symbol "BEGIN"? - oracle

Relative newbie here. I have a 3 part assignment and can't seem to get the last section to populate properly. I am attempting to use 2 functions to output both the average number of guests (which works) and the total number of booked nights (not working).
Here is the working code for the two parts:
SQL> DECLARE
2 DDI_REC DDI.LEDGER_VIEW %ROWTYPE; --declaring DDI_REC
3 DDI_ROOM DDI.LEDGER_VIEW.ROOMNUM%type := 0; --declaring DDI_ROOM and assiging it to ZERO
4 FOUND_ROWS BOOLEAN := FALSE; --variable to test for no_data_found exception in the FOR LOOP
5
6 FUNCTION AVG_GUESTS(ROOM IN NUMBER)
7 RETURN NUMBER
8 AS AVERAGE NUMBER;
9
10 BEGIN
11 SELECT AVG(ADULTCNT + CHILDCNT)
12 INTO AVERAGE
13 FROM DDI.LEDGER_VIEW
14 WHERE ROOMNUM = ROOM;
15
16 RETURN AVERAGE;
17
18 EXCEPTION
19 WHEN OTHERS THEN
20 RETURN NULL;
21 END;
22
23
24 BEGIN
25 DBMS_OUTPUT.NEW_LINE;
26 DBMS_OUTPUT.PUT_LINE (' AVG ROOM RENTALS');
27 DBMS_OUTPUT.PUT_LINE (' PER DDI.LEDGER_VIEW');
28 DBMS_OUTPUT.NEW_LINE;
29 DBMS_OUTPUT.PUT_LINE (' ROOM AVG NUMBER BOOKED');
30 DBMS_OUTPUT.PUT_LINE (' NUM OF GUESTS NIGHTS');
31 DBMS_OUTPUT.PUT_LINE (' ---- ---------- ------');
32
33 -- LOOP CALLS FUNCTION AVG_GUESTS ON EACH CHANGE IN ROOMNUM
34
35 FOR DDI_REC IN
36 (SELECT *
37 FROM DDI.LEDGER_VIEW
38 ORDER BY ROOMNUM)
39 LOOP
40 FOUND_ROWS := TRUE; --if data exist, sets variable to TRUE, so IF statement doesn't run
41 IF DDI_ROOM != DDI_REC.ROOMNUM THEN
42 DDI_ROOM := DDI_REC.ROOMNUM;
43 DBMS_OUTPUT.PUT_LINE(' ' ||DDI_ROOM||' '||TO_CHAR(AVG_GUESTS(DDI_ROOM), '9.99'));
44 END IF;
45 END LOOP; -- End of loop
46
47
48 IF NOT FOUND_ROWS THEN -- trigger the exception below when no results are returned
49 RAISE NO_DATA_FOUND;
50 END IF;
51
52 EXCEPTION
53 WHEN NO_DATA_FOUND THEN
54 DBMS_OUTPUT.PUT_LINE('No data found.');
55 END;
56 /
AVG ROOM RENTALS
PER DDI.LEDGER_VIEW
ROOM AVG NUMBER BOOKED
NUM OF GUESTS NIGHTS
---- ---------- ------
101 1.00
102 2.00
103 2.14
104 2.17
105 2.40
106 1.75
107 1.67
108 1.80
PL/SQL procedure successfully completed.
and now the broken code as I try to get "Booked Nights" working. I might even be barking up the wrong tree for how to go about it.
SQL> DECLARE
2 DDI_REC DDI.LEDGER_VIEW %ROWTYPE; --declaring DDI_REC
3 DDI_ROOM DDI.LEDGER_VIEW.ROOMNUM%type := 0; --declaring DDI_ROOM and assiging it to ZERO
4 FOUND_ROWS BOOLEAN := FALSE; --variable to test for no_data_found exception in the FOR LOOP
5 BOOKED_ROOMS DDI.LEDGER_VIEW.ROOMNUM%type := 0; --declaring BOOKED_ROOMS
6
7 FUNCTION AVG_GUESTS(ROOM IN NUMBER)
8 RETURN NUMBER
9 AS AVERAGE NUMBER;
10
11 BEGIN
12 SELECT AVG(ADULTCNT + CHILDCNT)
13 INTO AVERAGE
14 FROM DDI.LEDGER_VIEW
15 WHERE ROOMNUM = ROOM;
16
17 RETURN AVERAGE;
18
19 EXCEPTION
20 WHEN OTHERS THEN
21 RETURN NULL;
22 END;
23
24 BEGIN
25 SELECT COUNT(*)
26 FROM DDI.LEDGER_VIEW
27 WHERE ROOMNUM = BOOKED_ROOMS;
28
29 EXCEPTION
30 WHEN OTHERS THEN
31 RETURN NULL;
32 END;
33
34
35 BEGIN
36 DBMS_OUTPUT.NEW_LINE;
37 DBMS_OUTPUT.PUT_LINE (' AVG ROOM RENTALS');
38 DBMS_OUTPUT.PUT_LINE (' PER DDI.LEDGER_VIEW');
39 DBMS_OUTPUT.NEW_LINE;
40 DBMS_OUTPUT.PUT_LINE (' ROOM AVG NUMBER BOOKED');
41 DBMS_OUTPUT.PUT_LINE (' NUM OF GUESTS NIGHTS');
42 DBMS_OUTPUT.PUT_LINE (' ---- ---------- ------');
43
44 -- LOOP CALLS FUNCTION AVG_GUESTS ON EACH CHANGE IN ROOMNUM
45
46 FOR DDI_REC IN
47 (SELECT *
48 FROM DDI.LEDGER_VIEW
49 ORDER BY ROOMNUM)
50 LOOP
51 FOUND_ROWS := TRUE; --if data exist, sets variable to TRUE, so IF statement doesn't run
52 IF DDI_ROOM != DDI_REC.ROOMNUM THEN
53 DDI_ROOM := DDI_REC.ROOMNUM;
54 DBMS_OUTPUT.PUT_LINE(' ' ||DDI_ROOM||' '||TO_CHAR(AVG_GUESTS(DDI_ROOM), '9.99')|| ' '||TO_CHAR(BOOKED_ROOMS));
55 END IF;
56 END LOOP; -- End of loop
57
58
59 IF NOT FOUND_ROWS THEN -- trigger the exception below when no results are returned
60 RAISE NO_DATA_FOUND;
61 END IF;
62
63 EXCEPTION
64 WHEN NO_DATA_FOUND THEN
65 DBMS_OUTPUT.PUT_LINE('No data found.');
66 END;
67 /
BEGIN
*
ERROR at line 35:
ORA-06550: line 35, column 5:
PLS-00103: Encountered the symbol "BEGIN"
Any and all suggestions welcome... Thank you in advance.

I reformatted your code and added BEGIN-END outmost block (which is missing), along with some comments. Have a look.
DECLARE
ddi_rec ddi.ledger_view%rowtype; --declaring DDI_REC
ddi_room ddi.ledger_view.roomnum%TYPE := 0; --declaring DDI_ROOM and assiging it to ZERO
found_rows BOOLEAN := false; --variable to test for no_data_found exception in the FOR LOOP
booked_rooms ddi.ledger_view.roomnum%TYPE := 0; --declaring BOOKED_ROOMS
FUNCTION avg_guests (
room IN NUMBER
) RETURN NUMBER AS
average NUMBER;
BEGIN
SELECT AVG(adultcnt + childcnt) INTO
average
FROM ddi.ledger_view
WHERE roomnum = room;
RETURN average;
EXCEPTION
WHEN OTHERS THEN
RETURN NULL;
END;
BEGIN --> you miss this outmost BEGIN ...
-- the 1st begin-exception-end block has to be part of the outmost begin-end
BEGIN
SELECT COUNT(*)
FROM ddi.ledger_view
WHERE roomnum = booked_rooms;
EXCEPTION
WHEN OTHERS THEN
RETURN NULL;
END; -- the 1st block ends here
-- the 2nd begin-exception-end block begins here
BEGIN
dbms_output.new_line;
dbms_output.put_line(' AVG ROOM RENTALS');
dbms_output.put_line(' PER DDI.LEDGER_VIEW');
dbms_output.new_line;
dbms_output.put_line(' ROOM AVG NUMBER BOOKED');
dbms_output.put_line(' NUM OF GUESTS NIGHTS');
dbms_output.put_line(' ---- ---------- ------');
-- LOOP CALLS FUNCTION AVG_GUESTS ON EACH CHANGE IN ROOMNUM
FOR ddi_rec IN ( SELECT * FROM ddi.ledger_view
ORDER BY roomnum ) LOOP
found_rows := true; --if data exist, sets variable to TRUE, so IF statement doesn't run
IF
ddi_room != ddi_rec.roomnum
THEN
ddi_room := ddi_rec.roomnum;
dbms_output.put_line(' '
|| ddi_room
|| ' '
|| TO_CHAR(avg_guests(ddi_room),'9.99')
|| ' '
|| TO_CHAR(booked_rooms) );
END IF;
END LOOP; -- End of loop
IF
NOT found_rows
THEN -- trigger the exception below when no results are returned
RAISE no_data_found;
END IF;
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('No data found.');
END; -- the 2nd begin-exception-end block ends here
END; --> ... and you miss this END, for the outmost begin-end block
/

I see two problems. You have two BEGIN blocks in the main body. I believe Littlefoot corrected that. Also:
25 SELECT COUNT(*)
26 FROM DDI.LEDGER_VIEW
27 WHERE ROOMNUM = BOOKED_ROOMS;
You need an INTO clause after the count(*). You'll need to select the value into a variable and do something with the variable. You can't have a naked SELECT in PL/SQL like you can just at the sqlplus command line.

Related

How to create dynamic cursor in PLSQL - Oracle

I cannot create this cursor dynamically, I only have to modify the name of the table in the statement. But it returns me error.
What am I doing wrong or what am I missing to create the dynamic cursor?
The dynamic statement is in the Lv_SQL variable and I call the cursor C_DATOS but it does not recognize it.
PROCEDURE PROC_CAB_DET(Pv_corte VARCHAR2, Pv_MsjError IN OUT VARCHAR2) IS
Lv_Table VARCHAR2(100);
Lv_SQL VARCHAR2(5000);
C_DATOS SYS_REFCURSOR;
BEGIN
Lv_Table := NULL;
IF (Pv_corte IN ('02', '03')) THEN
Lv_Table := 'TABLE_TMP_MOV';
ELSIF (Pv_corte IN ('14', '15')) THEN
Lv_Table := 'TABLE_TMP_FIX';
ELSE
Lv_Table := 'TABLE_TMP_CMF';
END IF;
Lv_SQL := 'SELECT cuenta, campo_2 RUBRO
FROM ' || Lv_Table || '
WHERE codigo = 1
AND CAMPO_3 != "000"
AND (campo_2 NOT IN (SELECT RUBRO FROM GSI_QC_RUBROS_CABECERA)
AND upper(campo_2) NOT LIKE "NAN%")
MINUS
SELECT cuenta, campo_2 RUBRO
FROM ' || Lv_Table || '
WHERE codigo=4
AND campo_2 != "ICE (12%)"';
OPEN C_DATOS FOR Lv_SQL;
FOR I IN C_DATOS LOOP
INSERT INTO GSI_QC_CBS_CASOS_ERROR(CUENTA, ID_ESCENARIO, DATO_TMP_1)
VALUES(I.CUENTA, 'IdEscenario', 'DATA');
END LOOP;
COMMIT;
CLOSE C_DATOS;
EXCEPTION
WHEN OTHERS THEN
Pv_MsjError := SQLERRM;
END PROC_CAB_DET;
PLS-00221: C_DATOS is not a procedure or is undefined
You can't enclose strings into double quotes; have to be single ones. To make it simpler, use the q-quoting mechanism. Also, you wrongly looped through refcursor.
I created dummy tables to make that procedure compile; I don't know whether code does what you planned.
SQL> create or replace
2 PROCEDURE PROC_CAB_DET(Pv_corte VARCHAR2, Pv_MsjError IN OUT VARCHAR2) IS
3 Lv_Table VARCHAR2(100);
4 Lv_SQL VARCHAR2(5000);
5 C_DATOS SYS_REFCURSOR;
6 --
7 l_cuenta table_tmp_mov.cuenta%type;
8 l_rubro table_tmp_mov.campo_2%type;
9 BEGIN
10 Lv_Table := NULL;
11 IF (Pv_corte IN ('02', '03')) THEN
12 Lv_Table := 'TABLE_TMP_MOV';
13 ELSIF (Pv_corte IN ('14', '15')) THEN
14 Lv_Table := 'TABLE_TMP_FIX';
15 ELSE
16 Lv_Table := 'TABLE_TMP_CMF';
17 END IF;
18
19 Lv_SQL := 'SELECT cuenta, campo_2 RUBRO
20 FROM ' || Lv_Table || q'[
21 WHERE codigo = 1
22 AND CAMPO_3 != '000'
23 AND (campo_2 NOT IN (SELECT RUBRO FROM GSI_QC_RUBROS_CABECERA)
24 AND upper(campo_2) NOT LIKE 'NAN%')
25 MINUS
26 SELECT cuenta, campo_2 RUBRO
27 FROM ]' || Lv_Table || q'[
28 WHERE codigo=4
29 AND campo_2 != 'ICE (12%)']';
30
31 OPEN C_DATOS FOR Lv_SQL;
32
33 loop
34 fetch c_datos into l_cuenta, l_rubro;
35 exit when c_datos%notfound;
36
37 INSERT INTO GSI_QC_CBS_CASOS_ERROR(CUENTA, ID_ESCENARIO, DATO_TMP_1)
38 VALUES(l_CUENTA, 'IdEscenario', 'DATA');
39 END LOOP;
40 COMMIT;
41
42 CLOSE C_DATOS;
43
44 EXCEPTION
45 WHEN OTHERS THEN
46 Pv_MsjError := SQLERRM;
47 END PROC_CAB_DET;
48 /
Procedure created.
Let's run it:
SQL> set serveroutput on;
SQL> declare
2 l_err varchar2(200);
3 begin
4 proc_cab_det('02', l_err);
5 dbms_output.put_line('error = ' || l_err);
6 end;
7 /
error =
PL/SQL procedure successfully completed.
SQL>
Replace " inside your lv_SQL string with doubled single quotes, ''

oracle 11g ORA-06502: PL/SQL: numeric or value error: character string buffer too small

In oracle 11g r2,we want to get all the columns and Splicing, it issue:ORA-06502: PL/SQL: numeric or value error: character string buffer too small,and how to modify?
step 1:create table:
create table test.history_session as select * from dba_hist_active_sess_history where 1=1;
step 2: test:
declare
column_list1 varchar2(32767);
column_list2 varchar2(32767);
i number;
l number;
BEGIN
column_list1:='';
column_list2:='';
i:=0;
l:=0;
FOR v_column_name IN (SELECT owner, table_name, column_name,data_length,data_type FROM dba_tab_columns WHERE owner ='TEST' and table_name='HISTORY_SESSION'
and data_type in ('VARCHAR2','NVARCHAR2','NUMBER','CHAR') and data_length <=255 order by column_name) LOOP
if v_column_name.data_type='NUMBER' then
v_column_name.column_name:='to_char('||v_column_name.column_name||',''99999999999999999.99'')';
end if;
if l <3700 then
column_list1:=column_list1||v_column_name.column_name||chr(10)||'||''|'''||'||';
else
column_list2:=column_list2||v_column_name.column_name||chr(10)||'||''|'''||'||';
end if;
l:=l+v_column_name.data_length+10;
end loop;
dbms_output.put_Line(nvl(column_list1,' ')||nvl(column_list2,' '));
end;
/
error:
declare
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 14
i want to know how to modify?
You can't set cursor's variable to something else; this is wrong:
v_column_name.column_name:='to_char('||v_column_name.column_name| ...
Declare a local variable instead, then do those transformations, if needed. Something like this (ran as SCOTT user, so I'm using USER_TAB_COLUMNS instead).
SQL> CREATE TABLE history_session
2 (
3 id NUMBER
4 );
Table created.
SQL> DECLARE
2 column_list1 VARCHAR2 (32767);
3 column_list2 VARCHAR2 (32767);
4 l_column_name VARCHAR2 (200); --> local variable
5 i NUMBER;
6 l NUMBER;
7 BEGIN
8 column_list1 := '';
9 column_list2 := '';
10 i := 0;
11 l := 0;
12
13 FOR v_column_name IN ( SELECT --owner,
14 table_name,
15 column_name,
16 data_length,
17 data_type
18 FROM user_tab_columns
19 WHERE 1 = 1
20 -- AND owner = 'TEST'
21 AND table_name = 'HISTORY_SESSION'
22 AND data_type IN ('VARCHAR2',
23 'NVARCHAR2',
24 'NUMBER',
25 'CHAR')
26 AND data_length <= 255
27 ORDER BY column_name)
28 LOOP
29 IF v_column_name.data_type = 'NUMBER'
30 THEN
31 --v_column_name.column_name :=
32 l_column_name :=
33 'to_char('
34 || v_column_name.column_name
35 || ',''99999999999999999.99'')';
36 ELSE
37 l_column_name := v_column_name.column_name;
38 END IF;
39
40 IF l < 3700
41 THEN
42 column_list1 :=
43 column_list1 || l_column_name --v_column_name.column_name
44 || CHR (10) || '||''|''' || '||';
45 ELSE
46 column_list2 :=
47 column_list2 || l_column_name --v_column_name.column_name
48 || CHR (10) || '||''|''' || '||';
49 END IF;
50
51 l := l + v_column_name.data_length + 10;
52 END LOOP;
53
54 DBMS_OUTPUT.put_Line (NVL (column_list1, ' ') || NVL (column_list2, ' '));
55 END;
56 /
to_char(ID,'99999999999999999.99')
||'|'||
PL/SQL procedure successfully completed.
SQL>
The result doesn't look pretty, but I'll leave it to you - fix it, now that procedure kind of works.

plsql what is wrong with this code error 'INTO list is of wrong type'

Can someone please help me? Why do I get this error "INTO list is of wrong type"?
DECLARE
TYPE v_dept_table IS TABLE OF DEPARTMENTS.DEPARTMENT_NAME%TYPE INDEX BY PLS_INTEGER;
v_record_dept_table v_dept_table;
v_loop_count NUMBER := 10;
v_dept_no NUMBER := 1;
BEGIN
FOR v_dept_no IN 1..v_loop_count LOOP
SELECT DEPARTMENTS.DEPARTMENT_NAME
INTO v_record_dept_table
FROM DEPARTMENTS
WHERE DEPARTMENT_ID = v_dept_no;
v_dept_no := v_dept_no + 1;
INSERT
INTO v_dept_table
VALUES v_record_dept_table;
END LOOP;
FOR indx IN NVL (v_dept_table.FIRST, 0) .. NVL (v_dept_table.LAST, -1)
LOOP
DBMS_OUTPUT.PUT_LINE(v_dept_table(indx));
END LOOP;
END;
ORA-06550: line 16, column 14:
PLS-00597: expression 'V_RECORD_DEPT_TABLE' in the INTO list is of wrong type
Why is it a wrong type? I'm using the hr schema from Oracle
Not exactly like that; you've done several things wrong. I tried to fix your code (with as little modifications as possible); have a look, read comments I wrote, compare it to your code. Side note: I used Scott's DEPT table as I don't have your DEPARTMENTS.
SQL> set serveroutput on
SQL> DECLARE
2 TYPE v_dept_table IS TABLE OF dept.dname%TYPE
3 INDEX BY PLS_INTEGER;
4
5 v_record_dept_table v_dept_table;
6
7 v_loop_count NUMBER := 10;
8 v_dept_no NUMBER := 1;
9 BEGIN
10 FOR v_dept_no IN 1 .. v_loop_count
11 LOOP
12 BEGIN
13 SELECT dname
14 INTO v_record_dept_table (v_dept_no) --> you're missing "(v_dept_no)"
15 FROM dept
16 WHERE deptno = v_dept_no;
17 -- Don't manually increment FOR loop variable; Oracle does it itself
18 -- v_dept_no := v_dept_no + 1;
19
20 -- You can't insert into "type"; besides, you've already inserted into V_RECORD_DEPT_TABLE.
21 -- INSERT INTO v_dept_table VALUES v_record_dept_table;
22 EXCEPTION
23 WHEN NO_DATA_FOUND
24 THEN
25 NULL;
26 END;
27 END LOOP;
28
29 -- loop through V_RECORD_DEPT_TABLE (collection), not V_DEPT_TABLE (type). No need for NVL.
30 FOR indx IN NVL (v_record_dept_table.FIRST, 0) ..
31 NVL (v_record_dept_table.LAST, -1)
32 LOOP
33 DBMS_OUTPUT.PUT_LINE (v_record_dept_table (indx));
34 END LOOP;
35 END;
36 /
ACCOUNTING
PL/SQL procedure successfully completed.
SQL>
Alternatively, see whether this helps. I used built-in type (sys.odcivarchar2list) and BULK COLLECT INTO (performs better).
SQL> DECLARE
2 v_record_dept_table SYS.odcivarchar2list;
3 BEGIN
4 SELECT dname
5 BULK COLLECT INTO v_record_dept_table
6 FROM dept;
7
8 FOR indx IN v_record_dept_table.FIRST .. v_record_dept_table.LAST
9 LOOP
10 DBMS_OUTPUT.PUT_LINE (v_record_dept_table (indx));
11 END LOOP;
12 END;
13 /
ACCOUNTING
RESEARCH
SALES
OPERATIONS
PL/SQL procedure successfully completed.
SQL>

Function in Package does not return the date,

I will publish the package body and call the function
The function is execute, but does not return data.
Maybe my calling function is bad.
Can you tell me where the error is?
Thanks in advance
My function in package body looks like this:
SQL> CREATE OR REPLACE PACKAGE BODY account_api AS
2 PROCEDURE add_new_account
3 ( p_acc_id accounts.acc_id%type
4 , p_acc_name accounts.acc_name%type
5 , p_acc_amount accounts.acc_amount%type
6 , p_acc_date accounts.acc_date%type)
7 IS
8 BEGIN
9 INSERT INTO accounts(acc_id, acc_name, acc_amount, acc_date)
10 VALUES (p_acc_id, p_acc_name, p_acc_amount, p_acc_date);
11 COMMIT;
12 EXCEPTION
13 WHEN OTHERS THEN
14 ROLLBACK;
15 RAISE;
16 END;
17 PROCEDURE upd_account
18 (p_acc_id accounts.acc_id%type
19 , p_acc_name accounts.acc_name%type
20 , p_acc_amount accounts.acc_amount%type
21 , p_acc_date accounts.acc_date%type
22 )
23 IS
24 BEGIN
25 UPDATE accounts
26 set acc_name = p_acc_name
27 , acc_amount = p_acc_amount
28 , acc_date = p_acc_date
29 WHERE acc_id = p_acc_id;
30 COMMIT;
31 END;
32 PROCEDURE del_accounts
33 (p_acc_id accounts.acc_id%type)
34 IS
35 BEGIN
36 DELETE FROM accounts WHERE acc_id = p_acc_id;
37 COMMIT;
38 EXCEPTION
39 WHEN OTHERS THEN
40 ROLLBACK;
41 RAISE;
42 END;
43 FUNCTION get_amount
44 (p_acc_id accounts.acc_id%type)
45 return Number is res number;
46 begin
47 select acc_amount into res
48 from accounts where acc_id =p_acc_id;
49 return res;
50 end;
51 FUNCTION get_date
52 (p_acc_id accounts.acc_id%type)
53 RETURN date IS res1 date;
54 BEGIN
55 SELECT acc_date INTO res1
56 FROM accounts WHERE acc_id = p_acc_id;
57 RETURN res1;
58 end;
59 end account_api;
60 /
The function is executed but does not return the data.
SQL> set serveroutput on
SQL> declare
2 res1 date;
3 begin
4 res1 := account_api.get_date(1);
5 end;
6 /
PL/SQL procedure successfully completed.
Try to check date by printing. It will show you the output.
set serveroutput on
declare
res1 date;
begin
res1 := account_api.get_date(1);
dbms_output.put_line(res1);
end;
/

Wrong calculation for daily partitions

Oracle : 11.2.0.2
I'm trying to drop monthy and daily partitions using a script. This works fine for monthly partitions but not for daily partitions. Below is the error I see in the log. Day of the month is becoming zero when calculating.
2013-08-0|SYS_P328538|2|YES
DECLARE
*
ERROR at line 1:
ORA-01847: day of month must be between 1 and last day of month
ORA-06512: at line 43
Here below is the script. I think highvalue date is miscalculated.
SQL> DECLARE
2 CURSOR tab_part_cur IS
3 select PARTITION_POSITION, PARTITION_NAME,HIGH_VALUE,INTERVAL from dba_tab_partitions where table_name = 'MO_USAGEDATA'
and table_owner = 'WSMUSER17'
order by PARTITION_POSITION;
4 tab_part_rec tab_part_cur%ROWTYPE;
5 lHighValue LONG;
6 strPartitionLessThanDate VARCHAR2(100);
7 dtTestDate DATE;
8 DaysInPast NUMBER;
9 SQLstr varchar2(100);
10 strIntervalType varchar2(1000);
11 strRunType varchar2(20);
12 BEGIN
13 strRunType := 'DRY_RUN';
14 select INTERVAL into strIntervalType from dba_part_tables where table_name ='MO_USAGEDATA' and owner = 'WSMUSER17';
15 strIntervalType := REGEXP_SUBSTR(strIntervalType, '''[^'']+''');
16 DBMS_OUTPUT.PUT_LINE(strIntervalType);
17 CASE
18 WHEN strIntervalType = '''DAY''' THEN
19 DBMS_OUTPUT.PUT_LINE('Interval type = '||strIntervalType);
20 -- dtTestDate := CURRENT_DATE - 7 - 1; Offset adjustment if necessary
21 dtTestDate := CURRENT_DATE - 7;
22 DBMS_OUTPUT.PUT_LINE('Test Date = '||dtTestDate);
23 WHEN strIntervalType = '''MONTH''' THEN
24 DBMS_OUTPUT.PUT_LINE('Interval type = '||strIntervalType);
25 -- dtTestDate := CURRENT_DATE - 90;
26 dtTestDate := ADD_MONTHS(current_date,- 7);
27 DBMS_OUTPUT.PUT_LINE('TestDate = '||dtTestDate);
28 ELSE
29 DBMS_OUTPUT.PUT_LINE('Unexpected interval, exiting.');
30 GOTO EXIT;
31 END CASE;
32 OPEN tab_part_cur;
33 LOOP
34 FETCH tab_part_cur INTO tab_part_rec;
35 EXIT WHEN tab_part_cur%NOTFOUND;
36 DBMS_OUTPUT.PUT_LINE(tab_part_cur%ROWCOUNT);
37 lHighValue := tab_part_rec.high_value;
38 /* This next line seems redundant but is needed for conversion quirk from LONG to VARCHAR2
39 */
40 strPartitionLessThanDate := lHighValue;
41 strPartitionLessThanDate := substr(strPartitionLessThanDate, 11, 10);
42 DBMS_OUTPUT.PUT_LINE(strPartitionLessThanDate ||'|'|| tab_part_rec.partition_name ||'|'|| tab_part_rec.partition_position ||'|'|| tab_part_rec.interval);
43 DBMS_OUTPUT.PUT_LINE(TO_DATE(strPartitionLessThanDate, 'YYYY-MM-DD') ||'******'||dtTestDate);
44 IF TO_DATE(strPartitionLessThanDate, 'YYYY-MM-DD') < dtTestDate AND tab_part_rec.partition_name <> 'PART_MINVALUE
' THEN
45 SQLstr := 'ALTER TABLE WSMUSER17.MO_USAGEDATA DROP PARTITION '||tab_part_rec.partition_name ||' update Global indexes';
46 DBMS_OUTPUT.PUT_LINE('Targeted Partition !!!!!!!!');
47 IF strRunType = 'LIVE_RUN' THEN
48 DBMS_OUTPUT.PUT_LINE('Dropping Partition !!!!!!!!');
49 execute immediate SQLstr;
50 END IF;
51 END IF;
52 END LOOP;
53 CLOSE tab_part_cur;
54 << EXIT >>
55 DBMS_OUTPUT.PUT_LINE('Partition purge complete');
56 END;
57 /
'DAY'
Interval type = 'DAY'
Test Date = 03-SEP-13
1
2012-06-1|PART_MINVALUE|1|NO
01-JUN-12******03-SEP-13
2
2013-08-0|SYS_P328538|2|YES
DECLARE
*
ERROR at line 1:
ORA-01847: day of month must be between 1 and last day of month
ORA-06512: at line 43
I'm trying to keep lat 7 partitions in the daily partitioned table and drop the rest of the partitions. But its not dropping them.
Ok, I created the table, inserted some data and ran some of your queries and you've got something wrong with your substring:
SQL> CREATE TABLE "MO_USAGEDATA" (
2 "REQUESTDTS" TIMESTAMP (9) NOT NULL ENABLE
3 )
4 partition by range ("REQUESTDTS") INTERVAL(NUMTODSINTERVAL(1,'DAY'))
5 (partition PART_MINVALUE values less than(TIMESTAMP '2012-06-18 00:00:00'));
Table created
SQL> INSERT INTO MO_USAGEDATA
2 (SELECT SYSDATE + ROWNUM FROM dual CONNECT BY LEVEL <= 30);
30 rows inserted
SQL> SELECT high_value, INTERVAL
2 FROM all_tab_partitions
3 WHERE table_name = 'MO_USAGEDATA'
4 AND table_owner = USER
5 ORDER BY PARTITION_POSITION;
HIGH_VALUE INTERVAL
------------------------------------ ---------
[...]
TIMESTAMP' 2013-09-30 00:00:00' YES
TIMESTAMP' 2013-10-01 00:00:00' YES
TIMESTAMP' 2013-10-02 00:00:00' YES
[...]
SQL> SELECT substr('TIMESTAMP'' 2013-10-02 00:00:00''', 11, 10) FROM dual;
SUBSTR('TIMESTAMP''2013-10-020
------------------------------
2013-10-0
As you can see you're off by one character. It works with DATE columns, but for TIMESTAMP partitionning, you'll need to adjust the offset.

Resources