NEXTVAL Function in PostgreSQL

Bilal Shahid Apr 30, 2022
NEXTVAL Function in PostgreSQL

NEXTVAL() tends to advance an object to another value and return it. SEQUENCE OBJECTS are just single-row tables created from SEQUENCES in PostgreSQL.

The NEXTVAL() function is defined under the SEQUENCE MANIPULATION FUNCTIONS.

nextval ( regclass ) ? bigint

REGCLASS refers to the SEQUENCE OBJECT, and this function tends to return the BIGINT. Now let’s see some possible implementations of this NEXTVAL() function and how we can use it.

Practical Example of NEXTVAL() in PostgreSQL

One of the uses of SEQUENCE IDENTIFIERS in PostgreSQL is how they can be used for getting unique row identifier values. You can read more about them under the CREATE SEQUENCE URL.

We will follow up on the usage given above and then try to implement a system that can effectively use the NEXTVAL() function. We will boot up PostgreSQL and create a simple table called RANDOM_GEN (short for random generator).

CREATE TABLE RANDOM_GENE(
	val INT PRIMARY KEY
);

We have used a simple VALUE as a PRIMARY KEY in our table as it will be unique and random. Now let’s go ahead and append some data to this table.

Of course, the VAL should be RANDOM to use the SEQUENCE GENERATOR in PostgreSQL. Our tutorial will use a SERIAL GENERATOR with incrementing values to get UNIQUE VAL.

CREATE SEQUENCE serial_num;

And to use the values from this SEQUENCE GENERATOR, we can query a SELECT operation from this table.

SELECT * from SERIAL_NUM;

But there is an issue. If we repeatedly call this SELECT operation, we tend to get the same value from the SEQUENCE GENERATOR.

So if we were to INSERT values from this SEQUENCE to our table without testing, we would have ended up with duplicate values.

And this is where the NEXTVAL() function comes in. We can go ahead and advance the value of this GENERATOR and then issue the SELECT operation to get the ascending values.

So we can write:

SELECT * from NEXTVAL('serial_num');

And this will return output as follows for, let’s say, 5 iterations.

Output:

Iter      VAL
1          1
2          2
3          3
4          4
5          5

So NEXTVAL(), as we saw, tends to increase the SEQUENCE GENERATOR and advance it. So each time NEXTVAL() is called for the SEQUENCE passed in its argument, we can imagine the SEQUENCE to point itself to the next ascending value.

Hence we can now call something as follows for an INSERT operation into our RANDOM_GEN table.

INSERT INTO RANDOM_GENE values (NEXTVAL('SERIAL_NUM')), (NEXTVAL('SERIAL_NUM')), (NEXTVAL('SERIAL_NUM'));

Our table will now look as follows.

Output:

        val
1       1
2       2
3       3

Another simple way of achieving this for just the VALUE column would be to define NEXTVAL() right in the CREATE TABLE statement. We can write a query as follows.

CREATE TABLE RANDOM_GENE(
	val INT primary key default NEXTVAL('SERIAL_NUM')
);

We have used DEFAULT to define the default behavior of this VAL column that is getting values from the SEQUENCE GENERATOR. Of course, the above is useless without a secondary column, so let’s add a USER_NAME column to define the USERS receiving the RANDOM_GEN values.

CREATE TABLE RANDOM_GENE(
	val INT primary key default NEXTVAL('SERIAL_NUM'),
        name TEXT
);

We can now write an INSERT statement as follows.

INSERT into RANDOM_GENE (name) values ('John'), ('Marta'), ('Alex');

This will INSERT the names given in the query to our table with the respective values obtained in ascending order from our SEQUENCE GENERATOR. If we tend to look at the table now, it would be as follows.

val     name
1	"John"
2	"Marta"
3	"Alex"

Hence, we have now fully understood how NEXTVAL() works. As for now, let’s look at the working of NEXTVAL() in different environments.

NEXTVAL() in Different Environments and Circumstances in PostgreSQL

Using NEXTVAL() tends to increment the SEQUENCE GENERATOR each time called. Hence, we don’t have to worry about duplicates in this case.

Once NEXTVAL() is called, the GENERATOR is advanced and computes the next value. Any other query concurrently running that calls the NEXTVAL() for the same SEQUENCE will get the generator’s entirely different and unique value.

Hence, it is efficient and safe to use NEXTVAL() for multiple transactions and processes that may be executing queries on a Postgres server.

Gaps and Value Differences From NEXTVAL() in PostgreSQL

A common issue found in NEXTVAL() is the strict implementation of advancement. Once the SEQUENCE advances to the new values, it is highly unlikely for it to return back or even check to see if a previous value has been used or not.

So in case you have a table with a UNIQUE value column and a NAME, and somehow the NAME you are trying to INSERT is already present in the table, you can get a violation error. NEXTVAL() would have already been called in that scenario.

And the SEQUENCE advanced to a value, but the violation prevents the INSERTION. So the next time INSERT is called, NEXTVAL() will advance once again, and the former value will be entirely skipped.

The same can be said for ON CONFLICT operations or those that may not execute properly. In the example given below, use the following to call an INSERT on the table column NAME.

name TEXT unique

And then, we INSERT data into our table with an intentional duplicate name for ALEX with a query as follows.

INSERT into RANDOM_GENE (name) values ('John'), ('Marta'), ('Alex'), ('Alex'), ('Mathew') on conflict (name) do nothing;

We have put ON CONFLICT to bypass the duplicate violation error and check our table for the VALUE. The table now looks as follows.

val    name
1	"John"
2	"Marta"
3	"Alex"
5	"Mathew"

You can see how there is no number 4 value for the column VAL. And that is because the duplicate ALEX insertion did advance the SEQUENCE GENERATOR but did not get INSERTED.

Hence for the name MATHEW, the value was already at 4, which then advanced to 5 for its INSERTION.

So now we hope that you have fully understood how NEXTVAL() works and can implement it as you like.

Author: Bilal Shahid
Bilal Shahid avatar Bilal Shahid avatar

Hello, I am Bilal, a research enthusiast who tends to break and make code from scratch. I dwell deep into the latest issues faced by the developer community and provide answers and different solutions. Apart from that, I am just another normal developer with a laptop, a mug of coffee, some biscuits and a thick spectacle!

GitHub

Related Article - PostgreSQL Function