POSTGRES - Handling several ON CONFLICT constraints/indexes - sql

Have the following in the table where:
CONSTRAINT unique_position UNIQUE (id,city,type)
and
CREATE UNIQUE INDEX unique_position_sat_null ON public."position" (id,city) where type is null
on insert conflict there is currently:
ON CONFLICT ON CONSTRAINT unique_position DO UPDATE SET
.....
How can I incorporate both unique_position and unique_position_sat_null into ON CONFLICT ON CONSTRAINT
Tried:
ON CONFLICT ON CONSTRAINT unique_position DO UPDATE SET
.....,
ON CONFLICT ON CONSTRAINT unique_position_sat_null DO UPDATE SET
.....,
and
ON CONFLICT ON CONSTRAINT unique_position and unique_position_sat_null DO UPDATE SET
.....,
Thank you.

Unfortunately, unique indexes and unique constraints are not the same things in Postgres.
When you define a unique index, not constraint, Postgres doesn't create a constraint with the same name (in case of collisions during INSERTs it will produce error "unique constraint violation" mentioning index' name, but this is a minor bug, see https://www.postgresql.org/message-id/flat/CAH2-Wzn-uXcLgC5uFbqe2rUfmJWP9AxKnMKAEgqU26hbURxk5A%40mail.gmail.com#CAH2-Wzn-uXcLgC5uFbqe2rUfmJWP9AxKnMKAEgqU26hbURxk5A#mail.gmail.com)
So you cannot use index name like it is a constraint name.
You could do ALTER TABLE .. ADD CONSTRAINT .. UNIQUE, but it cannot be unique.
So this can be considered as a not yet implemented feature in Postgres -- either "ON CONFLICT" clause needs to learn how to use index names or ALTER TABLE .. ADD CONSTRAINT .. UNIQUE needs to be patched to allow partial constraints.
I suggest discussing it in pgsql-hackers# mailing list (e.g. if you answer thread mentioned above, explaining your problem, it would be awesome).

Related

How to add check constraint on a column in table?

ALTER TABLE Student ADD CONSTRAINT CHK_Student_ID_LENGTH CHECK (LEN([ID]) between 12 and 14);
SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME = 'CHK_Student_ID_LENGTH';
alter table Student drop constraint CHK_Student_ID_LENGTH;
I tried to add check constraint using the first statement. It gave me the below error.
[23000][547] The ALTER TABLE statement conflicted with the CHECK constraint "CHK_Student_ID_LENGTH". The conflict occurred in database, table "Student", column 'ID'.
I tried to check if there was any existing constraint with the same name. But I did not get any. Still I tried to drop the constraint. But then it gave the error:
CHK_Student_ID_LENGTH is not a constraint.
But still add constraint statement gives error saying it already exists. Where am I going wrong?
The error message is a little badly worded, but isn't saying what you think it's saying.
It's not saying that there's already a constraint with the same name. It's saying that the constraint is being violated. That means that there is data already in the table that doesn't meet the requirements of the new constraint you're trying to introduce.
You could use the NOCHECK option to create the constraint whilst allowing existing data to violate it. But this is frequently the wrong thing to do. It is usually more sensible to fix the existing data.
Specifying NOCHECK means that the constraint can't be used by the optimizer to eliminate redundant actions that the logic of the constraint would preclude.
You probably have some records in Your table that conflict with that new constraint.
Just find them and UPDATE/DELETE before adding a contraint.
SELECT *
FROM Student
WHERE LEN([ID]) between 12 and 14
Or try to add that constraint without checking existing values using WITH NOCHECK
ALTER TABLE Student WITH NOCHECK
ADD CONSTRAINT CHK_Student_ID_LENGTH CHECK (LEN([ID]) between 12 and 14);
Tip: In migration files I usually add this before adding a new constraint:
IF OBJECT_ID('CHK_Student_ID_LENGTH') IS NOT NULL
ALTER TABLE Student DROP CONSTRAINT CHK_Student_ID_LENGTH
IF OBJECT_ID('CHK_Student_ID_LENGTH') IS NULL
ALTER TABLE Student ADD CONSTRAINT ...
More about ALTER TABLE https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-table-transact-sql?view=sql-server-ver15

Is there inconsistency in PostgreSQL syntax of adding constraints to a table?

