Get the value of an auto-increment variable in HSQLDB - sql

I have a table that auto-increments its primary key. How can I return what this value currently is using SQL in HSQLDB?
I found this answer, but it doesn't give a full explanation of how to get it from a specific table.

If the primary key column is declared as IDENTITY, then I don't see a way to get the current value, except for calling the IDENTITY() as described in the other answer, which doesn't give the answer for the specific table.
An alternative is to create the primary key column to use a specific sequence generator instead of IDENTITY. You can then select the current value of the sequence from the INFORMATION_SCHEMA.SEQUENCE table.
The sample below shows how this would work.
create sequence test_seq;
create table test (
id integer generated by default as sequence test_seq,
value varchar(10));
insert into test (value) values ('foo');
insert into test (value) values ('bar');
insert into test (value) values ('bash');
select * from test;
id value
0 'foo'
1 'bar'
2 'bash'
select next_value from information_schema.sequences where sequence_name = 'TEST_SEQ'
3

Related

Auto-increment primary keys in SQL

I need help with the insert statements for a plethora of tables in our DB.
New to SQL - just basic understanding
Summary:
Table1
Col1 Col2 Col3
1 value1 value1
2 value2 value2
3 value3 value3
Table2
Col1 Col2 Col3
4 value1 value1
5 value2 value2
6 value3 value3
Multiple tables use the same sequence of auto-generated primary keys when user creates a static data record from the GUI.
However, creating a script to upload static data from one environment to the other is something I'm looking for.
Example from one of the tables:
Insert into RULE (PK_RULE,NAME,RULEID,DESCRIPTION)
values
(4484319,'TESTRULE',14,'TEST RULE DESCRIPTION')
How do I design my insert statement so that it reads the last value from the PK column (4484319 here) and auto inserts 4484320 without explicitly mentioning the same?
Note: Our DB has hundreds and thousands of records.
I think there's something similar to (SELECT MAX(ID) + 1 FROM MyTable) which could potentially solve my problem but I don't know how to use it.
Multiple tables use the same sequence of auto-generated primary keys when user creates a static data record from the GUI.
Generally, multiple tables sharing a single sequence of primary keys is a poor design choice. Primary keys only need to be unique per table. If they need to be unique globally there are better options such as UUID primary keys.
Instead, one gives each table their own independent sequence of primary keys. In MySQL it's id bigint auto_increment primary key. In Postgres you'd use bigserial. In Oracle 12c it's number generated as identity.
create table users (
id number generated as identity,
name text not null
);
create table things (
id number generated as identity,
description text not null
);
Then you insert into each, leaving off the id, or setting it null. The database will fill it in from each sequence.
insert into users (name) values ('Yarrow Hock'); -- id 1
insert into users (id, name) values (null, 'Reaneu Keeves'); -- id 2
insert into things (description) values ('Some thing'); -- id 1
insert into things (id, description) values (null, 'Shiny stuff'); -- id 2
If your schema is not set up with auto incrementing, sequenced primary keys, you can alter the schema to use them. Just be sure to set each sequence to the maximum ID + 1. This is by far the most sane option in the long run.
If you really must draw from a single source for all primary keys, create a sequence and use that.
create sequence master_seq
start with ...
Then get the next key with nextval.
insert into rule (pk_rule, name, ruleid, description)
values (master_seq.nextval, 'TESTRULE', 14, 'TEST RULE DESCRIPTION')
Such a sequence goes up to 1,000,000,000,000,000,000,000,000,000 which should be plenty.
The INSERT and UPDATE statements in Oracle have a ...RETURNING...INTO... clause on them which can be used to return just-inserted values. When combined with a trigger-and-sequence generated primary key (Oracle 11 and earlier) or an identity column (Oracle 12 and up) this lets you get back the most-recently-inserted/updated value.
For example, let's say that you have a table TABLE1 defined as
CREATE TABLE TABLE1 (ID1 NUMBER
GENERATED ALWAYS AS IDENTITY
PRIMARY KEY,
COL2 NUMBER,
COL3 VARCHAR2(20));
You then define a function which inserts data into TABLE1 and returns the new ID value:
CREATE OR REPLACE FUNCTION INSERT_TABLE1(pCOL2 NUMBER, vCOL3 VARCHAR2)
RETURNS NUMBER
AS
nID NUMBER;
BEGIN
INSERT INTO TABLE1(COL2, COL3) VALUES (pCOL2, vCOL3)
RETURNING ID1 INTO nID;
RETURN nID;
END INSERT_TABLE1;
which gives you an easy way to insert data into TABLE1 and get the new ID value back.
dbfiddle here

SQL Primary Key Increment

