Auto increment non primary column in SQLAlchemy - postgresql

In my db model I need userId and forumPostId to be a composite primary key. But I need id to be a auto incremented value. But when I'm trying to insert new row in table getting none in id instead of a auto incremented integer.
class ForumPostFollow(db.Model):
__tablename__ = "forum_post_follow"
id = db.Column(db.Integer,autoincrement=True,nullable=False,unique=True)
userId = db.Column(db.Integer,db.ForeignKey('user.id'),primary_key=True)
forumPostId = db.Column(db.Integer,db.ForeignKey('forum_post.id'),primary_key=True)
active = db.Column(db.Boolean,nullable=False)
My package versions
Flask-SQLAlchemy==2.3.2 SQLAlchemy>=1.3.0
This question is similar to this question. But it's for version 1.1
Updated Question
I've changed my id columns sequence from terminal
ALTER TABLE forum_post_follow DROP COLUMN id;
ALTER TABLE forum_post_follow ADD COLUMN id SERIAL;
Then my altered columns looks like this
But still getting same error
sqlalchemy.exc.IntegrityError: (psycopg2.errors.NotNullViolation) null value in column "id" violates not-null constraint
DETAIL: Failing row contains (1, 1, t, null).
[SQL: INSERT INTO forum_post_follow (id, "userId", "forumPostId", active) VALUES (%(id)s, %(userId)s, %(forumPostId)s, %(active)s)]
[parameters: {'id': None, 'userId': 1, 'forumPostId': 1, 'active': True}]

I had a similar problem and found that as per SQLAlchemy 1.3 Documentation:
For the case where this default generation of IDENTITY is not desired, specify False for the Column.autoincrement flag, on the first integer primary key column:
so you might want to try this:
class ForumPostFollow(db.Model):
__tablename__ = "forum_post_follow"
id = db.Column(db.Integer,autoincrement=False,primary_key=True,nullable=False,unique=True)
userId = db.Column(db.Integer,db.ForeignKey('user.id'),primary_key=True)
forumPostId = db.Column(db.Integer,db.ForeignKey('forum_post.id'),primary_key=True)
active = db.Column(db.Boolean,nullable=False)

Related

duplicate key value violates unique constraint "pk_user_governments"

