Check Constraints in SQL - sql-server

I want not to allow my DB user to enter bigger dates than 2017-03-18. How can add this constraint to my table?
Is this Correct?
(Year([ContractEnd])<2017) and (Month([ContractEnd])<03) and (Day([ContractEnd])<18)

You can add a constraint like that to an existing table like so:
alter table t add constraint chk_ContractEnd_lt_20170319
check (ContractEnd<'20170319');
rextester demo: http://rextester.com/FQWFMI88817
create table t (
id int not null identity(1,1)
, ContractEnd date
/* at table creation */
, constraint chk_ContractEnd_lt_20170319 check (ContractEnd<'20170319')
)
alter table t drop constraint chk_ContractEnd_lt_20170319;
/* to existing table */
alter table t add constraint chk_ContractEnd_lt_20170319
check (ContractEnd<='20170318');
insert into t values ('20161231')
insert into t values ('20170318')
/* all good */
insert into t values ('20170319')
/* -- Error, constraint violation */

Try
[ContractEnd] DATE CHECK ([ContractEnd] <= '20170318')

Related

How to alter a column in HANA DB to be incremented, after that table was already created?

I want to have a table with this properties:
CREATE TABLE status
(
identificationnumber BIGINT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
desc varchar(10)
);
Suddenly the production table was already created and has a enormous amount of data. Schema that is already in use:
CREATE TABLE status
(
identificationnumber BIGINT NOT NULL PRIMARY KEY,
desc varchar(10)
);
Is it possible to update the schema with an autoincrement?
Technically it is possible, but may depend on the size of data. You can check it by yourself at TEST/QAS system and then apply the change to production.
Here's the code I used:
/*Create example table*/
create column table tst_tab (
x int
);
/*Fill it with some data*/
insert into tst_tab
select 1 from dummy union all
select 2 from dummy union all
select 3 from dummy
;
/*Add identity column*/
alter table tst_tab
add(id int generated by default as identity);
/*Statement 'alter table tst_tab add(id int generated by default as identity)'
successfully executed in 14 ms 281 µs*/
/*Check results*/
select * from tst_tab;

T-SQL crazy function result

