I am an Oracle Database Specialist in Singapore.
Please note that this site uses cookies.
09 April, 2012
05 April, 2012
Primary Key name appears to be different
Here is a quick post on a scenario where Oracle attempts to validate a Primary Key (index present) when creating a Materialized View and apparently reports a different name for the constraint !. The Primary Key and Indexis called "TARGET_TABLE" but the ORA-2437 error reports the error as being against "TARGET_TABLE1" -- with a "1" seemingly appended.
SQL> drop table target_table purge;
Table dropped.
SQL> create table target_table (column_1 number not null, column_2 varchar2(30), column_3 varchar2(300));
Table created.
SQL>
SQL> insert into target_table
2 select rownum, dbms_random.string('X',8),dbms_random.string('U',30)
3 from dual connect by level < 101;
100 rows created.
SQL> commit;
Commit complete.
SQL> select count(*) from target_table;
COUNT(*)
----------
100
SQL>
SQL> create index target_table on target_table(column_1);
Index created.
SQL> insert into target_table values (5,'ABC','XYZXZYZ');
1 row created.
SQL>
SQL> alter table target_table add constraint target_table primary key (column_1) enable novalidate ;
Table altered.
SQL>
SQL> select index_name from user_indexes where table_name = 'TARGET_TABLE';
INDEX_NAME
------------------------------
TARGET_TABLE
SQL>
SQL> select constraint_name, index_name
2 from user_constraints
3 where table_name = 'TARGET_TABLE'
4 and constraint_type in ('U','P');
CONSTRAINT_NAME INDEX_NAME
------------------------------ ------------------------------
TARGET_TABLE TARGET_TABLE
SQL>
SQL> create materialized view log on target_table;
Materialized view log created.
SQL>
SQL> create materialized view tt_mv
2 refresh fast on demand
3 as select column_1, column_2
4 from target_table
5 /
from target_table
*
ERROR at line 4:
ORA-02437: cannot validate (HEMANT.TARGET_TABLE1) - primary key violated
SQL>
SQL>
SQL> select count(*) from target_table where column_1 = 5;
COUNT(*)
----------
2
SQL>
.
.
.
01 April, 2012
TOO_MANY_ROWS and Variable Assignment
UPDATE : Also see Jeffrey Kemp's blog post on the same topic, earlier in 2008.
When you have a cursor that is assigning a return value to a variable, you expect the cursor to return a single row. If it returns more than one row, the resulting error is a TOO_MANY_ROWS error. This can be handled as an Exception.
However, this blog post is about what might be happening to the variable that you assign the fetched value to.
In this demo, I use a "CUSTOMER" table and a VALIDATE_CUSTOMER procedure :
When you have a cursor that is assigning a return value to a variable, you expect the cursor to return a single row. If it returns more than one row, the resulting error is a TOO_MANY_ROWS error. This can be handled as an Exception.
However, this blog post is about what might be happening to the variable that you assign the fetched value to.
In this demo, I use a "CUSTOMER" table and a VALIDATE_CUSTOMER procedure :
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
TNS for Linux: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production
SQL>
SQL> drop table CUSTOMER purge;
Table dropped.
SQL>
SQL> create table CUSTOMER
2 (cust_id number, sales_mgr_id number, cust_name varchar2(50), cust_start_date date, status_flag varchar2(1));
Table created.
SQL>
SQL> insert into CUSTOMER values (1,1,'USA-NY Customer',to_date('01-JAN-2010','DD-MON-YYYY'),'Y');
1 row created.
SQL> insert into CUSTOMER values (2,1,'USA-LA Customer',to_date('01-JUL-2010','DD-MON-YYYY'),'Y');
1 row created.
SQL> insert into CUSTOMER values (3,2,'GB-LN Customer',to_date('01-SEP-2010','DD-MON-YYYY'),'Y');
1 row created.
SQL> insert into CUSTOMER values (4,3,'FR-PR Customer',to_date('01-OCT-2010','DD-MON-YYYY'),'Y');
1 row created.
SQL> -- this cust_id 4 will be replacing the current one from 01-JAN-2013
SQL> -- unfortunately, the date entered is 01-JAN-2011
SQL> insert into CUSTOMER values (4,4,'JP-TY Customer',to_date('01-JAN-2011','DD-MON-YYYY'),'N');
1 row created.
SQL>
SQL> commit;
Commit complete.
SQL>
SQL>
SQL> create or replace procedure VALIDATE_CUSTOMER (in_cust_id in number, out_cust_status out varchar2)
2 as
3 -- initialize status
4 -- U for Unknown
5 l_cust_flag varchar2(1) := 'U';
6 begin
7 select status_flag into l_cust_flag
8 from CUSTOMER
9 where cust_id = in_cust_id
10 and cust_start_date <= SYSDATE;
11 out_cust_status := l_cust_flag;
12 dbms_output.put_line('Flag : ' || l_cust_flag);
13 dbms_output.put_line('Cust Status Returned : ' || out_cust_status);
14 exception
15 when others then
16 dbms_output.put_line('Flag : ' || l_cust_flag);
17 dbms_output.put_line('Exception !! Cust Status Returned : ' || out_cust_status);
18 end;
19 /
Procedure created.
SQL>
SQL> show errors
No errors.
SQL>
So, I have a table with 2 rows for CUST_ID=4. How will the procedure handle it ?I have deliberately added dbms_output.put_line to show the values that the procedure "sees".
I run with three test CUST_IDs : 1 (existant and valid), 9 (not existant), 4 ("too_many_rows").
SQL> SET SERVEROUTPUT ON SQL> SQL> -- declare a variable to get the return value in sqlplus SQL> SQL> -- a valid customer SQL> variable cust_status_1 varchar2(1); SQL> execute VALIDATE_CUSTOMER(1,:cust_status_1); Flag : Y Cust Status Returned : Y PL/SQL procedure successfully completed. SQL> print :cust_status_1 CUST_STATUS_1 -------------------------------- Y SQL> SQL> -- a non-existent customer SQL> variable cust_status_9 varchar2(1); SQL> execute VALIDATE_CUSTOMER(9,:cust_status_9); Flag : U Exception !! Cust Status Returned : PL/SQL procedure successfully completed. SQL> print :cust_status_9 CUST_STATUS_9 -------------------------------------------------------------------------------- SQL> SQL> -- a cust_id with too_many_rows SQL> variable cust_status_4 varchar2(1); SQL> execute VALIDATE_CUSTOMER(4,:cust_status_4); Flag : Y Exception !! Cust Status Returned : PL/SQL procedure successfully completed. SQL> print :cust_status_4 CUST_STATUS_4 -------------------------------------------------------------------------------- SQL>The "Flag" and returned (output out_cust_status) values are correct for CUST_IDs 1 and 9. (For 9, the Flag is the initialized value of "U" because the cursor did not overwrite it).
However, for CUST_ID 4, although the procedure raises an EXCEPTION and returns no value, the Flag that is present *did* get reset from the initialized value of "U" to "Y" !! Apparently, when a cursor returns a row, it does assign the return value to the designated variable. If the cursor then returns *another* row, it raises an Exception but does not clear the value that was already assigned from the first row.
.
.
.
Subscribe to:
Posts (Atom)