How-to suggestions to views

Поиск
Список
Период
Сортировка
От KÖPFERL Robert
Тема How-to suggestions to views
Дата
Msg-id ED4E30DD9C43D5118DFB00508BBBA76EB16759@neptun.sonorys.at
обсуждение исходный текст
Список pgsql-sql
Hi,

in the course of my investigation on how to agglomerate or concat several
tables using a view or functions the following little HOW-TO felt out. It is
kind of a full fledged example of how to coalesce two tables using a view.
However it is as it is and I am more less new to writing rules and thus
making faults. As the PG-doc says: There's a mega example but not some
simple so I had a try in making something simple. 
So short story long: I want sou to have a look at my SQL-style example and
either learn from it and/or give comments and suggestions (what didn't I
see, since I am beginner and what hidden issues exist, what did I interpret
wrong)



textfile
----------------8<--------------------------------
HOW-TO concatinate two tables in Postgres using a view and rules

This is a full-example of how to agglomerate two tables, connected via a 1:1
relation into one view on which DELETE, UPDATE and INSERT can be used.
So our goal is to have two tables like  id|a|b  and  id|x|y  coalesced into
one
table or view id|a|b|x|y which by itself allows INSERT, UPDATE and DELETE.


-- We start with creation of the tables
-- In order to connect them afterwards, we need a primary key and some
columns:

CREATE TABLE tbla
(id int4 NOT NULL,a int4,b varchar(12),CONSTRAINT tbla_pk PRIMARY KEY (id)
) 
WITHOUT OIDS;


-- One table is kind of master table, whilst the other(s) are/is
-- slave table. This just means that the master table defines what
-- (new) values are valid for the primary key and thus for the
-- foreign keys of the slave tables.
-- So a second table will at least have the same key as the master table.
-- On the one hand as foreign key to allow just values in tbla and to
-- retain referential integrity and on the other hand as primary key to
-- keep values unique and thus make a 1:n relation become a 1:1 relation:

CREATE TABLE tblb
(id int4 NOT NULL,x bool,y timestamp,CONSTRAINT tblb_pk PRIMARY KEY (id),CONSTRAINT tblb_fk FOREIGN KEY (id) REFERENCES
tbla(id) ON UPDATE CASCADE
 
ON DELETE CASCADE
) 
WITHOUT OIDS;

-- Note that we specified ON DELETE CASCADE. This will get us handy, later

-- Now let's already test our new tables plus their constraints by inserting
some records:

INSERT INTO  tbla VALUES ( 3, 9034, 'F dabiu' );
INSERT INTO  tbla VALUES ( 6, -23, 'Moosi llap' );

-- we have to use same keys and qty 0..1
INSERT INTO  tblb VALUES ( 3, false,  now() );
INSERT INTO  tblb VALUES ( 6, true, now() );


-- Now we can create such a agglomerating view. However it will just allow
-- data to be viewed - maybe thus the name. 

CREATE OR REPLACE VIEW a_and_b AS SELECT tbla.id, tbla.a, tbla.b, tblb.x, tblb.y  FROM tbla
NATURAL LEFT OUTER JOIN tblb;

-- This creates a new 'table' (internally Postgres views are tables with no
data
-- but a bunch of rules) with all the columns we expected earlier.
-- Note that since we used the name id in both tables, we could use a
NATURAL
-- JOIN. Depending on your column names and intentions, other joins are
required.
-- As you can see, this resembles just the concatenated table we had in
mind:

SELECT * FROM a_and_b;


-- In order to make INSERT, UPDATE and DELETE work o the view, the next step
-- is to define some rules. Note that there already exists one rule: The 
-- 'standard-rule' named _RETURN. This makes a table to a view in Postgres.
-- Since the SELECT is covered by a rule, no actual data is required.
-- Let's start with a rule for inserting records:

