No unique constraint for composite foreign key, PostgreSQL - postgresql

I am trying to relate an assosciative table with another table.
...
knex.schema.createTable("test", (table) => {
table.integer("subject_id").unsigned().references("id").inTable("subject").notNullable();
table.integer("duration_id").unsigned().references("id").inTable("duration").notNullable();
table.unique(["subject_id", "duration_id"]);
}),
knex.schema.createTable("exam", (table) => {
table.increments().notNullable();
table.integer("subject_id").unsigned();
table.integer("duration_id").unsigned();
...
...
table.foreign(["subject_id", "duration_id"]).references(["subject_id", "duration_id"]).inTable("test");
}),
...
throws the following error:
migration failed with error: alter table "exam" add constraint "exam_subject_id_duration_id_foreign" foreign key ("subject_id", "duration_id") references "test" ("subject_id", "duration_id")
- there is no unique constraint matching given keys for referenced table "test"
Having unique or primary key constraint for the two columns results in the same error. Is this a knex related error?

Moving the foreign key constraint after the unique constraint fixed the problem. Though I don't know the exact reason.
...
knex.schema.createTable("test", (table) => {
table.integer("subject_id").unsigned().notNullable();
table.integer("duration_id").unsigned().notNullable();
table.unique(["subject_id", "duration_id"]);
table.foreign("subject_id").references("id").inTable("subject");
table.foreign("duration_id").references("id").inTable("duration");
}),
knex.schema.createTable("exam", (table) => {
table.increments().notNullable();
table.integer("subject_id").unsigned();
table.integer("duration_id").unsigned();
...
...
table.foreign(["subject_id", "duration_id"]).references(["subject_id", "duration_id"]).inTable("test");
}),
...

Related

Change primary key and its (foreign) references in existing table - Knex.js / Postgres

My Postgres DB has 2 tables, with thousands of rows each, that were initially created with the following migration:
exports.up = async function(knex, Promise) {
// users
await knex.schema.createTable('users', table => {
table.increments('id');
table.timestamps(false, true);
table.text('uid').notNullable().unique(),
table.text('email').notNullable();
table.text('password');
table.text('first_name').notNullable();
table.text('last_name').notNullable();
table.text('subscription_id');
table.boolean('is_active').notNullable().defaultTo(true);
table.boolean('is_blocked').notNullable().defaultTo(false);
table.enum('role', ['member', 'admin', 'test_user']).notNullable().defaultTo('member');
});
await knex.schema.raw('create unique index users_lower_email_index on users (lower(email))');
// projects
await knex.schema.createTable('projects', table => {
table.increments('id');
table.timestamps(false, true);
table.text('name').notNullable();
table.integer('user_id').notNullable().references('users.id').onDelete('cascade');
table.text('data');
});
};
I need to change the foreign key on the projects table so that it references the uid column instead from the users table.
The constraints on the users table are:
I tried the following migration but I get the error:
migration failed with error: alter table "users" add column "uid" text - column "uid" of relation "users" already exists
My code:
exports.up = async function(knex, Promise) {
await knex.schema.alterTable('users', table => {
table.text('uid').primary('users_pkey');
})
await knex.schema.alterTable('projects', table => {
table.text('user_id').notNullable().references('users.uid').onDelete('cascade').alter();
});
};
I also tried table.text('uid').primary('users_pkey').alter(); but then I get:
migration failed with error: alter table "users" add constraint "users_pkey" primary key ("uid") - multiple primary keys for table "users" are not allowed
I will transfer all users in auth0 and I though its better if I use a UUID primary key for the users table.
Before you can change the primary key of users, you need to remove the existing one, then you should be able to drop and recreate the foreign key in projects:
exports.up = async (knex) => {
await knex.schema.alterTable('users', (table) => {
table.dropPrimary()
table.primary('uid')
})
await knex.schema.alterTable('projects', (table) => {
table.dropForeign('user_id')
table.foreign('user_id').references('users.uid').onDelete('cascade')
})
}

Knex : Altering Primary Key Id column Error

