Can you create a sequence on a column that already exists in Postgres - postgresql

I have a table linelevelpmts with a column seq (Int4) which is to be used as a sequence.
I know I can delete the column and recreate it as type serial, but can I modify the existing column to be used as a sequence.
ALTER TABLE "public"."linelevelpmts" ALTER COLUMN "seq" SET DEFAULT nextval('linelevelpmts_seq_seq'::regclass);
This code generates an error: Relation linelevelpmts_seq_seq does not exist.

This code generates an error: Relation linelevelpmts_seq_seq does not exist.
Well you need to first create the sequence you want to use for the default value:
create sequence linelevelpmts_seq_seq;
ALTER TABLE public.linelevelpmts
ALTER COLUMN seq SET DEFAULT nextval('linelevelpmts_seq_seq'::regclass);
If you want the same effect as if it was created as serial you also need to change the "owner" of the sequence:
alter sequence linelevelpmts_seq_seq owned by linelevelpmts.seq;
Edit
Igor's comment is a good one: if you already have values in the column seq you should adjust the starting value of the sequence:
select setval('linelevelpmts_seq_seq', (select max(seq) from linelevelpmts));

Related

Postgres - How to add new column uuid

I need to add new column on my table would be uuid data type, here my code:
ALTER TABLE core.example add COLUMN newcolumn SET DATA TYPE UUID USING (uuid_generate_v4())
but show me this error:
ERROR: type modifier is not allowed for type "uuid"
LINE 1: ALTER TABLE core.example add COLUMN newsi UUID (uuid_genera...
I dont want to alter a column, would be to create a new column on my table. Any idea how to make this?
Regards
When adding a new column you don't use SET DATA TYPE. Your statement should look like:
ALTER TABLE core.example ADD COLUMN newcolumn UUID DEFAULT (uuid_generate_v4());
The DEFAULT clause will immediately fill the column with UUIDs.
Alternatively if you you just want to fill the column with initial data, you can drop the DEFAULT clause afterward:
ALTER TABLE core.example ALTER COLUMN newcolumn DROP DEFAULT;
Note that if you are using Postgres 13 and newer it is generally preferrable to use gen_random_uuid() since that method is built-in and does not rely on the uuid-ossp extension.

Remove "identity flag" from a column in PostgreSQL

I have some tables in PostgreSQL 12.9 that were declared as something like
-- This table is written in old style
create table old_style_table_1 (
id bigserial not null primary key,
...
);
-- This table uses new feature
create table new_style_table_2 (
id bigint generated by default as identity,
...
);
Second table seems to be declared using the identity flag introduced in 10th version.
Time went by, and we have partitioned the old tables, while keeping the original sequences:
CREATE TABLE partitioned_old_style_table_1 (LIKE old_style_table_1 INCLUDING DEFAULTS) PARTITION BY HASH (user_id);
CREATE TABLE partitioned_new_style_table_2 (LIKE new_style_table_2 INCLUDING DEFAULTS) PARTITION BY HASH (user_id);
DDL for their id columns seems to be id bigint default nextval('old_style_table_1_id_seq') not null and id bigint default nextval('new_style_table_2_id_seq') not null.
Everything has worked fine so far. Partitioned tables proved to be a great boon and we decided to retire the old tables by dropping them.
DROP TABLE old_style_table_1, new_style_table_2;
-- [2BP01] ERROR: cannot drop desired object(s) because other objects depend on them
-- Detail: default value for column id of table old_style_table_1 depends on sequence old_style_table_1_id_seq
-- default value for column id of table new_style_table_2 depends on sequence new_style_table_2_id_seq
After some pondering I've found out that sequences may have owners in postgres, so I opted to change them:
ALTER SEQUENCE old_style_table_1_id_seq OWNED BY partitioned_old_style_table_1.id;
DROP TABLE old_style_table_1;
-- Worked out flawlessly
ALTER SEQUENCE new_style_table_2_id_seq OWNED BY partitioned_new_style_table_2.id;
ALTER SEQUENCE new_style_table_2_id_seq OWNED BY NONE;
-- Here's the culprit of the question:
-- [0A000] ERROR: cannot change ownership of identity sequence
So, apparently the fact that this column has pg_attribute.attidentity set to 'd' forbids me from:
• changing the default value of the column:
ALTER TABLE new_style_table_2 ALTER COLUMN id SET DEFAULT 0;
-- [42601] ERROR: column "id" of relation "new_style_table_2" is an identity column
• dropping the default value:
ALTER TABLE new_style_table_2 ALTER COLUMN id DROP DEFAULT;
-- [42601] ERROR: column "id" of relation "new_style_table_2" is an identity column
-- Hint: Use ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY instead.
• dropping the identity, column or the table altogether (new tables already depend on the sequence):
ALTER TABLE new_style_table_2 ALTER COLUMN id DROP IDENTITY IF EXISTS;
-- or
ALTER TABLE new_style_table_2 DROP COLUMN id;
-- or
DROP TABLE new_style_table_2;
-- result in
-- [2BP01] ERROR: cannot drop desired object(s) because other objects depend on them
-- default value for column id of table partitioned_new_style_table_2 depends on sequence new_style_table_2_id_seq
I've looked up the documentation, it provides the way to SET IDENTITY or ADD IDENTITY, but no way to remove it or to change to a throwaway sequence without attempting to drop the existing one.
➥ So, how am I able to remove an identity flag from the column-sequence pair so it won't affect other tables that use this sequence?
UPD: Tried running UPDATE pg_attribute SET attidentity='' WHERE attrelid=16816; on localhost, still receive [2BP01] and [0A000]. :/
Though I managed to execute the DROP DEFAULT value bit, but it seems like a dead end.
I don't think there is a safe and supported way to do that (without catalog modifications). Fortunately, there is nothing special about sequences that would make dropping them a problem. So take a short down time and:
remove the default value that uses the identity sequence
record the current value of the sequence
drop the table
create a new sequence with an appropriate START value
use the new sequence to set new default values
If you want an identity column, you should define it on the partitioned table, not on one of the partitions.

postgres error that sequence doesn't exist but nextval returns value for sequence

I am trying to alter a table and need to drop primary key column and then recreate it. This is slightly more complicated because I need to insert a column that is 4th from last, the last 3 columns need to stay last.
I ma executing the following script:
DO$$
BEGIN
ALTER TABLE logging.audit_study
DROP CONSTRAINT audit_study_pkey,
DROP COLUMN indication,
ADD COLUMN indication INT,
ADD COLUMN audit_study_id_tmp INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
ADD COLUMN aud_action_tmp VARCHAR,
ADD COLUMN transaction_id_tmp BIGINT DEFAULT (TXID_CURRENT());
UPDATE logging.audit_study SET audit_study_id_tmp = audit_study_id;
UPDATE logging.audit_study SET aud_action_tmp = aud_action;
UPDATE logging.audit_study SET transaction_id_tmp = transaction_id;
ALTER TABLE logging.audit_study
DROP COLUMN audit_study_id,
DROP COLUMN aud_action,
DROP COLUMN transaction_id;
ALTER TABLE logging.audit_study RENAME audit_study_id_tmp TO audit_study_id;
ALTER TABLE logging.audit_study RENAME aud_action_tmp TO aud_action;
ALTER TABLE logging.audit_study RENAME transaction_id_tmp TO transaction_id;
PERFORM SETVAL('logging.audit_study_audit_study_id_tmp_seq', (SELECT MAX(audit_study_id)+1 FROM logging.audit_study), true);
END $$
I get the following error:
[42P01] ERROR: relation "logging.audit_study_audit_study_id_tmp_seq" does not exist Where: PL/pgSQL function inline_code_block line 26 at PERFORM
However, if i execute
SELECT nextval('logging.audit_study_audit_study_id_tmp_seq')
I get an integer back for the next sequence. The sequence is also listed in the table properties.
I can't seem to understand why during this script, the sequence seems to disappear.
Dropping a primary key column declared as SERIAL data type (that creates automatically the related sequence) also drops the related sequence.

Postgres: difference between DEFAULT in CREATE TABLE and ALTER TABLE in database dump

In database dump created with pg_dump, some tables have DEFAULTs in the CREATE TABLE statement, i.e.:
CREATE TABLE test (
f1 integer DEFAULT nextval('test_f1_seq'::regclass) NOT NULL
);
But others have an additional ALTER statement:
ALTER TABLE ONLY test2 ALTER COLUMN f1 SET DEFAULT nextval('test2_f1_seq'::regclass);
What is the reason of this? All sequential fields were created with type SERIAL, but in the dump they look different, and I can't guess any rule for this.
The difference must be that in the first case, the sequence is “owned” by the table column.
You can specify this dependency using the OWNED BY clause when you create a sequence. A sequence that is owned by a column will automatically be dropped when the column is.
If a sequence is implicitly created by using serial, it will be owned by the column.

Drop sequence and cascade

I would like to drop the sequence used in table and the table itself in one statement using CASCADE, but I'm getting NOTICE and table is not dropped. For example:
CREATE SEQUENCE seq1;
CREATE TABLE t1 (f1 INT NOT NULL DEFAULT nextval('seq1'));
And then when I do:
DROP SEQUENCE seq1 CASCADE;
I get following message, and the table is not dropped:
NOTICE: drop cascades to default for table t1 column f1
I'm definitely doing something wrong but these are my very first steps in PostgreSQL.
The table is never a depending object of an associated sequence and is never dropped by:
DROP SEQUENCE ... CASCADE;
Only a column DEFAULT drawing from the sequence "depends" on the sequence and is set to NULL if the sequence is deleted with CASCADE.
It's the other way round: if the sequence is owned by a table column it is dropped with:
DROP TABLE f1 CASCADE;
For a sequence to be owned by a table column you can either use the serial type, or ALTER an existing sequence:
ALTER SEQUENCE seq1 OWNED BY t1.f1;
I don't know why are you creating a sequence manually - maybe you have justification, or maybe it's due to habits working with another DBMS.
But if you don't have a special need for it, use the SERIAL pseudo-type and when you drop the table the sequence(s) behind the SERIAL column(s) will be dropped too.
You asked to drop the sequence and cascade that action. While the default can't exist without the sequence, and it is therefore dropped, the table and the column can exist without the sequence, so they remain.
With the way you've specified this, dropping the table will not drop the sequence, although you can make the sequence depend on the column with which it is used, and therefore have it drop automatically if you drop the table. You can do this by altering the owner of the sequence, or use SERIAL instead. Declaring a column to be type SERIAL automatically creates a sequence, makes it generate a default for the column, and makes that column the owner of the sequence.
drop cascade table table_name;
you can also use this... and i will also recommend you to use a serial with primary key so that you can identify a column uniquely..