I want to add a sequence to a column that might already have data, so I'm trying to start it beyond whatever's already there. Assuming there already is data, I would like to have done it this way:
CREATE SEQUENCE my_sequence MINVALUE 1000000 START
(SELECT MAX(id_column) FROM my_table) OWNED BY my_table.id_column;
but it keeps dying at ( claiming syntax error. It's like the start value has to be cold hard numbers--nothing symbolic.
Of course, an even better solution would be if the sequence could be intelligent enough to avoid duplicate values, since id_column has a unique constraint on it--that's why I'm doing this. But from what I can tell, that's not possible.
I also tried skipping the START and then doing:
ALTER SEQUENCE my_sequence RESTART WITH (SELECT max(id_column)+1 FROM my_table);
but, again, it doesn't seem like to symbolic start values.
I'm running PostgreSQL 9.4 but some of our customers are using stuff as primitive as 8.3.
You can't specify a dynamic value for the start value.
But you can set the value once the sequence is created:
CREATE SEQUENCE my_sequence MINVALUE 1000000 OWNED BY my_table.id_column;
select setval('my_sequence', (SELECT MAX(id_column) FROM my_table));
You can restore you sequence by request:
select setval('my_sequence', (SELECT MAX(id_column) FROM my_table));
Applicable for Postgres 9.2.
Just because I was struggling with a slight variation in use case to the accepted answers here and experiencing an error telling me that setval did not exist, thought I'd share in case others had the same.
I needed to set the value of my sequence to the max value in an id column, but I also wanted to combine that with a default starting value if there were no rows.
To do this I used coalesce combined with max like this:
select setval('sequence', cast((select coalesce(max(id),1) from table) as bigint));
The catch here was using cast with the select, without that, you get an error something like:
ERROR: function setval(unknown, double precision) does not exist
LINE 1: select setval('sequence', (select coalesce(MAX(i...
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Related
I want to add a sequence to a column that might already have data, so I'm trying to start it beyond whatever's already there. Assuming there already is data, I would like to have done it this way:
CREATE SEQUENCE my_sequence MINVALUE 1000000 START
(SELECT MAX(id_column) FROM my_table) OWNED BY my_table.id_column;
but it keeps dying at ( claiming syntax error. It's like the start value has to be cold hard numbers--nothing symbolic.
Of course, an even better solution would be if the sequence could be intelligent enough to avoid duplicate values, since id_column has a unique constraint on it--that's why I'm doing this. But from what I can tell, that's not possible.
I also tried skipping the START and then doing:
ALTER SEQUENCE my_sequence RESTART WITH (SELECT max(id_column)+1 FROM my_table);
but, again, it doesn't seem like to symbolic start values.
I'm running PostgreSQL 9.4 but some of our customers are using stuff as primitive as 8.3.
You can't specify a dynamic value for the start value.
But you can set the value once the sequence is created:
CREATE SEQUENCE my_sequence MINVALUE 1000000 OWNED BY my_table.id_column;
select setval('my_sequence', (SELECT MAX(id_column) FROM my_table));
You can restore you sequence by request:
select setval('my_sequence', (SELECT MAX(id_column) FROM my_table));
Applicable for Postgres 9.2.
Just because I was struggling with a slight variation in use case to the accepted answers here and experiencing an error telling me that setval did not exist, thought I'd share in case others had the same.
I needed to set the value of my sequence to the max value in an id column, but I also wanted to combine that with a default starting value if there were no rows.
To do this I used coalesce combined with max like this:
select setval('sequence', cast((select coalesce(max(id),1) from table) as bigint));
The catch here was using cast with the select, without that, you get an error something like:
ERROR: function setval(unknown, double precision) does not exist
LINE 1: select setval('sequence', (select coalesce(MAX(i...
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
I'm having troubles resetting the sequences as automatically as possible.
I'm trying to use the next query from phpPgAdmin:
SELECT SETVAL('course_subjects_seq', (SELECT MAX(subject_id) FROM course_subjects));
Somehow this query returns:
> HINT: No function matches the given name and argument types. You might need to add explicit type casts.
pointing to the first SELECT SETVAL
The next query will give the same error:
SELECT setval("course_subjects_seq", COALESCE((SELECT MAX(subject_id) FROM course_subjects), 1))
Can anyone point me to what am I doing wrong?
Fixed by doing so:
setval function requires regclass, bigint and boolean as arguments, therefore I added the type casts:
SELECT setval('course_subjects_seq'::regclass, COALESCE((SELECT MAX(subject_id) FROM course_subjects)::bigint, 1));
::regclass
and ::bigint
You don't need a subquery at all here. Can be a single SELECT:
SELECT setval(pg_get_serial_sequence('course_subjects', 'subject_id')
, COALESCE(max(subject_id) + 1, 1)
, false) -- not called yet
FROM course_subjects;
Assuming subject_id is a serial column, pg_get_serial_sequence() is useful so you don't have to know the sequence name (which is an implementation detail, really).
SELECT with an aggregate function like max() always returns a single row, even if the underlying table has no rows. The value is NULL in this case, that's why you have COALESCE in there.
But if you call setval() with 1, the next sequence returned number will be 2, not 1, since that is considered to be called already. There is an overloaded variant of setval() with a 3rd, boolean parameter: is_called, which makes it possible to actually start from 1 in this case like demonstrated.
Related:
How to reset postgres' primary key sequence when it falls out of sync?
I'm trying to insert data into a PostgreSQL table using a nested SQL statement. I'm finding that my inserts work with a small (a few thousand) rows being returned from the nested query. For instance, when I attempt:
insert into the_target_table (a_few_columns, average_metric)
SELECT a_few_columns, AVG(a_metric)
FROM a table
GROUP BY a_few_columns LIMIT 5000)
However, this same query fails when I remove my LIMIT (the inner query without limit returns about 30,000 rows):
ERROR: Integer out of range
a_metric is a double precision, and a_few_columns are text. I've played around with the LIMIT rows, and it seems like the # of rows it can insert without throwing an error is 14,000. I don't know if this is non-deterministic, or a constant threshold before the error is thrown.
I've looked through a few other SO posts on this topic, including this one, and changed my table primary key data type to BIGINT. I still get the same error. I don't think it's an issue w/ numerical overflow, however, as the number of inserts I'm making is small and nowhere even close to hitting the threshold.
Anyone have any clues what is causing this error?
The issue here was an improper definition of the avg_metric field in my table that I wanted to insert it into. I accidentally had defined it as an integer. This normally isn’t a huge issue, but I also had a handful of infinity values ( inf). Once I switched my field data type to double precision I was able to insert successfully. Of course, it’s probably best if my application had checked beforehand for finite values prior to attempting the insert- normally I’d do this programmatically via asserts, but with a nested query I hadn’t bothered to check.
The final query I used was
insert into the_target_table (a_few_columns, average_metric)
SELECT a_few_columns, CASE WHEN AVG(a_metric) = 'inf' THEN NULL ELSE AVG(a_metric) END
FROM a_table
GROUP BY a_few_columns LIMIT 5000)
An even better solution would have been to go through a_table and replace all inf values first.
I have a simple question, suppose we have a table:
id A B
1 Jon Doe
2 Foo Bar
Is there a way to know, which is the next id's increment, in this case 3 ?
Database is PostgreSQL!
Tnx alot!
If you want to claim an ID and return it, you can use nextval(), which advances the sequence without inserting any data.
Note that if this is a SERIAL column, you need to find the sequence's name based on the table and column name, as follows:
Select nextval(pg_get_serial_sequence('my_table', 'id')) as new_id;
There is no cast-iron guarantee that you'll see these IDs come back in order (the sequence generates them in order, but multiple sessions can claim an ID and not use it yet, or roll back an INSERT and the ID will not be reused) but there is a guarantee that they will be unique, which is normally the important thing.
If you do this often without actually using the ID, you will eventually use up all the possible values of a 32-bit integer column (i.e. reach the maximum representable integer), but if you use it only when there's a high chance you will actually be inserting a row with that ID it should be OK.
To get the current value of a sequence without affecting it or needing a previous insert in the same session, you can use;
SELECT last_value FROM tablename_fieldname_seq;
An SQLfiddle to test with.
Of course, getting the current value will not guarantee that the next value you'll get is actually last_value + 1 if there are other simultaneous sessions doing inserts, since another session may have taken the serial value before you.
SELECT currval('names_id_seq') + 1;
See the docs
However, of course, there's no guarantee that it's going to be your next value. What if another client grabs it before you? You can though reserve one of the next values for yourself, selecting a nextval from the sequence.
I'm new so here's the process I use having little to no prior knowledge of how Postgres/SQL work:
Find the sequence for your table using pg_get_serial_sequence()
SELECT pg_get_serial_sequence('person','id');
This should output something like public.person_id_seq. person_id_seq is the sequence for your table.
Plug the sequence from (1) into nextval()
SELECT nextval('person_id_seq');
This will output an integer value which will be the next id added to the table.
You can turn this into a single command as mentioned in the accepted answer above
SELECT nextval(pg_get_serial_sequence('person','id'));
If you notice that the sequence is returning unexpected values, you can set the current value of the sequence using setval()
SELECT setval(pg_get_serial_sequence('person','id'),1000);
In this example, the next call to nextval() will return 1001.
How is it possible to get the current sequence value in postgresql 8.4?
Note: I need the value for the some sort of statistics, just retrieve and store. Nothing related to the concurrency and race conditions in case of manually incrementing it isn't relevant to the question.
Note 2: The sequence is shared across several tables
Note 3: currval won't work because of:
Return the value most recently obtained by nextval for this sequence in the current session
ERROR: currval of sequence "<sequence name>" is not yet defined in this session
My current idea: is to parse DDL, which is weird
You may use:
SELECT last_value FROM sequence_name;
Update:
this is documented in the CREATE SEQUENCE statement:
Although you cannot update a sequence directly, you can use a query
like:
SELECT * FROM name;
to examine the parameters and current state of a
sequence. In particular, the last_value field of the sequence shows
the last value allocated by any session. (Of course, this value might
be obsolete by the time it's printed, if other sessions are actively
doing nextval calls.)
If the sequence is being used for unique ids in a table, you can simply do this:
select max(id) from mytable;
The most efficient way, although postgres specific, is:
select currval('mysequence');
although technically this returns the last value generated by the call to nextval('mysequence'), which may not necessarily be used by the caller (and if unused would leave gaps in an auto increments id column).
As of some point in time, a secret function (which is undocumented ... still), does exactly this:
SELECT pg_sequence_last_value('schema.your_sequence_name');