Dear Ask Tom-Team!
you guys helped me a lot solving my previous problems with sql.
Now I have a new problem I can't find a solution by myself.
In my data base I have the following situation:
I have a firm that has one or more contact persons. For each contact person it is stored in which matter it should be contacted (attribute 'type'), e.g. for shipping, for special questions, for marketing, .... Each year we receive information on the current contact persons. These persons can be the same as in the year before or it can be one or more different persons. The information in the data base should be updated if it is a new person for a specific type, e.g. the act_dat should be set for the current entry and a new entry should be created. If the contact person e.g. for marketing stays the same, there should be no changes in the data base.
Further constraints are:
a) For shipping only one current contact person is allowed whereas for all other issues/types there could be more than one current contact person
b) Person ‚A‘ can be the contact person for shipping in year 2012 while in 2013 it is person ‚B‘. In 2014 it could be again person ‚A‘
My table contact looks like this:
CREATE TABLE contact (
id NUMBER
CONSTRAINT nnc_con_id NOT NULL,
firm_id NUMBER
CONSTRAINT nnc_con_firm_id NOT NULL,
surname VARCHAR2(150),
lastname VARCHAR2(150),
division VARCHAR2(150),
phone VARCHAR2(35),
email VARCHAR2(150),
type VARCHAR2(150)
CONSTRAINT nnc_con_type NOT NULL,
creat_id NUMBER
CONSTRAINT nnc_con_creat_id NOT NULL,
creat_dat TIMESTAMP WITH LOCAL TIME ZONE DEFAULT systimestamp
CONSTRAINT nnc_con_creat_dat NOT NULL,
act_id NUMBER DEFAULT NULL,
act_dat TIMESTAMP WITH LOCAL TIME ZONE DEFAULT NULL
);
CREATE UNIQUE INDEX pk_con_ix ON
contact (
id
ASC );
CREATE UNIQUE INDEX con_ix_ship ON
contact ( decode(
type, 'Shipping',
firm_id, NULL),
decode(
type, 'Shipping', EXTRACT(YEAR FROM
creat_dat), NULL),
decode(
type, 'Shipping',
act_dat, null));
ALTER TABLE contact ADD CONSTRAINT pk_con PRIMARY KEY ( id );
CREATE SEQUENCE con_id_seq START WITH 1 NOCACHE ORDER;
CREATE OR REPLACE TRIGGER con_id_trg BEFORE
INSERT ON contact
FOR EACH ROW
WHEN ( new.id IS NULL )
BEGIN
:new.id := con_id_seq.nextval;
END;
/
I tried to model this with a procedure but did not succeed so far. Here is my best try:
create or replace PROCEDURE INSERT_CONTACT
(
IN_FIRM_ID IN contact.firm_id%TYPE
, IN_SURNAME IN contact.surname%TYPE
, IN_LASTNAME IN contact.lastname%TYPE
, IN_DIVISION IN contact.division%TYPE
, IN_PHONE IN contact.phone%TYPE
, IN_EMAIL IN contact.email%TYPE
, IN_TYPE IN contact.type%TYPE
, IN_CREAT_ID IN contact.creat_id%TYPE
, IN_CREAT_DAT IN contact.creat_dat%TYPE DEFAULT SYSTIMESTAMP
, IN_ACT_ID IN contact.act_id%TYPE DEFAULT NULL
, IN_ACT_DAT IN contact.act_dat%TYPE DEFAULT NULL
) AS
BEGIN
UPDATE contact
SET act_id = in_creat_id, act_dat = in_creat_dat
WHERE firm_id = IN_FIRM_ID
AND act_dat IS NULL
AND IN_type = 'Shipping'
AND type = 'Shipping'
AND ( type <> in_type
OR surname <> in_surname
OR lastname <> in_lastname
OR division <> in_division
OR phone <> in_phone
OR email <> in_email);
INSERT INTO contact
(firm_id, surname, lastname, division, phone, email, type, creat_id, creat_dat)
VALUES(in_firm_id, in_surname,in_lastname,in_division,in_phone,in_email,in_type,in_creat_id, in_creat_dat);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
dbms_output.put_line('<<<No Insert: '||sqlerrm);
END INSERT_CONTACT;
So
EXECUTE insert_contact(12,'Maria','Mouse',null,null,null,'Shipping',1,to_date('10.01.2013','DD.MM.YYYY'));
should insert the data.
EXECUTE insert_contact(12,'Maria','Mouse',null,null,null,'Shipping',1,to_date('10.01.2013','DD.MM.YYYY'));
should change nothing.
EXECUTE insert_contact(12,'Tom','Cat',null,null,null,'Shipping',1,to_date('11.01.2013','DD.MM.YYYY'));
should update the current entry (setting the act_dat) and insert a new entry (since there is only one current shipping person allowed).
EXECUTE insert_contact(12,'Maria','Mouse',null,null,null,'Shipping',1,to_date('10.01.2014','DD.MM.YYYY'));
should update the current entry (setting the act_dat) and insert a new entry.
EXECUTE insert_contact(12,'Tom','Cat',null,null,null,'Marketing',1,to_date('10.01.2013','DD.MM.YYYY'));
should insert a new entry.
EXECUTE insert_contact(12,'Maria','Mouse',null,null,null,'Marketing',1,to_date('10.01.2013','DD.MM.YYYY'));
should insert a new entry (no update, since there is more than one marketing current person allowed).
EXECUTE insert_contact(12,'Tina','Bird',null,null,null,'Marketing',1,to_date('11.01.2014','DD.MM.YYYY'));
should update the current two entries (setting the act_dat) and insert a new entry (since there is a new marketing person).
Regarding the error handling I plan to store it in a table and not just using dbms_output.
I really appreciate if you guys can give me a hint how to solve my problem.
Thanks a lot
Barbara
Your update statement *always* has:
AND IN_type = 'Shipping'
AND type = 'Shipping'
So it is never going to do anything with when you pass "Marketing". Isn't that the core issue here ?
Also, note the change I've made to the WHERE clause to handle null , because "a <> b" does not work with nulls
SQL>
SQL> CREATE TABLE contact (
2 id NUMBER
3 CONSTRAINT nnc_con_id NOT NULL,
4 firm_id NUMBER
5 CONSTRAINT nnc_con_firm_id NOT NULL,
6 surname VARCHAR2(150),
7 lastname VARCHAR2(150),
8 division VARCHAR2(150),
9 phone VARCHAR2(35),
10 email VARCHAR2(150),
11 type VARCHAR2(150)
12 CONSTRAINT nnc_con_type NOT NULL,
13 creat_id NUMBER
14 CONSTRAINT nnc_con_creat_id NOT NULL,
15 creat_dat TIMESTAMP WITH LOCAL TIME ZONE DEFAULT systimestamp
16 CONSTRAINT nnc_con_creat_dat NOT NULL,
17 act_id NUMBER DEFAULT NULL,
18 act_dat TIMESTAMP WITH LOCAL TIME ZONE DEFAULT NULL
19 );
Table created.
SQL>
SQL> CREATE UNIQUE INDEX pk_con_ix ON
2 contact (
3 id
4 ASC );
Index created.
SQL>
SQL> CREATE UNIQUE INDEX con_ix_ship ON
2 contact ( decode(
3 type, 'Shipping',
4 firm_id, NULL),
5 decode(
6 type, 'Shipping', EXTRACT(YEAR FROM
7 creat_dat), NULL),
8 decode(
9 type, 'Shipping',
10 act_dat, null));
Index created.
SQL>
SQL>
SQL> ALTER TABLE contact ADD CONSTRAINT pk_con PRIMARY KEY ( id );
Table altered.
SQL>
SQL> CREATE SEQUENCE con_id_seq START WITH 1 NOCACHE ORDER;
Sequence created.
SQL>
SQL> CREATE OR REPLACE TRIGGER con_id_trg BEFORE
2 INSERT ON contact
3 FOR EACH ROW
4 WHEN ( new.id IS NULL )
5 BEGIN
6 :new.id := con_id_seq.nextval;
7 END;
8 /
Trigger created.
SQL>
SQL>
SQL> create or replace PROCEDURE INSERT_CONTACT
2 (
3 IN_FIRM_ID IN contact.firm_id%TYPE
4 , IN_SURNAME IN contact.surname%TYPE
5 , IN_LASTNAME IN contact.lastname%TYPE
6 , IN_DIVISION IN contact.division%TYPE
7 , IN_PHONE IN contact.phone%TYPE
8 , IN_EMAIL IN contact.email%TYPE
9 , IN_TYPE IN contact.type%TYPE
10 , IN_CREAT_ID IN contact.creat_id%TYPE
11 , IN_CREAT_DAT IN contact.creat_dat%TYPE DEFAULT SYSTIMESTAMP
12 , IN_ACT_ID IN contact.act_id%TYPE DEFAULT NULL
13 , IN_ACT_DAT IN contact.act_dat%TYPE DEFAULT NULL
14 ) AS
15 BEGIN
16 UPDATE contact
17 SET act_id = in_creat_id, act_dat = in_creat_dat
18 WHERE firm_id = IN_FIRM_ID
19 AND act_dat IS NULL
20 AND IN_type = 'Shipping'
21 AND type = 'Shipping'
22 AND ( decode(type,in_type,0,1) = 1
23 OR decode(surname,in_surname,0,1) = 1
24 OR decode(lastname,in_lastname,0,1) = 1
25 OR decode(division,in_division,0,1) = 1
26 OR decode(phone,in_phone,0,1) = 1
27 OR decode(email,in_email,0,1) = 1
28 );
29 dbms_output.put_line('updated: '||sql%rowcount);
30 INSERT INTO contact
31 (firm_id, surname, lastname, division, phone, email, type, creat_id, creat_dat)
32 VALUES(in_firm_id, in_surname,in_lastname,in_division,in_phone,in_email,in_type,in_creat_id, in_creat_dat);
33 dbms_output.put_line('inserted 1');
34 EXCEPTION
35 WHEN DUP_VAL_ON_INDEX THEN
36 dbms_output.put_line('insert not done');
37 END INSERT_CONTACT;
38 /
Procedure created.
SQL> set serverout on
SQL>
SQL> --should insert the data.
SQL> EXECUTE insert_contact(12,'Maria','Mouse',null,null,null,'Shipping',1,to_date('10.01.2013','DD.MM.YYYY'));
updated: 0
inserted 1
PL/SQL procedure successfully completed.
SQL>
SQL> --should change nothing.
SQL> EXECUTE insert_contact(12,'Maria','Mouse',null,null,null,'Shipping',1,to_date('10.01.2013','DD.MM.YYYY'));
updated: 0
insert not done
PL/SQL procedure successfully completed.
SQL>
SQL> --should update the current entry (setting the act_dat) and insert a new entry (since there is only one current shipping person allowed).
SQL> EXECUTE insert_contact(12,'Tom','Cat',null,null,null,'Shipping',1,to_date('11.01.2013','DD.MM.YYYY'));
updated: 1
inserted 1
PL/SQL procedure successfully completed.
SQL>
SQL> --should update the current entry (setting the act_dat) and insert a new entry.
SQL> EXECUTE insert_contact(12,'Maria','Mouse',null,null,null,'Shipping',1,to_date('10.01.2014','DD.MM.YYYY'));
updated: 1
inserted 1
PL/SQL procedure successfully completed.
SQL>
SQL> --should insert a new entry.
SQL> EXECUTE insert_contact(12,'Tom','Cat',null,null,null,'Marketing',1,to_date('10.01.2013','DD.MM.YYYY'));
updated: 0
inserted 1
PL/SQL procedure successfully completed.
SQL>
SQL> --should insert a new entry (no update, since there is more than one marketing current person allowed).
SQL> EXECUTE insert_contact(12,'Maria','Mouse',null,null,null,'Marketing',1,to_date('10.01.2013','DD.MM.YYYY'));
updated: 0
inserted 1
PL/SQL procedure successfully completed.
SQL>
SQL> select * from contact
2 @pr
==============================
ID : 1
FIRM_ID : 12
SURNAME : Maria
LASTNAME : Mouse
DIVISION :
PHONE :
EMAIL :
TYPE : Shipping
CREAT_ID : 1
CREAT_DAT : 10-JAN-13 12.00.00.000000 AM
ACT_ID : 1
ACT_DAT : 11-JAN-13 12.00.00.000000 AM
==============================
ID : 3
FIRM_ID : 12
SURNAME : Tom
LASTNAME : Cat
DIVISION :
PHONE :
EMAIL :
TYPE : Shipping
CREAT_ID : 1
CREAT_DAT : 11-JAN-13 12.00.00.000000 AM
ACT_ID : 1
ACT_DAT : 10-JAN-14 12.00.00.000000 AM
==============================
ID : 4
FIRM_ID : 12
SURNAME : Maria
LASTNAME : Mouse
DIVISION :
PHONE :
EMAIL :
TYPE : Shipping
CREAT_ID : 1
CREAT_DAT : 10-JAN-14 12.00.00.000000 AM
ACT_ID :
ACT_DAT :
==============================
ID : 5
FIRM_ID : 12
SURNAME : Tom
LASTNAME : Cat
DIVISION :
PHONE :
EMAIL :
TYPE : Marketing
CREAT_ID : 1
CREAT_DAT : 10-JAN-13 12.00.00.000000 AM
ACT_ID :
ACT_DAT :
==============================
ID : 6
FIRM_ID : 12
SURNAME : Maria
LASTNAME : Mouse
DIVISION :
PHONE :
EMAIL :
TYPE : Marketing
CREAT_ID : 1
CREAT_DAT : 10-JAN-13 12.00.00.000000 AM
ACT_ID :
ACT_DAT :
PL/SQL procedure successfully completed.
SQL>
SQL> --should update the current two entries (setting the act_dat) and insert a new entry (since there is a new marketing person)
SQL> EXECUTE insert_contact(12,'Tina','Bird',null,null,null,'Marketing',1,to_date('11.01.2014','DD.MM.YYYY'));
updated: 0
inserted 1
PL/SQL procedure successfully completed.
SQL>
SQL>