postgres - insert gen_random_uuid() for the column "key" if the count(key) < 1 - postgresql-9.4

Generate gen_random_uuid() for the column key if there count(key) < 1
My table name is keytable and column is key.
I am using the below insert statement to generate the uuid : that is the only value in the table.
INSERT INTO keytable VALUES(gen_random_uuid());
key
---------------------------------------
5686473e-add1-4ab1-be85-7e62152ce539
I wanted to run this insert statement only when i dont have any values in my "key" column.
in other words, if count(key) < 1 then i want to run the INSERT INTO keytable VALUES(gen_random_uuid());
Please help.

use INSERT ... SELECT construct instead
t=# begin; insert into keytable select gen_random_uuid() where (select count(key) from keytable) < 1;
BEGIN
INSERT 0 1
t=# insert into keytable select gen_random_uuid() where (select count(key) from keytable) < 1;
INSERT 0 0
t=# rollback;
ROLLBACK

Already Answered By Clodoaldo Neto (Link Below)
here is according to your perspective
insert into keytable
select gen_random_uuid()
where not exists ( select key from keytable );
It will only insert the result of select statement when
select key from keytable
this does not return anything!
for more info: https://stackoverflow.com/a/15710598/8506841

Related

Is it possible to use nextval of a sequence as default value of a field in a table in infomrix database?

I have a table named T1 with a field id(int8) and a sequence named seq_id.
Can I use seq_id.nextval as a default value for id in informix database?
Or another way, can I use a trigger to update id before insert with seq_id.nextval?
In Informix you cannot use a sequence NEXTVAL as a default value for a column.
One option is to turn the column into a BIGSERIAL.
Other option is with an insert trigger. I did not find a way to directly assign the sequence NEXTVAL in the trigger definition, but it can be done by using a stored procedure.
CREATE SEQUENCE seq_id
INCREMENT BY 1 START WITH 1
MINVALUE 0
NOCYCLE CACHE 10
ORDER;
CREATE TABLE t1
(
id BIGINT NOT NULL
, val1 CHAR(4)
);
I found 2 ways to use the procedure. A generic procedure that returns the sequence NEXTVAL and a trigger procedure, that assigns the sequence NEXTVAL to the id.
Using a generic procedure:
CREATE FUNCTION spl_get_seq_id()
RETURNING BIGINT AS seq_id_next;
DEFINE seq_id_next BIGINT;
LET seq_id_next = seq_id.NEXTVAL;
RETURN seq_id_next;
END FUNCTION;
CREATE TRIGGER t1_ti
INSERT ON t1 REFERENCING NEW AS new_ins
FOR EACH ROW
(
EXECUTE FUNCTION spl_get_seq_id() INTO id
);
Inserting a few values into the table and checking the result:
INSERT INTO t1( id, val1 ) VALUES ( 1000, 'AAAA' );
INSERT INTO t1( val1 ) VALUES ( 'AAAB' );
INSERT INTO t1( id ) VALUES ( 1 );
INSERT INTO t1( id, val1 ) VALUES ( NULL::BIGINT, 'AAAD' );
SELECT * FROM t1;
id val1
1 AAAA
2 AAAB
3
4 AAAD
Using a trigger procedure:
DROP TRIGGER t1_ti;
CREATE PROCEDURE t1_ti_spl_get_seq_id()
REFERENCING NEW AS new_values FOR t1;
LET new_values.id = seq_id.NEXTVAL;
END PROCEDURE;
CREATE TRIGGER t1_ti
INSERT ON t1
FOR EACH ROW
(
EXECUTE PROCEDURE t1_ti_spl_get_seq_id() WITH TRIGGER REFERENCES
);
Inserting a few values into the table and checking the result:
INSERT INTO t1( id, val1 ) VALUES ( 1000, 'AAAE' );
INSERT INTO t1( val1 ) VALUES ( 'AAAF' );
INSERT INTO t1( id ) VALUES ( 1 );
INSERT INTO t1( id, val1 ) VALUES ( NULL::BIGINT, 'AAAH' );
SELECT * FROM t1;
id val1
1 AAAA
2 AAAB
3
4 AAAD
5 AAAE
6 AAAF
7
8 AAAH
I used BIGINT for the id column, but it should work for INT8 (as to why did I use it, seems there is some benefits: Counters and codes: BIGINT, INT8, INTEGER, and SMALLINT).
EDIT 1:
In response to your comment, you can try a condition on the trigger, based on the session user. This will only work if the cdc software is using a dedicated user. In this example, cdc_agent is the user that the cdc software uses in Informix.
DATABASE db1;
GRANT CONNECT TO cdc_agent;
GRANT CONNECT TO myuser;
CREATE SEQUENCE seq_id
INCREMENT BY 2 START WITH 2
MINVALUE 0
NOCYCLE CACHE 10
ORDER;
GRANT SELECT ON seq_id TO cdc_agent;
GRANT SELECT ON seq_id TO myuser;
CREATE TABLE t1
(
id BIGINT NOT NULL
, val1 CHAR(4)
);
GRANT ALL ON t1 TO cdc_agent;
GRANT ALL ON t1 TO myuser;
CREATE PROCEDURE t1_ti_spl_get_seq_id()
REFERENCING NEW AS new_values FOR t1;
LET new_values.id = seq_id.NEXTVAL;
END PROCEDURE;
GRANT EXECUTE ON t1_ti_spl_get_seq_id TO cdc_agent;
GRANT EXECUTE ON t1_ti_spl_get_seq_id TO myuser;
CREATE TRIGGER t1_ti
INSERT ON t1 REFERENCING NEW AS new_ins
FOR EACH ROW WHEN ( USER <> "cdc_agent" )
(
EXECUTE PROCEDURE t1_ti_spl_get_seq_id() WITH TRIGGER REFERENCES
);
Inserting a few values into the table and checking the result:
-- with user "cdc_agent"
INSERT INTO t1( id, val1 ) VALUES ( 11, 'AAAA' );
INSERT INTO t1( id, val1 ) VALUES ( 13, 'AAAC' );
-- with user "myuser"
INSERT INTO t1( id, val1 ) VALUES ( 1, 'AAAB' );
INSERT INTO t1( id, val1 ) VALUES ( 3, 'AAAD' );
SELECT * FROM t1;
id val1
11 AAAA
13 AAAC
2 AAAB
4 AAAD