I have this function:
CREATE FUNCTION CheckAkvNames (#Name VARCHAR(20))
RETURNS INT
AS
BEGIN
DECLARE #NoTexist int = 1
SELECT
#NoTexist = CASE WHEN COUNT(*) > 0 THEN 0 ELSE 1 END
FROM
[dbo].[Names]
WHERE
[Name] = #Name
RETURN #NoTexist
END
GO
ALTER TABLE [dbo].[Names]
ADD CONSTRAINT chkNames CHECK(dbo.CheckAkvNames([Name]) = 1);
GO
The problem is, when I run this on empty table I can't insert ...
So this change works:
CASE WHEN (COUNT(*) - 1) > 0 THEN 0 ELSE 1 END
WHY? Any ideas?
Edit:
Aim is to insert only names that are not in the table. I know it would be better to use key, point of the question is not to find better solution but why this solution does not work.
The constraint you added to the table actually means that you can't insert any name in the table, because for any value inserted in the table the function should return 1.This is impossible because if the name was inserted then the constraint would be violated.
This is why count(*) - 1 works: if there is already a name inserted and you tried to insert the same name then the constraint would be violated.
If you want unique names in a table, do not use a check constraint, use a unique constraint (or equivalently a unique index):
ALTER TABLE [dbo].[Names]
ADD CONSTRAINT unq_names_name UNIQUE (Name);

How add partitions and Incremental Update Statistics to existing table by

I have a table with data. Table was created by this code:
create table [tmp].[Test]
(
[RecordId] bigint not null
,[DateId] int not null
,[CustomerId] int not null
);
alter table [tmp].[Test]
add constraint [PK_REP_51671] primary key ([RecordId])
I have partition function and partition scheme:
CREATE PARTITION FUNCTION PartitionByYear_function(int)
AS RANGE RIGHT
FOR VALUES(
20130101
,20140101
,20150101
,20160101
,20170101
,20180101
,20190101
,20200101
,20210101
,20220101
,20230101
,20240101
,20250101
,20260101
,20270101
,20280101
,20290101
,20300101
,20310101
,20320101
,20330101
,20340101
,20350101
,20360101
,20370101
,20380101
,20390101
,20400101
,20410101
,20420101
,20430101
,20440101
,20450101
,20460101
,20470101
,20480101
,20490101
,20500101
,20510101
,20520101
,20530101
,20540101
,20550101
,20560101
,20570101
,20580101
,20590101
,20600101
);
GO
CREATE PARTITION SCHEME PartitionByYear_Scheme
AS PARTITION PartitionByYear_function
ALL TO ([PRIMARY])
GO
But I don't know how to add partitions to table Test and how to enable Incremental Update Statistics by alter. I know how to add this things to new table by create but how can I add parttitions and statistics to existing table with data by alter?
You have everything prepared. You should recreate your table using the partition schema:
create table [tmp].[Test]
(
[RecordId] bigint not null
,[DateId] int not null
,[CustomerId] int not null
)on PartitionByYear_Scheme([DateId]);

How to create a column null or not-null dependent on the value of another column?

I'm using database first approach with EF core and trying to figure out a clean solution to the below problem -
Consider a Student attendance table (irrelevant columns removed) below that stores date of class and allows the student to enter his class rating -
create table Student (
Id int Identity(1, 1) not null,
ClassDate smalldatetime not null,
ClassRatingByStudent varchar(250) not null
)
This is a webapp where school attendance system automatically populates the above table at EOD and then the student (let's say a few days later) is required to add class ratings. When the table is populated by the school attendance system, there is nothing in the ClassRatingByStudent column. Then when the student logs in, he must add the rating.
As you see, ClassRatingByStudent must be null when the school attendance system populates the table and must be not-null when the student saves his changes. One obvious solution is make ClassRatingByStudent column nullable ad handle it in the code but I'm wondering if there is a neater database (or maybe EF) level solution exists or some sort of pattern/architecture guidelines for this type of scenarios?
I don't know but maybe CHECK constraint could help you:
CREATE TABLE TestTable(
ID int NOT NULL IDENTITY,
RatingAllowed bit NOT NULL DEFAULT 0, -- switcher
RatingValue varchar(250),
CONSTRAINT PK_TestTable PRIMARY KEY(ID),
CONSTRAINT CK_TestTable_RatingValue CHECK( -- constraint
CASE
WHEN RatingAllowed=0 AND RatingValue IS NULL THEN 1
WHEN RatingAllowed=1 AND RatingValue IS NOT NULL THEN 1
ELSE 0
END=1
)
)
INSERT TestTable(RatingAllowed,RatingValue)VALUES(0,NULL)
INSERT TestTable(RatingAllowed,RatingValue)VALUES(1,'AAA')
-- The INSERT statement conflicted with the CHECK constraint "CK_TestTable_RatingValue"
INSERT TestTable(RatingAllowed,RatingValue)VALUES(0,'AAA')
INSERT TestTable(RatingAllowed,RatingValue)VALUES(1,NULL)
I found a variant how to check using another table as switcher
CREATE TABLE TableA(
ID int NOT NULL IDENTITY PRIMARY KEY,
StudentID int NOT NULL,
Grade int
)
CREATE TABLE TableB(
StudentID int NOT NULL PRIMARY KEY
)
GO
-- auxiliary function
CREATE FUNCTION GradeIsAllowed(#StudentID int)
RETURNS bit
BEGIN
DECLARE #Result bit=CASE WHEN EXISTS(SELECT * FROM TableB WHERE StudentID=#StudentID) THEN 1 ELSE 0 END
RETURN #Result
END
GO
-- constraint to check
ALTER TABLE TableA ADD CONSTRAINT CK_TableA_Grade CHECK(
CASE dbo.GradeIsAllowed(StudentID) -- then we can use the function here
WHEN 1 THEN CASE WHEN Grade IS NOT NULL THEN 1 ELSE 0 END
WHEN 0 THEN CASE WHEN Grade IS NULL THEN 1 ELSE 0 END
END=1)
GO
-- Tests
INSERT TableB(StudentID)VALUES(2) -- allowed student
INSERT TableA(StudentID,Grade)VALUES(1,NULL) -- OK
INSERT TableA(StudentID,Grade)VALUES(2,5) -- OK
INSERT TableA(StudentID,Grade)VALUES(1,4) -- Error
INSERT TableA(StudentID,Grade)VALUES(2,NULL) -- Error
INSERT TableB(StudentID)VALUES(1) -- add 1
UPDATE TableA SET Grade=4 WHERE StudentID=1 -- OK
UPDATE TableA SET Grade=NULL WHERE StudentID=1 -- Error

How to limit the length of an array in PostgreSQL?

Is there any way to add a constraint on a column that is an array to limit it's length? I want these arrays to be no longer than 6. And yes, I understand that often a new table is better than storing in an array but I am in a situation where an array makes more sense.
You can add a CHECK constraint to the table definition:
CREATE TABLE my_table (
id serial PRIMARY KEY,
arr int[] CHECK (array_length(arr, 1) < 7),
...
);
If the table already exists, you can add the constraint with ALTER TABLE:
ALTER TABLE my_table ADD CONSTRAINT arr_len CHECK (array_length(arr, 1) < 7);

Resources