postgresql partitioning master table duplicate entries - sql

I ve created a simple partitioning structure as given below:
Master table
CREATE TABLE parent_table
(
id_n numeric(19,0) NOT NULL,
name_v character varying(255),
location_n numeric(19,0),
CONSTRAINT parent_table_pkey PRIMARY KEY (id_n )
)
Child tables
CREATE TABLE child_table_location_1
(
-- Inherited from table parent_table: id_n numeric(19,0) NOT NULL,
-- Inherited from table parent_table: name_v character varying(255),
-- Inherited from table parent_table: location_n numeric(19,0),
CONSTRAINT child_table_location_1_pkey PRIMARY KEY (id_n ),
CONSTRAINT child_table_location_1_location_n_check CHECK (location_n = 1::numeric)
)INHERITS (parent_table)
CREATE TABLE child_table_location_2
(
-- Inherited from table parent_table: id_n numeric(19,0) NOT NULL,
-- Inherited from table parent_table: name_v character varying(255),
-- Inherited from table parent_table: location_n numeric(19,0),
CONSTRAINT child_table_location_2_pkey PRIMARY KEY (id_n ),
CONSTRAINT child_table_location_2_location_n_check CHECK (location_n = 2::numeric)
)INHERITS (parent_table)
Trigger
CREATE OR REPLACE FUNCTION PARTITION_INSERTION_TRIGGER()
RETURNS TRIGGER AS
$$
BEGIN
EXECUTE 'INSERT INTO '|| QUOTE_IDENT('child_table_location_'||NEW.LOCATION_N)||' SELECT ($1).*' USING NEW;
RETURN NEW;
END;
$$
LANGUAGE PLPGSQL;
CREATE TRIGGER INSERT_INTO_PARTITION_TRIGGER BEFORE INSERT ON PARENT_TABLE FOR EACH ROW EXECUTE PROCEDURE PARTITION_INSERTION_TRIGGER();
I create the trigger such that based on the location field, the data gets populated in respective child tables.
Now I ve the below insert scripts:
INSERT INTO parent_table(id_n, name_v, location_n) VALUES (1, 'aaa', 1);
INSERT INTO parent_table(id_n, name_v, location_n) VALUES (2, 'bbb', 2);
INSERT INTO parent_table(id_n, name_v, location_n) VALUES (3, 'ccc', 1);
INSERT INTO parent_table(id_n, name_v, location_n) VALUES (4, 'ddd', 2);
INSERT INTO parent_table(id_n, name_v, location_n) VALUES (5, 'eee', 1);
INSERT INTO parent_table(id_n, name_v, location_n) VALUES (6, 'fff', 2);
When I select from individual tables:
Child Table 1
id_n| name_v| location_n
1|"aaa"|1
3|"ccc"|1
5|"eee"|1
Child Table 2
id_n| name_v| location_n
2|"bbb"|2
4|"ddd"|2
6|"fff"|2
But when I query on the master table:
Parent table
id_n|name_v|location_n
1|"aaa"|1
1|"aaa"|1
2|"bbb"|2
2|"bbb"|2
3|"ccc"|1
3|"ccc"|1
4|"ddd"|2
4|"ddd"|2
5|"eee"|1
5|"eee"|1
6|"fff"|2
6|"fff"|2
I get duplicate entries from the parent_table even after having the primary key constraint on the id field.
Why it is happening and what changes should I make on my design.
Awaiting quick response.
Thanks in advance.

Returning NULL is not the clean way.
The elegant solution is to have the trigger "INSTEAD OF"
See: http://www.postgresql.org/docs/9.3/static/sql-createtrigger.html

Related

writing trigger containing multiple conditions

