Given the following tables:
CREATE TABLE videos (
video_id UUID,
added_date TIMESTAMP,
description TEXT,
title TEXT,
user_id UUID,
PRIMARY KEY (video_id)
);
CREATE TABLE videos_by_title_year (
title TEXT,
added_year INT,
added_date TIMESTAMP,
description TEXT,
user_id UUID,
video_id UUID,
PRIMARY KEY ((title, added_year))
);
When a new video is created it has to be added to these two tables. The video_idneeds to be the same in both. On the application side you would solve this programmatically.
I'm writing some cql dml scripts for test environment setup data. So basically a long list of INSERT statements.
INSERT (video_id, ... , user_id) INTO videos VALUES (uuid(), ...);
INSERT (title, ... , video_id) INTO videos_by_title_year VALUES ('Forrest Gump', ... , uuid());
In this case the video_id's will be different. Can I in someway reuse a generated UUID in cql scripts? Or is the only possible solution to set the id's by hand in my script like below?
INSERT (video_id, ... , user_id) INTO videos VALUES (7bd6e4ae-0ef2-11e5-9de3-8438355b7e3a, ...);
INSERT (title, ... , video_id) INTO videos_by_title_year VALUES ('Forrest Gump', ... , 7bd6e4ae-0ef2-11e5-9de3-8438355b7e3a);
As far as I know now this is not possible.
Related
So I've been going through SQL migrations to insert data in a SEQUENTIAL manner specifically from parent to child.
I've inserted data in the parent table. Now I've to store the primary key value of that
specific row (WHERE condition is defined in query for reference " where description = '1234'") in a variable.
And while inserting data to the child table I've to use that primary key value stored in a variable in place of a foreign key column("country_code_id") of the child table.
I'm using Postgresql
CREATE TABLE Countries
(
id SERIAL,
description VARCHAR(100),
CONSTRAINT coutry_pkey PRIMARY KEY (id)
);
CREATE TABLE Cities
(
country_code_id int ,
city_id int,
description VARCHAR(100),
CONSTRAINT cities_pkey PRIMARY KEY (city_id),
CONSTRAINT fk_cities_countries FOREIGN KEY (country_code_id) REFERENCES Countries (id)
);
INSERT INTO COUNTRIES (description) VALUES('asdf');
#countrid = SELECT id FROM COUNTRIES WHERE description = 'asdf';
INSERT INTO cities VALUES (countrid, 1 , 'abc');
SQL does not have variables. The normal way to do this is to use INSERT ... RETURNING:
INSERT INTO countries (description) VALUES ('1234')
RETURNING id;
This will return the automatically generated primary key. You store that in a variable on the client side and run a second statement:
INSERT INTO cities (country_code_id, city_id, description)
VALUES (4711, 1, 'abc');
where 4711 is the value returned from the first statement. To avoid hard-coding the value, you can use a prepared statement, which also will boost performance.
An alternative, more complicated, solution is to run both statements in a single statement using a common table expression:
WITH country_ids AS (
INSERT INTO countries (description) VALUES ('1234')
RETURNING id
INSERT INTO (country_code_id, city_id, description)
SELECT id, 1, 'abc'
FROM country_ids;
We are dealing with legacy code that doesn't auto-increment the primary key (see serial) so I have to manually do it. What is the correct way to manually update the primary key field on insert. I am getting an error when I do the below
Table:
CREATE TABLE pizza (
id bigint not null,
price int
)
Insert statement:
INSERT INTO pizza
(id, price)
VALUES
(
(SELECT max(id) from pizza)+1,
1.75
)
Don't use max()+1 to generate a primary key. It's not safe for concurrent inserts and it doesn't really scale well.
Just create a sequence and use that:
create sequence pizza_id_seq;
Then synchronize it with the current values in the table:
select setval('pizza_id_seq', coalesce(max(id),1))
from pizza;
Then, instead of changing your INSERT statements to use the dreaded max() + 1, just use the sequence:
INSERT INTO pizza
(id, price)
VALUES
(nextval('pizza_id_seq'), 1.75)
I am creating a sql file which has uuids as primary key. Here is how my create table definition looks like using pgcrypto extension
CREATE EXTENSION pgcrypto;
CREATE TABLE snw.contacts(
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT,
email TEXT
);
Now I add a record in this table using
INSERT INTO snw.contacts (name,email) VALUES('Dr Nic Williams','drnic');
postgres=# select * from snw.contacts;
id | name | email
--------------------------------------+-----------------+-------
7c627ee0-ac94-40ee-b39d-071299a55c13 | Dr Nic Williams | drnic
Now going ahead in the same file I want to insert a row in one of tables which looks like
CREATE TABLE snw.address(
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
street TEXT
contact UUID
);
where contact UUID refers to ID in snw.contacts table. How can I fetch the uuid which was generated in the first insert and use it in another insert in the snw.address table?Something like:
INSERT INTO snw.address(street,contact) values('ABC', (select id from snw.contacts where email='drnic'));
I can use where clause I am using this script for generating some test data and so I know what the email would be for fetching the id.
Use a data modifying CTE:
with new_contact as (
INSERT INTO snw.contacts (name,email)
VALUES('Dr Nic Williams','drnic')
returning id
)
INSERT INTO snw.address(street,contact)
select 'ABC', id
from new_contact;
I have a table that contains common subjects text, that requires insertion of some string at run time. For example below:
CREATE TABLE certification.cert_email_dtls (
cert_eid_id numeric(10,0),
cert_eid_email_body character varying(8000),
);
insert into certification.cert_email_dtls(1,'hello world <blank-value1>);
insert into certification.cert_email_dtls(2,'hello guys <blank-other-value2>);
insert into certification.cert_email_dtls(3,'hello <blank-value3> india <some-other-value4>);
and so on. <some-value>,<some-other-value> etc come at run time.
SELECT cert_eid_id ,
cert_eid_email_body,
INTO v_id,
v_email_body_end
FROM certification.cert_email_dtls where cert_eid_id = in_id;
My requirement is to insert that some-values that are coming in between and generate the final email body.
format() might be the perfect tool for this. Read details in the manual.
If you can save cert_eid_email_body in a compatible format, like:
CREATE TABLE cert_email_dtls (
cert_eid_id serial PRIMARY KEY
, cert_eid_email_body text
);
INSERT INTO cert_email_dtls (cert_eid_email_body)
VALUES ('hello %1$s india %2$s');
The whole operation can be as simple as:
SELECT format(cert_eid_email_body, 'foo', 'bar', 'baz') AS cert_eid_email_body
FROM cert_email_dtls
WHERE cert_eid_id = 1;
Result:
cert_eid_email_body
-------------------
hello foo india bar
Note that the 3rd parameter 'baz' is silently ignored, since it is not referenced in the string.
SQL Fiddle.
Aside: Don't use numeric(10,0) for an ID or primary key. integer or bigint typically serve you better. Using serial PRIMARY KEY above as it probably should be.
Hi people i need some help deciding on the best way to do an insert into table ‘shop’ which has a serial id field. I also need to insert into tables ‘shopbranch’ and ‘shopproperties’ which both references shop.id.
In a nutshell I need to insert one shop record. Then two records for each table of the following tables, shopproperty and shopbranch, whose shopid (FK) references the just created shop.id field
I saw somewhere that i could wrap the ‘shop’ insert, inside a function called lets say ‘insert_shop’ which does the 'shop' insert and returns its id using a select statement
Then inside another function which inserts shoproperty and shopbranch records i could do one call to insert_shop function to return the shop id which can be used to be passed in as the shop id for the records.
Can you let me know if I’m looking at this in the correct way as I’m a newbie.
One way to approach this is to create a view on your three tables that shows all columns from all three tables that can be inserted or updated. If you then create an INSTEAD OF INSERT trigger on the view then you can manipulate the view contents as if it were a table. You can do the same with UPDATE and even combine the two into an INSTEAD OF INSERT OR UPDATE trigger. The function that your trigger calls then has three INSERT statements that redirect the insert on the view to the underlying tables:
CREATE TABLE shop (
id serial PRIMARY KEY,
nm text,
...
);
CREATE TABLE shopbranch (
id serial PRIMARY KEY,
shop integer NOT NULL REFERENCES shop,
branchcode text,
loc text,
...
);
CREATE TABLE shopproperties (
id serial PRIMARY KEY,
shop integer NOT NULL REFERENCES shop,
prop1 text,
prop2 text,
...
);
CREATE VIEW shopdetails AS
SELECT s.*, b.*, p.*
FROM shop s, shopbranch b, shopproperties p,
WHERE b.shop = s.id AND p.shop = s.id;
CREATE FUNCTION shopdetails_insert() RETURNS trigger AS $$
DECLARE
shopid integer;
BEGIN
INSERT INTO shop (nm, ...) VALUES (NEW.nm, ...) RETURNING id INTO shopid;
IF NOT FOUND
RETURN NULL;
END;
INSERT INTO shopbranch (shop, branchcode, loc, ...) VALUES (shopid, NEW.branchcode, NEW.loc, ...);
INSERT INTO shopproperties(shop, prop1, prop2, ...) VALUES (shopid, NEW.prop1, NEW.prop2, ...);
RETURN NEW;
END; $$ LANGUAGE plpgsql;
CREATE TRIGGER shopdetails_trigger_insert
INSTEAD OF INSERT
FOR EACH ROW EXECUTE PROCEDURE shopdetails_insert();
You could of course play with the view and show only those columns from the three tables that can be inserted or updated (such as excluding primary and foreign keys).