PostgreSQL insert current sequence value to another field with condition

the issue:
i need to do something like this
drop table if exists tt_t;
create temp table tt_t(id serial primary key, main_id int, external_id int);
insert into tt_t(main_id, external_id)
select currval(pg_get_serial_sequence('tt_t', 'id')), 1
where not exists (select from tt_t where external_id = 1);
but execution raises an error
SQL Error [55000]: ERROR: currval of sequence "tt_t_id_seq" is not yet defined in this session
solution:
there is a way to solve this with anonymous code block
do
$$
begin
if not exists(select from tt_t where external_id = 1)
then
insert into tt_t(external_id, main_id)
values(1, currval(pg_get_serial_sequence('tt_t', 'id')));
end if;
end;
$$
;
but anonymous blocks has some restrictions e.g. Dapper parameters not working with PostgreSQL through npgsql connection, is postgres anonymous function parameterization supported?
how do i fix it without anonymous code block (UPD: and without any DDL changes)?
probable solution:
insert into tt_t(id, main_id, external_id)
select nextval(pg_get_serial_sequence('tt_t', 'id')), currval(pg_get_serial_sequence('tt_t', 'id')), 1
where not exists (select from tt_t where external_id = 1);
shorter code has been proposed to me
insert into tt_t(id, main_id, external_id)
select nextval(pg_get_serial_sequence('tt_t', 'id')), lastval(), 1
where not exists (select from tt_t where external_id = 1);
but i'm not sure if nextval will be calculated first
What about using a default value:
drop table if exists tt_t;
create temp table tt_t(id serial primary key, main_id int default lastval(), external_id int);
insert into tt_t(external_id)
select 1
where not exists (select * from tt_t where external_id = 1);
In theory it shouldn't be possible that another nextval() is called between the one for the id and the lastval(). However I am not 100% sure if there are some corner cases that I don't know of.
The following works as well (even if one or more of the external_id values already exist).
insert into tt_t(external_id)
select *
from (values (1),(2),(3)) x (external_id)
where not exists (select *
from tt_t
where external_id = x.external_id);

PostgreSQL: Column DEFAULT gen_random_bytes UNIQUE