The database is built on Knex / PostgreSQL.
I would like to alter a table to add 'unique()' type to primary key Id column.
But Migration failed with an error message below.
alter table "users" alter column "id" drop not null - column "id" is
in a primary key
exports.up = knex =>
knex.schema
.raw('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"')
.createTable('users', table => {
table
.uuid('id')
.primary()
.notNullable()
.defaultTo(knex.raw('uuid_generate_v4()'));
table
.string('companyName')
.unique()
.notNullable();
table
.string('username')
.unique()
.notNullable();
table.string('password').notNullable();
table.string('contactNo').notNullable();
table.string('email').unique();
table.string('address');
table
.boolean('isAdmin')
.notNullable()
.defaultTo(false);
table
.enum('businessType', ['catering', 'restaurant'])
.defaultTo('catering');
table.integer('lunchQty').defaultTo(null);
table.integer('dinnerQty').defaultTo(null);
table
.uuid('bankAccountId')
.references('id')
.inTable('bank_account')
.onDelete('SET NULL')
.onUpdate('RESTRICT')
.index();
table.string('resetPasswordToken');
table.timestamps(true, true);
});
exports.down = knex => knex.schema.dropTable('users');
exports.up = knex =>
knex.schema.alterTable('users', table => {
table
.uuid('id')
.unique()
.primary()
.notNullable()
.defaultTo(knex.raw('uuid_generate_v4()'))
.alter();
});
exports.down = knex =>
knex.schema.table('users', table => {
table.dropColumn('id').alter();
});
PostgreSQL version : 11.1
Knex version : 0.19.2
I have searched here and there but couldn't find an answer for this issue.
Thanks for taking your time to help me out !
------------------------------ EDITION -----------------------------------
Qustion ) when I created delivery table like below. The error below accurred. I thought this was caused because I didn't set primary key unique.
migration failed with error: alter table "delivery" add constraint
"delivery_userid_foreign" foreign key ("userId") references "users"
("id") on update RESTRICT on delete CASCADE - there is no unique
constraint matching given keys for referenced table "users"
exports.up = knex =>
knex.schema
.raw('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"')
.createTable('delivery', table => {
table
.uuid('id')
.primary()
.notNullable()
.defaultTo(knex.raw('uuid_generate_v4()'));
table
.uuid('routeId')
.references('id')
.inTable('routes')
.onDelete('CASCADE')
.onUpdate('RESTRICT')
.index();
table
.uuid('userId')
.references('id')
.inTable('users')
.onDelete('CASCADE')
.onUpdate('RESTRICT')
.index();
table.timestamps(true, true);
});
exports.down = knex => knex.schema.dropTable('delivery');
```
Primary keys are already unique and not null: there is no need for your alteration. See documentation. Knex is trying to do what you ask, but in order to alter the table it would have to drop id which is in a PRIMARY KEY constraint.
resolved the issue by removing alter users file !!
the 'unique key()' was the one that was causing the problem.

Adding column with foreign key into table.

I have some problem. I want to add new column into my table that references to other column in other table. I do something like that:
class m161202_153033_dodanie_informacji_o_obsludze_prawnej_do_pozyczki extends CDbMigration
{
public function safeUp()
{
$this->execute("ALTER TABLE loan ADD COLUMN administrator int NOT NULL DEFAULT 15 REFERENCES person (id) ON UPDATE CASCADE ON DELETE NO ACTION;");
}
public function safeDown()
{
$this->execute("ALTER TABLE loan DROP COLUMN administrator;");
}
}
But when i try to execute this migration i have this error:
Foreign key violation: 7
DETAIL: Key (administrator)=(15) doesn't appear in table "person"..
I know that there is no suck column "administrator" in my table. But i want to add new column "administrator" into loan table. I wanted to make "administrator" foreign key from person table, column "id". Can u help me, what am i doing wrong?
The error means that there is no row in person with id equal to 15, which would be required for the constraint to be fulfilled.
When you run that ALTER TABLE statement, the table has to be rewritten, and the new column is filled with the value 15.
Often it is easier to create a new column nullable and without default value (then ALTER TABLE will not rewrite the table) and use UPDATE to populate the new column. After that you can change the column definition to NOT NULL and add a default value.
Try this
class m161202_153033_dodanie_informacji_o_obsludze_prawnej_do_pozyczki extends CDbMigration
{
public function safeUp()
{
$this->execute("INSERT INTO person (id) VALUES (15) ON CONFLICT (id) DO NOTHING;");
$this->execute("ALTER TABLE loan ADD COLUMN administrator int NOT NULL DEFAULT 15 REFERENCES person (id) ON UPDATE CASCADE ON DELETE NO ACTION;");
}
public function safeDown()
{
$this->execute("ALTER TABLE loan DROP COLUMN administrator;");
}
}

Sequelize Duplicate Key Constraint Violation

I am trying to add a many to many relationship through an explicitly created junction table using Sequelize and Postgresql.
The tables on either side of the relationship are associated like this:
Shop.belongsToMany(models.user, {through: 'visits' })
User.belongsToMany(models.shop, {through: 'visits' })
And the visits junction table primary key is defined like this:
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true // Automatically gets converted to SERIAL for postgres
}
When I try and insert into visits I get the following error:
ERROR: duplicate key value violates unique constraint "visits_shopId_userId_key"
DETAIL: Key ("shopId", "userId")=(1, 12) already exists.
After doing a pg_dump, I have tried to remove the composite key constraint by adding constraint: false to the models, but I still get the error.
(I have dropped the tables and resynced several times during the debugging process)
After digging around the Sequelize issues, it turns out that removing the constraint on the N:M composite key is an easy fix.
The through key can take an object with the unique: false property:
Shop.belongsToMany(models.user, {
through: {
model: 'visits',
unique: false
},
constraints: false
});

dead-lock scenario in grails when trying to do ORM

I am writing a simple grails (2.3.1) sample application which uses postgresql(9.1)
I have two domain classes 'Nose' and 'Face'.
//Nose class
package human
class Nose {
static belongsTo=[face:Face]
static constraints = {
face nullable: true
}
}
//Face class
package human
class Face {
static hasOne = [nose:Nose];
static constraints = {
nose nullable: true
}
}
My database is empty and I am using static scaffold.
Now, grails does not allow me to insert into either, because one has foreign key constraint with other.
Also, when i try to insert directly in the postgresql database, i get the same foreign key constraint error:
human=# insert into nose (id, version, face_id) values (1, 0, 1);
ERROR: insert or update on table "nose" violates foreign key constraint "fk33afd3c47bf8db"
DETAIL: Key (face_id)=(1) is not present in table "face".
OR
human=# insert into face (id, version, nose_id) values (1, 0, 1);
ERROR: insert or update on table "face" violates foreign key constraint "fk2fd65d8476fd1b"
DETAIL: Key (nose_id)=(1) is not present in table "nose".
human=#
How to resolve this dead-lock condition ?