Check if row already exists, if so tell the referenced table the id
Let's assume I have a table magazine:
CREATE TABLE magazin开发者_Python百科e
(
magazine_id integer NOT NULL DEFAULT nextval(('public.magazine_magazine_id_seq'::text)::regclass),
longname character varying(1000),
shortname character varying(200),
issn character varying(9),
CONSTRAINT pk_magazine PRIMARY KEY (magazine_id)
);
And another table issue:
CREATE TABLE issue
(
issue_id integer NOT NULL DEFAULT nextval(('public.issue_issue_id_seq'::text)::regclass),
number integer,
year integer,
volume integer,
fk_magazine_id integer,
CONSTRAINT pk_issue PRIMARY KEY (issue_id),
CONSTRAINT fk_magazine_id FOREIGN KEY (fk_magazine_id)
REFERENCES magazine (magazine_id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
);
Current INSERTS:
INSERT INTO magazine (longname,shotname,issn)
VALUES ('a long name','ee','1111-2222');
INSERT INTO issue (fk_magazine_id,number,year,volume)
VALUES (currval('magazine_magazine_id_seq'),'8','1982','6');
Now a row should only be inserted into 'magazine', if it does not already exist. However if it exists, the table 'issue' needs to get the 'magazine_id' of the row that already exists in order to establish the reference.
How can i do this?
Thx in advance!
How do you know if a magazine is already in magazine
table? Does issn
column define a magazine? If yes then it should be a primary key, or at least unique
.
The easiest way would be to do a check for magazine existence in your client application, like this (in pseudocode):
function insert_issue(longname, shotname, issn, number,year,volume) {
/* extensive comments for newbies */
start_transaction();
q_get_magazine_id = prepare_query(
'select magazine_id from magazine where issn=?'
);
magazine_id = execute_query(q_get_magazine_id, issn);
/* if magazine_id is null now then there’s no magazine with this issn */
/* and we have to add it */
if ( magazine_id == NULL ) {
q_insert_magazine = prepare_query(
'insert into magazine (longname, shotname, issn)
values (?,?,?) returning magazine_id'
);
magazine_id = execute_query(q_insert_magazine, longname, shortname, issn);
/* we have tried to add a new magazine; */
/* if we failed (magazine_id==NULL) then somebody else just added it */
if ( magazine_id == NULL ) {
/* other, parerelly connected client just inserted this magazine, */
/* this is unlikely but possible */
rollback();
start_transaction();
magazine_id = execute_query(q_get_magazine_id, issn);
}
}
/* now magazine_id is an id of magazine, */
/* added if it was not in a database before, new otherwise */
q_insert_issue = prepare_query(
'insert into issue (fk_magazine_id,number,year,volume)
values (?,?,?,?)'
);
execute_query(q_insert_issue, magazine_id, number, year, volume);
/* we have inserted a new issue referencing old, */
/* or if it was needed new, magazine */
if ( ! commit() ) {
rollback();
raise "Unable to insert an issue";
}
}
If you just have to do this in one query then you can implement this pseudocode as pl/pgsql function in database and just select insert_issue(?, ?, ?, ?, ?, ?)
.
If you are on PostgreSQL 9.1 or higher you can do something like:
WITH ref_key (id) AS (
WITH ins (id) AS (
INSERT INTO magazine (longname,shotname,issn)
VALUES ('a long name','ee','1111-2222')
RETURNING id
)
SELECT id
FROM magazine
LEFT JOIN ins USING id
WHERE issn = '1111-2222'
)
INSERT INTO INTO issue (fk_magazine_id,number,year,volume)
SELECT id,'8','1982','6'
FROM ref_key;
Writeable CTE's FTW!
I'm not sure that if you can do this with SQL. I know that Oracle can be used for triggers, but i don't think SQL is able to. Someone correct me if I'm wrong.
精彩评论