Oracle constraint / unique index: check if the query has no result - then you can insert the line - sql

I did something similar in the past for the purpose of limiting the range of cells:
ALTER TABLE "CES"."NS_CES" ADD CONSTRAINT "CHECK_OVER_DIAPAZON" CHECK (
(ID_NS_WORK != 1835 AND ID_NS_WORK != 1833) OR
(ID_NS_WORK = 1835 and PNS BETWEEN 0 AND 100 and QNS BETWEEN -200 AND 10) OR
(ID_NS_WORK = 1833 and PNS BETWEEN 0 AND 100 and QNS BETWEEN -200 AND 10)
);
But now I've got different task: add constraint, which will check the result of the query does not return any value.
This is my select, which must return no value, and which I want to create as check constraint for the table Training_rule:
select type, training_list_id, element_id, request_code
from training_rule
where after_rule is null and after_group is null
group by type, training_list_id, element_id, request_code
having count(*) > 1;
Something like this:
ALTER TABLE "CES"."TRAINING_RULE" ADD CONSTRAINT "CHEK_SELECT_HAS_NO_RESULT" CHECK (
^HAS NO RESULT^:
[
select type, training_list_id, element_id, request_code
from training_rule
where after_rule is null and after_group is null
group by type, training_list_id, element_id, request_code
having count(*) > 1;
]
)
Thanks
Edit 1
It works, thanks to Gordon Linoff
create unique index idx_trainingrule_4 on TRAINING_RULE (
type, training_list_id, element_id, request_code,
(case when after_rule is null and after_group is null then null
else name
end)
);

I think you can do what you want with a conditional unique index. This assumes that you have a unique id column in the table (trainingrule_id) that is never negative:
create unique index idx_trainingrule_4 on (
type, training_list_id, element_id, request_code,
(case when after_rule is null and after_group is null then -1
else trainingrule_id
end)
);

You cannot do it like that. The ADD CHECK CONSTRAINT:
A check constraint can NOT be defined on a SQL View.
The check constraint defined on a table must refer to only columns in that table. It can not refer to columns in other tables.
A check constraint can NOT include a SQL Subquery.
A check constraint can be defined in either a SQL CREATE TABLE statement or a SQL ALTER TABLE statement.
The reason why it was working previously was because you were applying the constraint on a column value which is syntactically correct. But the latter is not the correct syntax and is not allowed.

Related

How to check for clustered unique key while inserting in SQL table

I am trying to insert rows from another database table to new database table getting the below error if there is no where condition in the query.
Violation of UNIQUE KEY constraint 'NK_LkupxViolations'. Cannot insert duplicate key in object 'dbo.LkupxViolation'. The duplicate key value is (00000000-0000-0000-0000-000000000000, (Not Specified)).
Then I wrote the below query adding where conditions it worked but it didn't insert the expected no. of rows.
IF EXISTS(SELECT 1 FROM sys.tables WHERE name = 'LkupxViolation')
BEGIN
INSERT INTO dbo.[LkupxViolation] SELECT * FROM [DMO_DB].[dbo].[LkupxViolation] where CGRootId not in (select CGRootId from dbo.[LkupxViolation])
and Name not in (select name from dbo.[LkupxViolation])
END
ELSE
PRINT 'LkupxViolation table does not exist'
The unique key in the table is created as:
CONSTRAINT [NK_LkupxViolations] UNIQUE CLUSTERED
(
[CGRootId] ASC,
[Name] ASC
)
Try using NOT EXISTS:
INSERT INTO dbo.[LkupxViolation]
SELECT *
FROM [DMO_DB].[dbo].[LkupxViolation] remove_l
WHERE NOT EXISTS (SELECT 1
FROM dbo.[LkupxViolation] local_l
WHERE local_l.Name = remote_l.Name AND
local_l.CGRootId = remote_l.CGRootId
);
This checks for both values in the same row. In addition, NOT IN is not NULL-safe. If any values generated by the subquery are NULL then all rows are filtered out.

Check for uniqueness of column in postgres table