So I have a table trans which has two columns tx_type and ref_nbr
and I want to create a trigger such that the trigger ensures the following condition
in the trans table.
The following two conditions should be ensured:
if tx_type = D or W then ref_nbr should match the branch_nbr in branch table
if tx_type= B , P or R then ref_nbr should match mer_nbr in mer table
Triggers are not intended for keeping consistency in database relations. Use foreign keys for that. So make a table trans not with one column ref_nbr but use 2 columns - one for each relation (foreign key). Additionaly you can create check constraint for making sure that correct column is filled for given tx_type.
If you try to use triggers, you will have problems with concurrent transactions changing related tables like deleting your ref_nbr.
Example definitions for mer, branch and trans tables with some sample inserts:
create table branch(
branch_nbr number generated by default on null as identity start with 3 primary key,
branch_name varchar2(100) not null
);
create table mer (
mer_nbr number generated by default on null as identity start with 2 primary key,
mer_name varchar2(100) not null
);
create table trans (
id number generated by default on null as identity primary key,
tx_type varchar2(1) not null,
ref_branch_nbr number,
ref_mer_nbr number,
constraint ck_tx_type check (tx_type in ('D', 'W', 'B', 'P', 'R')),
constraint ck_correct_ref_for_tx_type
check (
(tx_type in ('D', 'W') and ref_branch_nbr is not NULL and ref_mer_nbr is NULL)
or (tx_type in ('B', 'P', 'R') and ref_branch_nbr is NULL and ref_mer_nbr is not NULL)
),
constraint fk_trans_ref_branch_nbr
foreign key (ref_branch_nbr)
references branch(branch_nbr),
constraint fk_trans_ref_mer_nbr
foreign key (ref_mer_nbr)
references mer(mer_nbr)
);
insert into branch(branch_nbr, branch_name) values(1, 'Master');
insert into branch(branch_nbr, branch_name) values(2, 'Test');
insert into mer(mer_nbr, mer_name) values(1, 'Test to Master');
commit;
-- working:
insert into trans(tx_type, ref_mer_nbr) values('P', 1);
insert into trans(tx_type, ref_branch_nbr) values('D', 1);
-- not working - non existing parent:
insert into trans(tx_type, ref_mer_nbr) values('P', 999);
insert into trans(tx_type, ref_branch_nbr) values('D', 999);
-- not working - wrong tx_type or wrong ref column:
insert into trans(tx_type, ref_mer_nbr) values('D', 1);
insert into trans(tx_type, ref_branch_nbr) values('P', 1);
insert into trans(tx_type, ref_branch_nbr, ref_mer_nbr ) values('P', 1, 1);
-- not working - cant insert without tx_type
insert into trans(ref_mer_nbr, ref_branch_nbr) values(1, 1);

Oracle if value to be inserted in foreign key is -1, insert null instead

I have a xml script I'm reading from to populate my database with data. One of the nodes in the xml file don't have a idDirector field (the nodes are movies) and so the xml reads a -1 as idDirector and then my stored procedure tries to insert -1 into the fk field and this makes my database returna constraint error : director -1 doesn't exist in Director table. How can I make it so it inserts null instead and make my fk field nullable?
CREATE TABLE Film (
PRIMARY KEY (idFilm),
FOREIGN KEY (idDirector) REFERENCES Director
);
Thank you
Looks like CASE to me, e.g.
insert into film (id_film, id_director)
select id_film,
case when id_director = -1 then null
else id_director
end
from ...
Will it work? Yes:
SQL> create table director (id number primary key);
Table created.
SQL> create table film (id number primary key, id_director number references director);
Table created.
SQL> insert into director values (100);
1 row created.
Inserting -1 fails:
SQL> insert into film (id, id_director) values (1, -1);
insert into film (id, id_director) values (1, -1)
*
ERROR at line 1:
ORA-02291: integrity constraint (SCOTT.SYS_C0065885) violated - parent key not
found
Inserting NULL works:
SQL> insert into film (id, id_director) values (1, null);
1 row created.
SQL>

Check if many-to-many relationship exists before insert or delete

I have 3 tables
For example:
Book
id
title
Tag
id
name
BookTag
book_id
tag_id
The goal to disallow having Book without Tag. i.e. when I try insert/delete data I need something to check on database level that Book has at least one Tag through many-to-many. If such validation fails it should throw constaint violation error or some sort of that. How should I implement that? Can it be reached by check constraint or should I create some trigger, if so then how?
please help me. thanks for your help in advance
You can enforce this at the pure database level by adding a foreign key in the book table that points back to a tag (any tag) in the book_tag table. As of now, your database model looks like:
create table book (
id int primary key not null,
title varchar(50)
);
create table tag (
id int primary key not null,
name varchar(50)
);
create table book_tag (
book_id int not null,
book_tag int not null,
primary key (book_id, book_tag)
);
Now, add the extra foreign key that points back to a tag:
alter table book add column a_tag int not null;
alter table book add constraint fk1 foreign key (id, a_tag)
references book_tag (book_id, tag_id) deferrable initially deferred;
Now when you insert a book, it can temporarily not have a tag, but only while the transaction hasn't finished yet. You need to insert a tag before committing. If you don't the constraint will fail, the transaction will rollback, and the insert won't happen.
Note: Please notice that this requires the use of deferrable constraints (look at deferrable initially deferred), something that is part of the SQL Standard but seldomly implemented. Fortunately, PostgreSQL does.
EDIT - Adding an example
Considering the previous modified tables you can try inserting a book without tags (will fail) and with tags (succeeding) as shown below:
insert into tag (id, name) values (10, 'classic');
insert into tag (id, name) values (12, 'action');
insert into tag (id, name) values (13, 'science fiction');
-- begin transaction
insert into book (id, title, a_tag) values (1, 'Moby Dick', 123);
commit; -- fails
-- begin transaction
insert into book (id, title, a_tag) values (2, 'Frankenstein', 456);
insert into book_tag (book_id, book_tag) values (2, 10);
insert into book_tag (book_id, book_tag) values (2, 13);
update book set a_tag = 10;
commit; -- succeeds