How can I have a primary key that auto increments?
for example: when I insert something at the field name, the field id should be assign a value that is +1 that the last one.
id, name
1, test1
2, test2
so I insert the name something like testX and the id should be auto assigned as 3
how can i do that?
In addition to answer of ain, you can use generator like :
Create a generator :
CREATE GENERATOR <name>;
SET GENERATOR <name> TO <value>;
Getting the current value of generator:
SELECT GEN_ID( <GeneratorName>, 0 ) FROM RDB$DATABASE;
Generating the next value
SELECT GEN_ID( <GeneratorName>, 1 ) FROM RDB$DATABASE;
Using generator in trigger
CREATE OR ALTER trigger <trigger_name>_bi for <table_name>
active before insert position 0
as
begin
if (new.id is null) then
new.id = gen_id(my_generator,1);
end
If you want numeration without holes you have to be very careful.
Generators/Sequences are non-transactional.
Once you get a value if your operation fails, you will have a hole.
If you're using Firebird 3 then you can use the identity column feature:
create table T (
id integer generated by default as identity primary key,
...
);
If you're using some older version of Firebird, then using an sequence with trigger can be used to achieve the autoincrement:
create table T (
id integer primary key,
...
);
CREATE SEQUENCE t_seq;
create trigger t_gen_id
active before insert
on T
as
begin
if(new.id is null)then new.id = next value for t_seq;
end;
Since Firebird 2 the returning clause is supported which is very handy to get the id value generated on the server side.

I don't understand how postgresql's nextval() work, can someone explain?

I'm just starting to wade into backend development after my first few months on the job as a front end dev. I'm working with postgreSQL and can't seem to wrap my head around the nextval() function. I read this, but it's not clear to me.
http://www.postgresql.org/docs/current/interactive/functions-sequence.html
what are the benefits/use cases for nexval()?
NEXTVAL is a function to get the next value from a sequence.
Sequence is an object which returns ever-increasing numbers, different for each call, regardless of transactions etc.
Each time you call NEXTVAL, you get a different number.
This is mainly used to generate surrogate primary keys for you tables.
You can create a table like this:
CREATE SEQUENCE mysequence;
CREATE TABLE mytable (id BIGINT NOT NULL PRIMARY KEY, value INT);
and insert values like this:
INSERT
INTO mytable (id, value)
VALUES
(NEXTVAL('mysequence'), 1),
(NEXTVAL('mysequence'), 2);
and see what you get:
SELECT * FROM mytable;
id | value
----+-------
1 | 1
2 | 2
PostgreSQL offers a nice syntax sugar for this:
CREATE TABLE mytable (id BIGSERIAL PRIMARY KEY, value INT);
which is equivalent to
CREATE SEQUENCE mytable_id_seq; -- table_column_'seq'
CREATE TABLE mytable (id BIGINT NOT NULL PRIMARY KEY DEFAULT NEXTVAL('mytable_id_seq'), value INT); -- it's not null and has a default value automatically
and can be used like this:
INSERT
INTO mytable (value)
VALUES (1),
(2); -- you can omit id, it will get filled for you.
Note that even if you rollback your insert statement or run concurrent statements from two different sessions, the returned sequence values will never be the same and never get reused (read the fine print in the docs though under CYCLE).
So you can be sure all the values of your primary keys will be generated unique within the table.

Postgres: Problems using insert with select

I have a table defined like this:
CREATE TABLE wp_master (
gid integer NOT NULL DEFAULT nextval('wp_master_gid_seq'::regclass),
name character varying(80),
....
type integer DEFAULT 4,
CONSTRAINT p_key PRIMARY KEY (gid),
);
I want to insert data into the table from another table so I
insert into wp_master ( name, .... type) select "NAME", ...., 1 from ."Tiri2011";
but I get the error:
ERROR: duplicate key value violates unique constraint "p_key"
DETAIL: Key (gid)=(2) already exists.
Why is postgres trying to put anything into the gid field when I have explicitly not included it in the list of columns? I assumed that gid pick up its value from the sequence.
Russell
Is is trying to insert the next value of the wp_master_gid_seq sequence. Declaring an id column as serial (auto-increment) will create a sequence which has a stored value of the last inserted id which was auto-incremented. If at anytime you inserted a gid value manually, it bypassed the sequence and the autoincrement function may become broken, because the sequence value did not get updated accordingly.
The easiest way to fix it is to change the value of the sequence to the (max gid value of your table) + 1. Just execute this once and you should be ok
select setval('wp_master_gid_seq', coalesce((select max(id)+1 from wp_master), 1), false)

Update value on insert into table in SQL Server

I am working with SQL Server - on inserting into a table, I have a unique constraint on a table column id. There is a possibility that when inserting, the value going into the id column is 0. This will cause an error.
Is it possible to update this id to another value during the insert if the id value is 0? This is to prevent the error and to give it a valid value.
Possibly a trigger?
A trigger is one way, but you may want to use a filtered index (CREATE UNIQUE INDEX, not as a table constraint) to ignore zero value. This way, you don't have to worry about what value to put there
Alternatively, if you want to populate it from another column, you can have a computed column with a unique constraint.
ALTER TABLE whatever
ADD ComputedUniqueCol = CASE WHEN Id = 0 THEN OtherCol ELSE Id END
If that's your primary key you can specify it as IDENTITY. Then it should generate a value for itself based on seed and increment (the default is seed=1 and default=1) so you don't have to worry about it.
CREATE TABLE MyTable
(
ID int PRIMARY KEY IDENTITY,
...
)
create an "instead of" trigger and check for the value on the ID.
CREATE trigger checkID
on YOUR_TABLE
instead of insert
as
begin
declare #id int
select #id=id from inserted
if (#id==0) begin
--DO YOUR LOGIC HERE AND THEN INSERT
end else begin
insert into DESTINATION_TABLE (VALUES)
SELECT VALUES FROM INSERTED
end
end