I need to ensure that the values in a column from a table are unique as part of a larger process.
I'm aware of the UNIQUE constraint, but I'm wondering if there is a better way to do the check.
I'm running the queries using psycopg2 so adding that tag on the off chance there's something in there that can help with this.
If the column is unique I can add a constraint. If the column is not unique adding the constraint will return an error.
If there is already a constraint of the same name a useful error is returned. in this case would prefer to just check for the existing constraint.
If the column is the primary key, the unique constraint can be added without error but in this case it would be preferable to just recognize that the column must be unique based on the primary key.
Code examples of this below.
DROP TABLE IF EXISTS unique_test;
CREATE TABLE unique_test (
pkey INT PRIMARY KEY,
unique_yes CHAR(1),
unique_no CHAR(1)
);
INSERT INTO unique_test (pkey, unique_yes, unique_no)
VALUES(1, 'a', 'a'),
(2, 'b', 'a');
CREATE UNIQUE INDEX CONCURRENTLY u_test_1 ON unique_test (unique_yes);
ALTER TABLE unique_test
ADD CONSTRAINT unique_target_1
UNIQUE USING INDEX u_test_1;
-- the above runs no problem
-- check what happens when column is not unique
CREATE UNIQUE INDEX CONCURRENTLY u_test_2 ON unique_test (unique_no);
ALTER TABLE unique_test
ADD CONSTRAINT unique_target_2
UNIQUE USING INDEX u_test_2;
-- returns:
-- SQL Error [23505]: ERROR: could not create unique index "u_test_2"
-- Detail: Key (unique_no)=(a) is duplicated.
CREATE UNIQUE INDEX CONCURRENTLY u_test_1 ON unique_test (unique_yes);
ALTER TABLE unique_test
ADD CONSTRAINT unique_target_1
UNIQUE USING INDEX u_test_1;
-- returns
-- SQL Error [42P07]: ERROR: relation "unique_target_1" already exists
-- test what happens if adding constrint to primary key column
CREATE UNIQUE INDEX CONCURRENTLY u_test_pkey ON unique_test (pkey);
ALTER TABLE unique_test
ADD CONSTRAINT unique_target_pkey
UNIQUE USING INDEX u_test_pkey;
-- this runs no problem but is inefficient.
If all you want to do is verify that values are unique, then use a query:
select unique_no, count(*)
from unique_test
group by unique_no
having count(*) > 1;
If it needs to be boolean output:
select not exists (
select unique_no, count(*)
from unique_test
group by unique_no
having count(*) > 1
);
If you just want a flag, you can use:
select count(*) <> count(distinct uniq_no) as duplicate_flag
from unique_test;
DELETE FROM
zoo x
USING zoo y
WHERE
x.animal_id < y.animal_id
AND x.animal = y.animal;
I think this is simpler, https://kb.objectrocket.com/postgresql/delete-duplicate-rows-in-postgresql-762 for reference

Check constraint to prevent 2 or more rows from having numeric value of 1

I have a SQL table with a column called [applied], only one row from all rows can be applied ( have the value of 1) all other rows should have the value 0
Is there a check constraint that i can write to force such a case?
If you use null instead of 0, it will be much easier.
Have a CHECK constraint to make sure the (non-null) value = 1. Also have a UNIQUE constraint to only allow a single value 1.
create table testtable (
id int primary key,
applied int,
constraint applied_unique unique (applied),
constraint applied_eq_1 check (applied = 1)
);
Core ANSI SQL, i.e. expected to work with any database.
Most databases support filtered indexes:
create unique index unq_t_applied on t(applied) where applied = 1;
To know exactly how to write trigger that will help you an info of a database you use is needed.
You wil need a trigger where this will be your test control:
SELECT COUNT(APPLIED)
FROM TEST
WHERE APPLIED = 1
If it is > 0 then do not allow insert else allow.
While this can be done with triggers and constraints, they probably require an index. Instead, consider a join table.
create table things_applied (
id smallint primary key default 1,
thing_id bigint references things(id) not null,
check(id = 1)
);
Because the primary key is unique, there can only ever be one row.
The first is activated with an insert.
insert into things_applied (thing_id) values (1);
Change it by updating the row.
update things_applied set thing_id = 2;
To deactivate completely, delete the row.
delete things_applied;
To find the active row, join with the table.
select t.*
from things t
join things_applied ta on ta.thing_id = t.id
To check if it's active at all, count the rows.
select count(id) as active
from things_applied
Try it.

How can I ensure that Column_A can only have a value if Column_B is NULL? And vice versa

I'm attempting to create a table that has three columns:
id
paid_at
failed_at
How can I make sure that paid_at can only have a value if failed_at is NULL?
Here is my current code:
CREATE TABLE charges(
id TEXT NOT NULL PRIMARY KEY,
paid_at TEXT,
failed_at TEXT
);
ALTER TABLE charges
ADD CONSTRAINT paid_at CHECK (failed_at IS NULL);
ALTER TABLE charges
ADD CONSTRAINT failed_at CHECK (paid_at IS NULL);
I also want to make sure that BOTH cannot be null.
How can I do this?
Thanks!
You can use num_nonnulls() in the check constraint:
alter table charges
add constraint only_one_not_null
check (num_nonnulls(paid_at, failed_at) = 1);
That ensure that exactly one of the columns is not null and the other is null.
If you consider a string with only spaces to be "null" as well, you could extend that to:
alter table charges
add constraint only_one_not_null
check (num_nonnulls(nullif(trim(paid_at),''), nullif(trim(failed_at),'')) = 1);
I am inclined to do this with addition. To check that one of a group of columns is not null, count the number of not-null values:
check ( (paid_at is not null)::int + (failed_at is not null)::int) > 0 )
You can use the following predicate:
alter table charges add constraint exclusive_rule check (
paid_at is null and failed_at is not null or
paid_at is not null and failed_at is null
);

Alter Table add check for nulls and not nulls

I am using Oracle Express, and I'd like to make a statement to add a check constraint to my Invoices table that allows Payment_Date to be NULL if Payment_Total = 0, AND Payment_Date to be NOT NULL if Payment_Total > 0.
I only understand how to alter a table to add a constraint that checks that a column's value. I don't understand how to make constraints that Allow null values or disallow null values if a certain condition (ColumnValue > SomeValue) is met.
Here is how you can express the check constraint:
alter table t add constraint ck_values
check ((payment_date is null and payment_total = 0) or
(payment_date is not null and payment_total > 0)
);