Check constraint in SQL Server - sql

I have three tables a,b and c and need to add a constraint like below for checking the data integrity
The below is wrong but I need help in enforcing the below condition.
ALTER TABLE [a]
ADD CONSTRAINT UOMGROUPIG CHECK UNITOFMEASURID IN (SELECT UnitOfMeasureId FROM b WHERE UOMGroupId=1 )
ALTER TABLE [c]
ADD CONSTRAINT UOMGROUPIG CHECK UNITOFMEASURID IN (SELECT UnitOfMeasureId FROM b WHERE UOMGroupId=2 )
Thanks

A scalar valued function like this works for your example, you can easily modify it and create your second constraint:
CREATE FUNCTION your_schema_name.udf_Check1(
#UNITOFMEASURID INT
)
RETURNS BIT
AS
BEGIN
DECLARE #returnValue BIT = 0
SELECT #returnValue = CASE WHEN COUNT(UnitOfMeasureId) > 0 THEN 1 ELSE 0 END
FROM your_schema_name.b
WHERE UOMGroupId=1
AND #UNITOFMEASURID = UnitOfMeasureId
RETURN #returnValue
END
GO
ALTER TABLE [a]
ADD CONSTRAINT UOMGROUPIG
CHECK (your_schema_name.udf_Check1(UNITOFMEASURID) = 1)
GO
Here is the example: SQL Fiddle

You cannot write query within Check constraint. Instead you can call user defined function.
You can use same function in both constraints by passing #UOMGroupId value along with UNITOFMEASURID.
CREATE FUNCTION CheckFnctn(#UNITOFMEASURID int, #UOMGroupId int)
RETURNS int
AS
BEGIN
if exists(SELECT UnitOfMeasureId FROM b WHERE UOMGroupId=#UOMGroupId
and UnitOfMeasureId = #UNITOFMEASURID)
BEGIN
RETURN 1;
END
RETURN 0; --missed this line
END;
ALTER TABLE [a]
ADD CONSTRAINT UOMGROUPIG CHECK (dbo.CheckFnctn(UNITOFMEASURID, 1)=1);
ALTER TABLE [c]
ADD CONSTRAINT UOMGROUPIG CHECK (dbo.CheckFnctn(UNITOFMEASURID, 2)=1);

Related

Can't use UDF as constraint in MariaDB

I'm running MariaDB 10.3.17 and I'm trying to add a constraint to an existing table. The constraint uses a UDF - which should be allowed.
Here's my table and UDF.
CREATE OR REPLACE TABLE real_estate.sample_two_expected_output (
u_id int (9) NOT NULL,
first_date date NOT NULL,
last_date date NOT NULL,
days int AS (DATEDIFF(last_date,first_date)+1),
address varchar(50),
price varchar(50),
--Constraints
CONSTRAINT dates CHECK (last_date >= first_date),
PRIMARY KEY (u_id,first_date));
DELIMITER //
USE real_estate;
CREATE OR REPLACE FUNCTION overlap(
u_id INT,
first_date DATE,
last_date DATE
) RETURNS INT DETERMINISTIC
BEGIN
DECLARE valid INT;
SET valid = 1;
IF EXISTS(SELECT * FROM real_estate.sample_two_expected_output t WHERE t.u_id = u_id AND first_date <= t.last_date AND t.first_date <= last_date) THEN SET valid = 0;
ELSE SET valid = 1;
END IF;
RETURN valid;
END; \\
DELIMITER;
I try to add this function as a constraint in the table.
ALTER TABLE real_estate.sample_two_expected_output ADD CONSTRAINT overlap CHECK(overlap(u_id,first_date,last_date)=1);
However I get the below error message and I don't know why.
EXECUTE FAIL:
ALTER TABLE real_estate.sample_two_expected_output ADD CONSTRAINT overlap CHECK(overlap(u_id,first_date,last_date)=1);
Message :
Function or expression '`overlap`()' cannot be used in the CHECK clause of `overlap`
In general you can use any deterministic user defined function (UDF) but not a stored function (SF) in constraints like DEFAULT, CHECK, etc.
A big difference between UDFs and SFs is the fact that a UDF is usually written in C/C++ while a SF is written in SQL. That means it is not possible to execute SQL code in a UDF within the same connection, which would lead to significant problems, as your SF shows:
Depending on the storage engine ALTER TABLE locks the entire table, parts of it or creates a temporary copy. I cannot imagine a way to execute the SQL statement SELECT * FROM real_estate.sample_two_expected_output t WHERE t.u_id = u_id .. in your SF while the table is locked or reorganized.

Drop a Constraint doesn’t work

I am getting following error when deleting a column with constraint in SQL Server 2005.
The object 'DF__PlantRecon__Test' is dependent on column 'Test'.
The column is not part of any key. But it has a default constraint and the constraint has a pre-defined name.
Though I have written code to delete constraint first, it is not working.
Why doesn't it work?
What need to be done to make it working?
Note: I need to check whether the constraint exist first.
REFERENCES
Named CONSTRAINT benefits
How to drop column with constraint?
How to drop SQL default constraint without knowing its name?
CODE
IF OBJECT_ID('DF__PlantRecon__Test', 'C') IS NOT NULL
BEGIN
SELECT 'EXIST'
ALTER TABLE [dbo].[PlantReconciliationOptions] drop constraint DF__PlantRecon__Test
END
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_NAME ='DF__PlantRecon__Test')
BEGIN
SELECT 'EXIST'
--drop constraint
ALTER TABLE [dbo].[PlantReconciliationOptions] drop constraint DF__PlantRecon__Test
END
IF EXISTS ( SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'[dbo].[PlantReconciliationOptions]') AND name = 'Test')
BEGIN
--drop column
ALTER TABLE [dbo].[PlantReconciliationOptions] DROP COLUMN Test
END
ALTER TABLE PlantReconciliationOptions
ADD Test INT NOT NULL
CONSTRAINT DF__PlantRecon__Test DEFAULT 30
try
IF OBJECT_ID('DF__PlantRecon__Test') IS NOT NULL
BEGIN
SELECT 'EXIST'
ALTER TABLE [dbo].[PlantReconciliationOptions] drop constraint DF__PlantRecon__Test
END
In your example, you were looking for a 'C' Check Constraint, which the DEFAULT was not. You could have changed the 'C' for a 'D' or omit the parameter all together.
If you are consistent with your naming, as it appears you are, (e.g. DF__xxx) then dropping the second parameter is an acceptable choice to be sure that the hard coded constraint name is dropped.
Here is a list of the OBJECT_ID() Object Types you can pass:
AF = Aggregate function (CLR)
C = CHECK constraint
D = DEFAULT (constraint or stand-alone)
F = FOREIGN KEY constraint
PK = PRIMARY KEY constraint
P = SQL stored procedure
PC = Assembly (CLR) stored procedure
FN = SQL scalar function
FS = Assembly (CLR) scalar function
FT = Assembly (CLR) table-valued function
R = Rule (old-style, stand-alone)
RF = Replication-filter-procedure
S = System base table
SN = Synonym
SQ = Service queue
TA = Assembly (CLR) DML trigger
TR = SQL DML trigger
IF = SQL inline table-valued function
TF = SQL table-valued-function
U = Table (user-defined)
UQ = UNIQUE constraint
V = View
X = Extended stored procedure
IT = Internal table
(This list was found on Beyond Relational: Using TSQL Function: OBJECT_ID())
Steps to solve your problem.
Open SSMS.
Edit the table to remove the default. Do not press save
Script the output to "new window".
Read the script.