From PostgreSQL document
To add a constraint, the table constraint syntax is used. For example:
ALTER TABLE products ADD CHECK (name <> '');
ALTER TABLE products ADD CONSTRAINT some_name UNIQUE (product_no);
ALTER TABLE products ADD FOREIGN KEY (product_group_id) REFERENCES product_groups;
To add a not-null constraint, which cannot be written as a table
constraint, use this syntax:
ALTER TABLE products ALTER COLUMN product_no SET NOT NULL;
Why the word after ADD differ for constraints of different kinds?
Why does unique constraint has a more generic ADD CONSTRAINT some_name than check and foreign key?
Why is not null constraint specified by ALTER COLUMN, instead of ADD CONSTRAINT some_name NOT NULL (col_name)?
Is there inconsistency in PostgreSQL syntax of adding constraints to a table?
Does this belong to the SQL standard?
The word after ADD differs so the database knows what you mean. E.g. CHECK introduces a generic boolean condition; UNIQUE is followed by a list of column names; FOREIGN KEY is followed by a column name, REFERENCES, and a target table/column. Without these keywords it would be ambiguous which kind of constraint you mean.
The CONSTRAINT constraint_name syntax is not limited to unique constraints. See the definition of column_constraint and table_constraint in https://www.postgresql.org/docs/10/static/sql-createtable.html; both allow an optional leading CONSTRAINT constraint_name to name the constraint.
As for NOT NULL, see https://www.postgresql.org/docs/10/static/ddl-constraints.html#id-1.5.4.5.6:
A not-null constraint is always written as a column constraint. A not-null constraint is functionally equivalent to creating a check constraint CHECK (column_name IS NOT NULL), but in PostgreSQL creating an explicit not-null constraint is more efficient. The drawback is that you cannot give explicit names to not-null constraints created this way.
I assume not-null constraints are a special case internally, allowing for better optimization than a generic CHECK constraint, which can use any boolean expression.
We cant use add constraint syntax for Not Null. You have to use modify column syntax to add not null
eg.
alter table modify ( not null);

SQLite option for ADD CONSTRAINT with ON CONFLICT REPLACE

SQLite doesn't support Add Constaints. I have the below SQL. How could I get that supported?
ALTER TABLE mytable ADD CONSTRAINT unique_hash UNIQUE (hash) ON CONFLICT REPLACE
Note: CREATE UNIQUE INDEX won't solve this problem of having ON CONFLICT REPLACE

Oracle SQL Foreign Key constraint that ignores null or historic values

I am trying to add a constrain to a database table that I want to modify. I want to add a constraint on a column so it references a primary key of another tables. Easy enough, I just have to add a foreign key constraint. The problem is that the column already has some values that are null or something that is not part of the table I will be referencing.
My question is how do I add a constraint that references a primary key but can also accept null values (the primary key always has a value) and how to ignore the existing values so far. Is it possible? If the second part is not, I am thinking I could always write a script that updates all the nonsense values (they have a format of sort if that I can reg ex) to null so they only thing I have to figure out is how to add a foreign key constraind that also accepts null values
Firstly, there's nothing stopping you from adding a referential constraint on a column that has NULLs - foreign key constraints are only enforced for non-NULL values.
Secondly, if there are existing values that do not exist in the parent table, and you can't fix them, you do have the option in Oracle to make the constraint only validated for newly inserted or updated rows, using the NOVALIDATE option, e.g.
ALTER TABLE x ADD CONSTRAINT fk FOREIGN KEY (id) REFERENCES parent (id) NOVALIDATE;
The only downside to using the NOVALIDATE option is that the query optimizer will not rely on the FK constraint, and will execute queries with the assumption that there may be rows that do not have a matching parent row.
It would be a good idea if you are able to fix the missing values, afterwards to alter the constraint to VALIDATE.
Primary keys can not contain NULL values in all databases (proof)
To add a foreign key you should do something like:
ALTER TABLE table1
ADD CONSTRAINT fk_table1_2
FOREIGN KEY (column1)
REFERENCES table2(column2);

Can you replace or update a SQL constraint?

I have written the following constraint for a column I've called 'grade':
CONSTRAINT gradeRule CHECK grade IN (‘easy’, ‘moderate’, ‘difficult’),
Is it possible to later update the gradeRule to have different values? For example, 'moderate' and 'difficult' could be changed to 'medium' and 'hard'.
Thanks
You could drop the existing constraint, and add the new constraint with the NOCHECK option. This would allow you to add the constraint even though data in the table violates the constraint. The problem with doing this though would be that you wouldn't be able to update existing records without making them pass the constraint first.
ALTER TABLE SomeTable DROP CONSTRAINT gradeRule
GO
ALTER TABLE SomeTable ADD CONSTRAINT gradeRule ... WITH NOCHECK
GO
Although this is possible, its not usually recommended because of the potential problems with future updates of the data.
Drop the constraint, and then add the replacement constraint.
You can't update a constraint in SQL Server at least.
ALTER TABLE SomeTable DROP CONSTRAINT gradeRule
In addition, you'll need to update the table data before adding the new constraint, so that it meets the new constraint.
If you change the constraint, all of the data currently in the table must meet the constraint. So if you had 2 rows of data with 'moderate' and tried to change the constraint to easy, medium, and hard, it would not let you.
So you would have to make the new constraint (easy, moderate, medium, difficult, hard) or, update the data to the new values - moderate --> medium etc.