Generating sql file with uuids and referring those ids further postgres9.5 - sql

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;

Related

Populate virtual SQLite FTS5 (full text search) table from content table

I've followed https://kimsereylam.com/sqlite/2020/03/06/full-text-search-with-sqlite.html to set up SQLite's virtual table extension FTS5 for full text search on an external content table.
While the blog shows how to set up triggers to keep the virtual FTS table updated with the data:
CREATE TABLE user (
id INTEGER PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
email TEXT NOT NULL UNIQUE,
short_description TEXT
)
CREATE VIRTUAL TABLE user_fts USING fts5(
username,
short_description,
email UNINDEXED,
content='user',
content_rowid='id'
)
CREATE TRIGGER user_ai AFTER INSERT ON user
BEGIN
INSERT INTO user_fts (rowid, username, short_description)
VALUES (new.id, new.username, new.short_description);
END;
...
I am failing to populate the FTS table from all previous data in an analogous fashion.
I'll stick to the example from the blog:
INSERT INTO user_fts (rowid, username, short_description) SELECT (id, username, short_description) FROM user;
However, sqlite (3.37.2) fails with row value misused.
Please explain how id, content_rowid, rowid and new.id are related and how to modify the query to update the FTS table properly.
INSERT INTO user_fts (rowid, username, short_description) SELECT id, username, short_description FROM user;
(no parentheses) works.
rowid is a unique 64 bit unsigned integer row id.
If the table contains an integer primary key (as id in user), they are the same (alias). I.e. user.rowid == user.id = user_fts.rowid.
Doc: https://www.sqlite.org/lang_createtable.html#rowid
The new refers to the element being inserted.
Doc: https://www.sqlite.org/lang_createtrigger.html
content_rowid links the virtual FTS table to the external data table row id column (it defaults to rowid).
Doc: https://www.sqlite.org/fts5.html#external_content_tables

postgresql how to update another table while on conflict

I have two tables
CREATE TABLE people (
name VARCHAR(100) NOT NULL,
company_id int8 NOT NULL,
);
CREATE TABLE company (
id int8 NOT NULL,
);
I want to copy data from csv to DB. This is my script
BEGIN
CREATE TEMP TABLE tmp_company
ON COMMIT DROP AS SELECT * FROM company WITH NO DATA;
\COPY tmp_company FROM 'company.csv' WITH CSV HEADER
DELIMITER as ',';
INSERT INTO company
SELECT * FROM tmp_company
ON CONFLICT DO NOTHING;
CREATE TEMP TABLE tmp_people
ON COMMIT DROP AS SELECT * FROM people WITH NO DATA;
\COPY tmp_people FROM 'people.csv' WITH CSV HEADER
DELIMITER as ',';
INSERT INTO people
SELECT * FROM tmp_people
ON CONFLICT DO NOTHING;
COMMIT;
If existing company id is found in company table,
I should do company.id+=1 and replace the new company_id for the related people records.
Example:
company.csv
id
1
5
people.csv
name,company_id
tom,1
paul,5
existing company table data
id
1
2
existing people table data
name,company_id
tom,1
paul,2
After copying data from csv to DB, the data should look like
company table data
id
1
2
3 <-- from csv data, as 1,2 are used, set id=3
5
people table data
name,company_id
tom,1
paul,2
tom,3 <-- from csv data
paul,5 <-- from csv data
How can i do this? I am wondering if I can add the logic after ON CONFLICT...
Edit 1:
The two tables' size are near 5TBs.
and two csv contains 5M records.
First, you should use the bigserial data type instead of int8 for the column id of the table company so that to automatically increase the id when inserting a new row.
Then, you should create a foreign key between your tables people and company with the option ON UPDATE CASCADE so that any change in the id column of the table company will be automatically propagated to the company_id column in the table people.
CREATE TABLE company (
id bigserial NOT NULL
);
CREATE TABLE people (
name VARCHAR(100) NOT NULL,
company_id int8 NOT NULL,
CONSTRAINT fkey FOREIGN KEY company_id REFERENCES company(id) ON UPDATE CASCADE
);

How to get the ID of new row in SQL?