Using a function in a SQL CHECK constraint

I am trying to replace simple CHECK constraint with an embedded function within a CHECK constraint however it doesn't seem to restrict the data I can enter. The constraint is to prevent product amount of less than 0.25 and more than 5,000. The original check worked fine, however the function doesn't seem to do anything at all.
The original constraint:
ALTER TABLE Prices
ADD CONSTRAINT CheckPrices CHECK ((Amount > 0.25) AND (Amount <= 5000.00))
The function:
ALTER FUNCTION dbo.CheckProductPrices
(
#productSKU int,
#priceDate smalldatetime
)
RETURNS bit
AS
BEGIN
DECLARE #retVal bit = 0
SELECT #retVal = CASE WHEN Amount > 0.25 AND Amount <= 5000.00 THEN 1 ELSE 0 END
FROM Prices
WHERE productSKU = #productSKU
AND priceDate = #priceDate
RETURN #retVal
END
The new CHECK constraint:
ALTER TABLE Prices
ADD CONSTRAINT CheckPrices CHECK (dbo.CheckProductPrices([productItem], [priceValidDate]) = 1)
I don't understand why the new constraint isn't stopping invalid prices the way the original constraint did.

constraint check against values of foreign key

I have these two tables
Table: Guards
ID int
Name varchar
Rank int
Table: Squads
SquadId
Leader
SquadName
The Leader column points to the ID column in the Guard table and I'm trying to create a constraint that checks if the Rank column linked to the guard id provided as the leader is a specific value (in this case 1)
Is this possible or do I have to use a trigger?
You need to add a CHECK constraint. I'd wrap the constraint into a function since you need to check another table's value.
CREATE FUNCTION CheckLeaderRank
(#LeaderID INTEGER)
RETURNS INTEGER
AS
BEGIN
DECLARE #value INTEGER;
DECLARE #MinimumRank INTEGER = 3;
SET #value = CASE WHEN (SELECT RANK FROM Guards WITH(NOLOCK) WHERE Id = #LeaderID) >= #MinimumRank THEN 1 ELSE 0 END
RETURN #value
END
The function will check if the guard's Rank is high enough : make sure to set #MinimumRank to the proper value or, even better, to fetch it from another table.
Now add the constraint to your Squads table.
ALTER TABLE Squads
ADD CONSTRAINT chk_rank CHECK (dbo.CheckLeaderRank(i) = 1)

SQL Server: alter table, how to add SPARSE definition

I would like alter my table and add SPARSE option to all fields that contain a lot of NULL values. What is the right syntax for this ALTER TABLE command?
The other answers work, but you can also get away with:
ALTER TABLE #foo ALTER COLUMN bar ADD SPARSE;
This way you don't have to look up the column's type or nullability.
CREATE TABLE #Foo
(
X INT NULL,
Y INT NULL
)
ALTER TABLE #Foo ALTER COLUMN Y INT SPARSE NULL
ALTER TABLE #Foo ALTER COLUMN X INT SPARSE NULL
ALTER TABLE Xtable
ADD myCol int sparse null