I am trying to insert a record with many to many relationship in EfCore to postgres table
When adding a simple record to Users...it works but when I introduced 1:N with User_Governments
It started giving me duplicate key value violates unique constraint "pk_user_governments"
I have tried a few things:
SELECT MAX(user_governments_id) FROM user_governments;
SELECT nextval('users_gov_user_id_seq');
This keeps incrementing everytime I run it in postgres..but the issue does not go
I am inserting it as follows:
User user = new();
user.Organisation = organisation;
user.Name = userName;
user.Email = email;
user.IsSafetyDashboardUser = isSafetyFlag;
if (isSafetyFlag)
{
List<UserGovernment> userGovernments = new List<UserGovernment>();
foreach (var govId in lgas)
{
userGovernments.Add(new UserGovernment()
{
LocalGovId = govId,
StateId = 7
});
}
user.UserGovernments = userGovernments;
}
_context.Users.Add(user);
int rows_affected = _context.SaveChanges();
Table and column in db is as follows:
CREATE TABLE IF NOT EXISTS user_governments
(
user_government_id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
user_id integer NOT NULL,
state_id integer NOT NULL,
local_gov_id integer NOT NULL,
CONSTRAINT pk_user_governments PRIMARY KEY (user_government_id),
CONSTRAINT fk_user_governments_local_govs_local_gov_id FOREIGN KEY (local_gov_id)
REFERENCES local_govs (local_gov_id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE,
CONSTRAINT fk_user_governments_states_state_id FOREIGN KEY (state_id)
REFERENCES states (state_id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE,
CONSTRAINT fk_user_governments_users_user_id FOREIGN KEY (user_id)
REFERENCES users (user_id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
I have also tried running following command as per this post
SELECT SETVAL((SELECT PG_GET_SERIAL_SEQUENCE('user_governments', 'user_government_id')), (SELECT (MAX("user_government_id") + 1) FROM "user_governments"), FALSE);
but I get error:
ERROR: relation "user_governments" does not exist
IDENTITY is an table integrated automatic increment. No needs to use PG_GET_SERIAL_SEQUENCE wich is dedicated for SEQUENCES that is another way to have increment outside the table. So you cannot use a query like :
SELECT SETVAL((SELECT PG_GET_SERIAL_SEQUENCE('user_governments', 'user_government_id')),
(SELECT (MAX("user_government_id") + 1) FROM "user_governments"), FALSE)
If your purpose is to assigne the seed for an IDENTITY, the ways to do that is :
You must use a syntax like this one :
ALTER TABLE user_governments
ALTER COLUMN user_government_id RESTART WITH (select Max(user_government_id) + 1 from user_governments);
It turned out that I did not build the model correctly.
The user_government table had an incremental key, but I had defined the model as follows
modelBuilder.Entity<UserGovernment>()
.HasKey(bc => new { bc.UserId, bc.LocalGovId });
I replaced it with:
modelBuilder.Entity<UserGovernment>()
.HasKey(bc => new { bc.UserGovernmentId});
The Journey :)
Initially I found out that once I commented the following line
_context.UserGovernments.AddRange(userGovernments);
It just inserted data with user_government_id as 0
Then I tried manually giving a value to user_government_id and it also went successfully, this lead me to check my modelbuilder code!!

Auto-incremented attribute assignment in sqlalchemy orm

I have a table with the single auto-incremented field id of type bigserial:
create table user
(
id bigserial
primary key
);
I expect a new class instance to have a value of attribute 'id', but it is None:
>>> u = User()
>>> session.add(u)
>>> print(u.id)
None
However, if I execute a query statement, the attribute is there:
>>> session.query(User.id).all()
>>> print(u.id)
1
Why is field id empty on the first and not empty on the second call?

Updating key constraints on multiple records simultaneously

We have a table with a unique key which gets updated by ‘aging’ older records, as mentioned by #Tony O’Hagan here.
The table looks as follows:
-- auto-generated definition
create table abc
(
key uuid not null,
hash text not null,
age integer not null,
value varchar(50),
constraint abc_pkey
primary key (key, age)
);
We can simulate an ‘aged’ record with the following dummy data:
INSERT INTO public.abc (key, hash, age, value) VALUES ('bec619bb-451c-49d8-b555-4d16e1f724fb', 'asdf', 0, '1');
INSERT INTO public.abc (key, hash, age, value) VALUES ('bec619bb-451c-49d8-b555-4d16e1f724fb', 'asdf', 1, '2');
INSERT INTO public.abc (key, hash, age, value) VALUES ('bec619bb-451c-49d8-b555-4d16e1f724fb', 'asdf', 2, '3');
When I want to add a new record, I must first ‘age’ the older records before inserting a new record with age=0
However I get the following error message when I run the query below:
[23505] ERROR: duplicate key value violates unique constraint "abc_pkey" Detail: Key (key, age)=(bec619bb-451c-49d8-b555-4d16e1f724fb, 2) already exists.
UPDATE abc
SET age = age +1
WHERE key IN (
'bec619bb-451c-49d8-b555-4d16e1f724fb'
)
How can I update/age these records?
We can disable the CONSTRAINTS with the commande
SET CONSTRAINTS ALL DEFERRED
✓
which lets us run our update
UPDATE public.abc SET age = age + 1;
3 rows affected
we can then reactivate the CONSTRAINTS with
SET CONSTRAINTS ALL IMMEDIATE
✓

How to reset the auto generated primary key in PostgreSQL

My class for the table topics is as below. The primary key is autogenerated serial key. While testing, I deleted rows from the table and was trying to re-insert them again. The UUID is not getting reset.
class Topics(db.Model):
""" User Model for different topics """
__tablename__ = 'topics'
uuid = db.Column(db.Integer, primary_key=True)
topics_name = db.Column(db.String(256),index=True)
def __repr__(self):
return '<Post %r>' % self.topics_name
I tried the below command to reset the key
ALTER SEQUENCE topics_uuid_seq RESTART WITH 1;
It did not work.
I would appreciate any form of suggestion!
If it's indeed a serial ID, you can reset the owned SEQUENCE with:
SELECT setval(pg_get_serial_sequence('topics', 'uuid'), max(uuid)) FROM topics;
See:
How to reset postgres' primary key sequence when it falls out of sync?
But why would the name be uuid? UUID are not integer numbers and not serial. Also, it's not entirely clear what's going wrong, when you write:
The UUID is not getting reset.
About ALTER SEQUENCE ... RESTART:
Postgres manually alter sequence
In order to avoid duplicate id errors that may arise when resetting the sequence try:
UPDATE table SET id = DEFAULT;
ALTER SEQUENCE seq RESTART;
UPDATE table SET id = DEFAULT;
For added context:
'table' = your table name
'id' = your id column name
'seq' = find the name of your sequence with:
SELECT pg_get_serial_sequence('table', 'id');

IBM DB2 recreate index on truncated table

After truncating table, and inserting new values in table, auto-increment values are not set to started value 1. When inserting new values it's remember last index-ed value of auto-increment.
Colum in table named: ID
Index: PRIMARY,
Initial Value: 1
Cache size: 1
Increment: 1
[checked on IBM DB2 Control Center]
This query:
TRUNCATE TABLE ".$this->_schema.$table." DROP STORAGE IGNORE DELETE TRIGGERS IMMEDIATE
table is EMPTY.
After INSERT NEW VALUES example: INSERT INTO DB2INST1.db (val) VALUES ('abc') it's INSERT with LAST
ID | val
55 | abc
But it SHOULD BE:
ID | val
1 | abc
I'm guessing here that your question is "how do you restart the IDENTITY sequence?" If that is the case, then you can reset it with the following SQL:
ALTER TABLE <table name> ALTER COLUMN <IDENTITY column> RESTART WITH 1
However, like #Ian said, what you are seeing is the expected behavior of a TRUNCATE.
First select in TABLE SCHEMA WHERE is name of IDENTITY column:
Query 1:
SELECT COLNAME FROM SYSCAT.COLUMNS WHERE TABSCHEMA = 'DB2INST1' AND
TABNAME = 'DB' AND IDENTITY = 'Y'
Then, truncate table and return it's example: ID for altering index:
Query 2:
This ID puts on query for reset and altering index identity:
ALTER TABLE DB2INST1.DB ALTER COLUMN ID RESTART WITH 1
Change ID above returned from Query 1, which returns name of ID to Query 2.
SOLVED!