Why this sequence increments by 2?

I can't understand why this sequence is incremented by 2.
Is there any error in sequence to increment by 1? I need this to insert primary key value in table 'food'.
CREATE SEQUENCE food_id_ai START WITH 1 INCREMENT BY 1 CACHE 100;
create table food(
food_id integer,
f_name varchar(30) not null,
category varchar(30) not null,
price number(4),
amount number(4)
);
alter table food add constraint fpk primary key(food_id);
CREATE OR REPLACE TRIGGER insert_into_food
BEFORE INSERT ON food
FOR EACH ROW
BEGIN
:new.food_id:= food_id_ai.nextval;
END;
/
insert into food values(food_id_ai.nextval,'ruchi', 'chanachur' , 8, 50);
insert into food values(food_id_ai.nextval,'chips', 'chips' , 8, 50);
insert into food values(food_id_ai.nextval,'aeromatic', 'soap' , 8, 50);
insert into food values(food_id_ai.nextval,'handwash', 'toyletries', 8, 50);
insert into food values(food_id_ai.nextval,'tissue', 'toyletries' , 8, 50);
Because you're accessing the sequence both in your INSERT statement and in the trigger that is launched for each row, of course it's incremented by two.
Choose one.
I'd go for the trigger-based one, since you won't have to remember to specify the sequence in each insert statement you may execute.
In that case, you'll have to explicitly list the columns you are going to insert VALUES to:
INSERT INTO food (f_name, category, price, amount)
VALUES ('ruchi', 'chanachur' , 8, 50);
you have two options to correct this.
modify insert statement to be like this:
insert into food (f_name, category,price , amount)
values ('ruchi', 'chanachur' , 8, 50);
or modify you triggers as follow:
CREATE OR REPLACE TRIGGER insert_into_food
BEFORE INSERT ON food
FOR EACH ROW
BEGIN
if :new.food_id is null then
:new.food_id:= food_id_ai.nextval;
end if;
END;
/

PostgreSQL Addition in Primary Key in Create Table

i'm facing a problem with a primary key in PostgreSQL, my plan was to make an addition of two values and set this to one primary key, how could this be realized (first try below):
/* Tabelle fuer die Test*/
create table Test(
var_a integer,
var_b integer,
var_key integer,
var_key = var_a + var_b,
primarykey(var_key),
);
if i call this with a foreign key then it should be one value:
foreign key (var_key_f) references Test(var_key),
EDIT: I know th option of two multiple primary keys entries but i want to have only one primary key, so that i not have to reference over two vars again. I need to have both variables generated to one primary key.
It appears this can be accomplished without triggers: (pg-9.3):
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;
CREATE TABLE test
( var_key INTEGER NOT NULL PRIMARY KEY
, var_a INTEGER NOT NULL
, var_b INTEGER NOT NULL
, var_key_f INTEGER REFERENCES test(var_key)
, CONSTRAINT the_sum CHECK (var_a+var_b = var_key)
);
INSERT INTO test(var_key, var_a, var_b) VALUES(42, 21, 21); -- Ok
INSERT INTO test(var_key, var_a, var_b) VALUES(666, 660, 6); -- Ok
INSERT INTO test(var_key, var_a, var_b) VALUES(34, 21, 11); -- bad sum
INSERT INTO test(var_key, var_a, var_b) VALUES(666, 600, 66); -- duplicate sum
INSERT INTO test(var_key, var_a, var_b, var_key_f) VALUES(14, 6, 8, 42); -- Ok
INSERT INTO test(var_key, var_a, var_b, var_key_f) VALUES(13, 5, 8, 43); -- Bad FK
Result:
NOTICE: drop cascades to table tmp.test
DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 1
INSERT 0 1
ERROR: new row for relation "test" violates check constraint "the_sum"
DETAIL: Failing row contains (34, 21, 11, null).
ERROR: duplicate key value violates unique constraint "test_pkey"
DETAIL: Key (var_key)=(666) already exists.
INSERT 0 1
ERROR: insert or update on table "test" violates foreign key constraint "test_var_key_f_fkey"
DETAIL: Key (var_key_f)=(43) is not present in table "test".