DDL: SQL Question Check Constraint on multiple columns - sql

create table Game(
isOn boolean,
playHour int,
isOff boolean,
constraint ck_isOn_hour check ( ? )
);
Constraint : playHour is NULL when isOn = FALSE
Replace the '?' symbol with a valid check for the given constraint.
Any help is much appreciated.

This should do it:
constraint ck_isOn_hour check (isOn or (playHour is null and not isOn))
This can be simplified:
constraint ck_isOn_hour check (isOn or playHour is NULL)

Related

SQL - How do you use a user defined function to constrain a value between 2 tables

First here's the relevant code:
create table customer(
customer_mail_address varchar(255) not null,
subscription_start date not null,
subscription_end date, check (subscription_end !< subcription start)
constraint pk_customer primary key (customer_mail_address)
)
create table watchhistory(
customer_mail_address varchar(255) not null,
watch_date date not null,
constraint pk_watchhistory primary key (movie_id, customer_mail_address, watch_date)
)
alter table watchhistory
add constraint fk_watchhistory_ref_customer foreign key (customer_mail_address)
references customer (customer_mail_address)
on update cascade
on delete no action
go
So i want to use a UDF to constrain the watch_date in watchhistory between the subscription_start and subscription_end in customer. I can't seem to figure it out.
Check constraints can't validate data against other tables, the docs say (emphasis mine):
[ CONSTRAINT constraint_name ]
{
...
CHECK [ NOT FOR REPLICATION ] ( logical_expression )
}
logical_expression
Is a logical expression used in a CHECK constraint and returns TRUE or
FALSE. logical_expression used with CHECK constraints cannot
reference another table but can reference other columns in the same
table for the same row. The expression cannot reference an alias data
type.
That being said, you can create a scalar function that validates your date, and use the scalar function on the check condition instead:
CREATE FUNCTION dbo.ufnValidateWatchDate (
#WatchDate DATE,
#CustomerMailAddress VARCHAR(255))
RETURNS BIT
AS
BEGIN
IF EXISTS (
SELECT
'supplied watch date is between subscription start and end'
FROM
customer AS C
WHERE
C.customer_mail_address = #CustomerMailAddress AND
#WatchDate BETWEEN C.subscription_start AND C.subscription_end)
BEGIN
RETURN 1
END
RETURN 0
END
Now add your check constraint so it validates that the result of the function is 1:
ALTER TABLE watchhistory
ADD CONSTRAINT CHK_watchhistory_ValidWatchDate
CHECK (dbo.ufnValidateWatchDate(watch_date, customer_mail_address) = 1)
This is not a direct link to the other table, but a workaround you can do to validate the date. Keep in mind that if you update the customer dates after the watchdate insert, dates will be inconsistent. The only way to ensure full consistency in this case would be with a few triggers.

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
);

Missing Right Parenthesis in SQL

I'm new to learning SQL. When I create this table, it has an Asterix (*) under the first parenthesis of the "(dbClassID)" and says "missing right parenthesis"
Does anyone know why it does that and how I can fix it?
CREATE TABLE vod_classification (
dbClassId CHAR(4) NOT NULL,
dbDescription VARCHAR2(100)
CONSTRAINT vod_classification_PK PRIMARY KEY (dbClassId)
);
CONSTRAINT is part of table creation and need to be comma delimited as other column:
CREATE TABLE zz_classification (
dbClassId CHAR(4) NOT NULL,
dbDescription VARCHAR2(100),
CONSTRAINT vod_classification_PK PRIMARY KEY( dbClassId)
);
Tables contain columns and constraints
you are missing , here try this VARCHAR2(100),
For a single-column constraint, it's neater to define it inline as part of the column:
create table vod_classification
( dbclassid varchar2(4) not null constraint vod_classification_pk primary key
, dbdescription varchar2(100) not null constraint vod_classification_uk unique
);
I have corrected the CHAR column to the standard string type which is VARCHAR2 in Oracle.
(PK columns will be not null automatically, but I've left it in for completeness and in case you later create table as select.)
When using the "Create" code, you must use a comma in the line where you define each column of the table. Except the last column. You can read the oracle sql syntax link as follows: https://docs.oracle.com/cd/E11882_01/server.112/e41085/sqlqr01001.htm#SQLQR110

Adding an one-out-of-two not null constraint in postgresql

If I have a table in Postgresql:
create table Education (
id integer references Profiles(id),
finished YearValue not null,
started YearValue,
qualification text,
schoolName text,
studiedAt integer references Organizations(id),
primary key (id)
);
I need to make a constraint so that either schoolName or studiedAt needs to not be null (one of them has to have information in it).
How do I do this?
You can use a check constraint e.g.
constraint chk_education check (schoolName is not null or studiedAt is not null)
From the manual:
A check constraint is the most generic constraint type. It allows you to specify that the value in a certain column must satisfy a Boolean (truth-value) expression.
Edit: Alternative to comply with Pithyless' interpretation:
constraint chk_education check ((schoolName is not null and studiedAt is null) or (schoolName is null and studiedAt is not null))
You can also use a trigger on update and insert to check that a rule is followed before allowing the data into the table. You would normally use this type of approach when the check constraint needs more complicated logic.
This is my solution for sequelize migration file in "up" function
queryInterface.addConstraint('Education', {
fields: ['schoolName', 'studiedAt'],
type: 'check',
name: 'schoolName_or_studiedAt_is_null',
where: { [Sequelize.Op.or]: [{ password: null }, { googleId: null }] },
}),

CHECK CONSTRAINT on multiple columns

I use SQL Server 2008
I use a CHECK CONSTRAINT on multiple columns in the same table to try to validate data input.
I receive an error:
Column CHECK constraint for column
'AAAA' references another column,
table 'XXXX'.
CHECK CONSTRAINT does not work in this way.
Any other way to implement this on a single table without using FK?
Thanks
Here an example of my code
CREATE TABLE dbo.Test
(
EffectiveStartDate dateTime2(2) NOT NULL,
EffectiveEndDate dateTime2(2) NOT NULL
CONSTRAINT CK_CmsSponsoredContents_EffectiveEndDate CHECK (EffectiveEndDate > EffectiveStartDate),
);
Yes, define the CHECK CONSTRAINT at the table level
CREATE TABLE foo (
bar int NOT NULL,
fred varchar(50) NOT NULL,
CONSTRAINT CK_foo_stuff CHECK (bar = 1 AND fred ='fish')
)
You are declaring it inline as a column constraint
...
fred varchar(50) NOT NULL CONSTRAINT CK_foo_fred CHECK (...)
...
Edit, easier to post than describe. Fixed your commas.
CREATE TABLE dbo.Test
(
EffectiveStartDate dateTime2(2) NOT NULL,
EffectiveEndDate dateTime2(2) NOT NULL, --need comma
CONSTRAINT CK_CmsSponsoredContents_EffectiveEndDate CHECK (EffectiveEndDate > EffectiveStartDate) --no comma
);
Of course, the question remains are you using a CHECK constraint where it should be an FK constraint...?
Check constraints can refer to a single column or to the whole record.
Use this syntax for record-level constraints:
ALTER TABLE MyTable
ADD CONSTRAINT MyCheck
CHECK (...your check expression...)
You can simply apply your validation in a trigger on the table especially that either way the operation will be rolled back if the check failed.
I found it more useful for CONSTRAINT using case statements.
ALTER TABLE dbo.ProductStock
ADD
CONSTRAINT CHK_Cost_Sales
CHECK ( CASE WHEN (IS_NOT_FOR_SALE=0 and SAL_CPU <= SAL_PRICE) THEN 1
WHEN (IS_NOT_FOR_SALE=1 ) THEN 1 ELSE 0 END =1 )