CREATE OR REPLACE RULE a_b_insert AS   ON INSERT TO a_and_b DO INSTEAD (    INSERT INTO tbla (id, a, b) VALUES (new.id,
new.a,new.b);   INSERT INTO tblb (id, x, y) VALUES (new.id, new.x, new.y);
 
);

-- What we do here is: Instead of issuing the users insert, we issue two of
-- our own inserts. Thereby reusing values we got from the users insert. 
-- This is the pseudo relation NEW. NEW has the same structure as the view
-- the rule is written for. The two INSERTs (or whatever other
SQL-statements)
-- are coalesced by putting them into parentheses. Note that coming from our

-- definition, we have to fill tbla before tblb.


-- So it's now possible to insert records via tha view:

INSERT INTO a_and_b VALUES (99, 123, 'text', false, now() );
SELECT * FROM a_and_b WHERE id=99;

-- In order to be able to also delete records, a delete-rule is needed
-- This is also a INSTEAD-rule, since it is intended to be a rather 
-- generic rule (any DELETE-WHERE-clause shall be possible), there are
-- no restricting expressions and it is a INSTEAD but not a ALSO-rule.
-- So in this case we want to delete records from just tbla. Since we
enabled
-- DELETE CASCADE Postgres will clean all dependent records in tblb as well.
-- One could think that the WHERE clause of the view's DELETE will be
applied
-- to this rule as well, but that's not true. a 'DELETE FROM tbla' ends up
-- in purging all records. So to restrict the rule's DELETE we can make use
-- of the pseudo relation OLD. This relation has the same form as the view 
-- and delivers us the terms given in a WHERE-clause. That leads us to:

CREATE OR REPLACE RULE a_and_b_del AS   ON DELETE TO a_and_b DO INSTEAD      DELETE FROM tbla WHERE tbla.id = OLD.id;

-- which now allows us to safely delete selected records:

DELETE FROM a_and_b WHERE id=99;
SELECT * FROM a_and_b WHERE id=99;


-- Last but not least there's still the UPDATE to the view. A rule is
required,
-- too. It works almost the same pattern as before. Since a update is like a
-- combination of DELETE and INSERT, there exist two pseudo relations: OLD
and NEW.
-- One can refer to the unchanged record, to terms of the current statement
and
-- to the user's new values (he wants to set). In our case, we do only need
the
-- NEW-relation. As at the INSERT rule before, we coalesce several
SQL-statements
-- by using parentheses. This is again a 'default' and INSTEAD-rule. Instead
-- of the big update, we do two updates on each table. Thereby restricting
-- updates again of using just the primary key:

CREATE OR REPLACE RULE a_and_b_upd AS   ON UPDATE TO a_and_b DO INSTEAD    (       UPDATE tbla SET a = new.a, b = new.b
WHERE tbla.id = new.id;      UPDATE tblb SET x = new.x, y = new.y  WHERE tblb.id = new.id;   );
 




UPDATE a_and_b SET a=155, b='t1e5xt', x=false, y='2005-6-6' WHERE id=1;
SELECT * FROM a_and_b;

-- Note that this may fail if not all slave records exist. If for example
-- there exists just a master record for id=1
INSERT INTO  tbla VALUES ( 1, -12399, 'solo master' );
-- a UPDATE on the view will update or try to update both tables, it will
-- have success however in jus one table and thus the second half columns
-- do not get set:

UPDATE a_and_b SET a=-333, b='neotext', x=false, y='2005-6-6' WHERE id=1;
SELECT * FROM a_and_b;

--  The values for x and y are lost.

SELECT * FROM a_and_b;

-- Maybe in this case it is more recommendable to define the view not as
-- with LEFT OUTER JOIN but with a normal equal join. This is up to you.      


В списке pgsql-sql по дате отправления:

Предыдущее
От: "Dinesh Pandey"
Дата:
Сообщение: Re: [GENERAL] Permission denied for language pltclu
Следующее
От: Richard Huxton
Дата:
Сообщение: Re: [GENERAL] Permission denied for language pltclu