Let's say we have the following table:
CREATE TABLE foo (
column_1 bigint,
column_2 bytea DEFAULT gen_random_bytes(2),
PRIMARY KEY (column_1, column_2)
);
Note: We want column_2 to be random & cryptographically strong.
How do we insert a row without causing a primary key conflict?
I guess we'd have to do a loop until gen_random_bytes(2) returns a unique result? If so, can we do this loop with pure SQL, maybe with recursive CTE, instead of with plpgsql?
insert into t (col1, col2)
select 1, ('\x' || right('000' || to_hex(i), 4))::bytea
from (
select generate_series(0, 65535) i
except
select get_byte(col2, 0) * 256 + get_byte(col2, 1)
from t
where col1 = 1
) s
order by random()
limit 1

How to Auto Increment Alpha-Numeric value in postgresql?

I am using "PostgreSQL 9.3.5"
I have a Table(StackOverflowTable) with columns (SoId,SoName,SoDob).
I want a Sequence generator for column SoId which is a Alpha-numeric value.
I want to auto increment a Alpha-Numeric Value in postgresql.
For eg : SO10001, SO10002, SO10003.....SO99999.
Edit:
If tomorrow i need to generate a Sequence which can be as SO1000E100, SO1000E101,... and which has a good performance. Then what is the best solution!
Use sequences and default value for id:
postgres=# CREATE SEQUENCE xxx;
CREATE SEQUENCE
postgres=# SELECT setval('xxx', 10000);
setval
--------
10000
(1 row)
postgres=# CREATE TABLE foo(id text PRIMARY KEY
CHECK (id ~ '^SO[0-9]+$' )
DEFAULT 'SO' || nextval('xxx'),
b integer);
CREATE TABLE
postgres=# insert into foo(b) values(10);
INSERT 0 1
postgres=# insert into foo(b) values(20);
INSERT 0 1
postgres=# SELECT * FROM foo;
id | b
---------+----
SO10001 | 10
SO10002 | 20
(2 rows)
You can define default value of your column as a concatenation of S and a normal sequence as bellow:
CREATE SEQUENCE sequence_for_alpha_numeric
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 1
CACHE 1;
CREATE TABLE table1
(
alpha_num_auto_increment_col character varying NOT NULL,
sample_data_col character varying,
CONSTRAINT table1_pkey PRIMARY KEY (alpha_num_auto_increment_col)
)
;
ALTER TABLE table1 ALTER COLUMN alpha_num_auto_increment_col SET DEFAULT TO_CHAR(nextval('sequence_for_alpha_numeric'::regclass),'"S"fm000000');
Test:
^
insert into table1 (sample_data_col) values ('test1');
insert into table1 (sample_data_col) values ('test2');
insert into table1 (sample_data_col) values ('test3');
select * from table1;
alpha_num_auto_increment_col | sample_data_col
------------------------------+-----------------
S000001 | test1
S000002 | test2
S000003 | test3
(3 lignes)
How to use sequences
How to use to_char function.
Create A sequence like below
CREATE SEQUENCE seq_autoid
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 10000
Create A Function to generate alpha numeric id
create or replace function auto_id () returns varchar as $$
select 'SO'||nextval('seq_autoid')
$$ language sql
and try this example table
create table AAA(id text ,namez text)
insert into AAA values (auto_id(),'MyName')
insert into AAA values (auto_id(),'MyName1')
insert into AAA values (auto_id(),'MyName2')

Select from insert

Is it possible to select from an insert statement? For example:
SELECT id FROM (INSERT INTO table (col1, col2) VALUES (val1, val2));
Where id is an autoincrementing primary key.
It's not possible in such way, because INSERT doesn't return virtual table for SELECT. However you could get id's actual value using currval(regclass) sequence function as:
SELECT currval('yourTableName_id_seq'::regclass);
currval
---------
1
(1 row)
EDIT:
Use RETURNING clause (available since PostgreSQL 8.2):
INSERT INTO yourTableName (col1, col2) VALUES ('aaa', 'bbb') RETURNING id;
id
----
2
(1 row)
"SELECT id FROM mytable WHERE id IS NULL;
"id" has to be an auto_increment column to make it work.
It will return the last_insert_id just as last_insert_id() is expected to do.
example:
mysql> INSERT INTO orders (customer_cust_id, orderdatetime, message, taxrate, shippingprice)
-> SELECT '1', NOW(), null, taxrate, shippingprice FROM customer
-> WHERE cust_id='1';"
http://dev.mysql.com/doc/refman/5.0/en/insert-select.html