I want to fill a column with a format using its ID.
My table:
CREATE TABLE "TEST"
(
"ID" INTEGER,
"Formatted_Column" TEXT,
PRIMARY KEY("ID" AUTOINCREMENT)
);
I want to do:
INSERT INTO TEST (Formatted_Column) VALUES ('U' + this_ID);
INSERT INTO TEST (Formatted_Column) VALUES ('U' + this_ID);
I want the output to be:
ID
Formatted_Column
1
U1
2
U2
What methods can help me?
Note: I tried to use last_insert_rowid()+1, but I think it's kind of spaghetti code (: .
My database currently SQLite, but I will change it to MySQL or SQL Server later.
I will use an online database with multi-users.
Thank you
If your version of SQLite is 3.31.0+ you can define Formatted_Column as a generated column: (VIRTUAL or STORED):
CREATE TABLE "TEST" (
"ID" INTEGER,
"Formatted_Column" TEXT GENERATED ALWAYS AS ('U' || ID) STORED,
PRIMARY KEY("ID" AUTOINCREMENT)
);
After you insert 2 rows:
INSERT INTO TEST (ID) VALUES (NULL), (NULL);
you will have:
ID
Formatted_Column
1
U1
2
U2

How to UPDATE or INSERT in PostgreSQL

I want to UPDATE or INSERT a column in PostgreSQL instead of doing INSERT or UPDATE using INSERT ... ON CONFLICT ... because there will be more updates than more inserts and also I have an auto incrementing id column that's defined using SERIAL so it increments the id column everytime it tries to INSERT or UPDATE and that's not what I want, I want the id column to increase only if it's an INSERT so that all ids would be in an order instead
The table is created like this
CREATE TABLE IF NOT EXISTS table_name (
id SERIAL PRIMARY KEY,
user_id varchar(30) NOT NULL,
item_name varchar(50) NOT NULL,
code_uses bigint NOT NULL,
UNIQUE(user_id, item_name)
)
And the query I used was
INSERT INTO table_name
VALUES (DEFAULT, 'some_random_id', 'some_random_name', 1)
ON CONFLICT (user_id, item_name)
DO UPDATE SET code_uses = table_name.code_uses + 1;
Thanks :)
Upserts in PostgreSQL do exactly what you described.
Consider this table and records
CREATE TABLE t (id SERIAL PRIMARY KEY, txt TEXT);
INSERT INTO t (txt) VALUES ('foo'),('bar');
SELECT * FROM t ORDER BY id;
id | txt
----+-----
1 | foo
2 | bar
(2 Zeilen)
Using upserts the id will only increment if a new record is inserted
INSERT INTO t VALUES (1,'foo updated'),(3,'new record')
ON CONFLICT (id) DO UPDATE SET txt = EXCLUDED.txt;
SELECT * FROM t ORDER BY id;
id | txt
----+-------------
1 | foo updated
2 | bar
3 | new record
(3 Zeilen)
EDIT (see coments): this is the expected behaviour of a serial column, since they're nothing but a fancy way to use sequences. Long story short: using upserts the gaps will be inevitable. If you're worried the value might become too big, use bigserial instead and let PostgreSQL do its job.
Related thread: serial in postgres is being increased even though I added on conflict do nothing

create unique numerical identifier column in oracle sql

I have a table that has a list of states. I did this to create the table:
CREATE TABLE drb (
Statename VARCHAR2(15)
)
I then inserted the state data. However, I want my first column to be a created unique state ID. So it should list 1-50 for the 50 states in the United States. I tried searching different unique tutorials like this and nothing seemed to work.
Essentially, I want to know how to get a unique numerical key for a variable
Your table should have id field along with statename, add it this way.
CREATE TABLE drb (
id NUMBER,
Statename VARCHAR2(15)
);
Make id as primary key:
alter table drb
add constraint drb_pk primary key (id);
Create a sequence as follows:
create ore replace sequence drb_sequence
start with 1 increment by 1;
Create a trigger which will insert a unique id into drb table as follows:
create or replace trigger drb_trigger
before insert on drb
for each row
begin
select drb_sequence.nextval into :new.id from dual;
end;
/
Now insert into drb:
insert into drb(Statename) values('state one');
Select from drb:
select * from drb;
Output :
--------------------------
|id Statename |
--------------------------
|1 state one |
--------------------------
Hope it helps.