I working with SQL Server 2008 and I have two existing tables, venues
and events
.
I am trying to create a custom function with a check constraint to make sure that the integer in the event_expected_attendance
column in the events
table is always less than or equal to the venue_max_capacity
integer in the venues
table.
I am struggling with the syntax of a custom function as well as the join statement since the check constraint is between two tables.
Thanks for the help! I will answer any additional questions quickly.
You can use user-defined functions (UDF) in check constraints. But the functions must return a scalar value.
Use SQL Server Management Studio In Object Explorer, expand the table to which you want to add a check constraint, right-click Constraints and select New Constraint. In the Check Constraints dialog box, select in the Expression field and then select the ellipses (...).
The CHECK constraint is used to limit the value range that can be placed in a column. If you define a CHECK constraint on a column it will allow only certain values for this column. If you define a CHECK constraint on a table it can limit the values in certain columns based on values in other columns in the row.
The basic syntax of an ALTER TABLE command to add a NOT NULL constraint to a column in a table is as follows. ALTER TABLE table_name MODIFY column_name datatype NOT NULL; The basic syntax of ALTER TABLE to ADD UNIQUE CONSTRAINT to a table is as follows.
As stated by Martin Smith using a check constraint with a UDF has some problems and might have a negative impact on performance, but if you want to try it anyway this code should work:
CREATE FUNCTION dbo.CheckVenueCapacity (@venue_id int, @capacity int)
RETURNS int
AS
BEGIN
DECLARE @retval int
SELECT @retval = CASE WHEN venue_max_capacity >= @capacity THEN 0 ELSE 1 END
FROM venues
WHERE venue_id = @venue_id
RETURN @retval
END;
GO
ALTER TABLE events
ADD CONSTRAINT chkVenueCapacity
CHECK (dbo.CheckVenueCapacity(event_venue_id, event_expected_attendance) = 0);
You could use a scalar UDF for this but using those in check constraints has well documented problems (e.g. see Scalar UDFs wrapped in CHECK constraints are very slow and may fail for multirow updates or Snapshot isolation: A threat for integrity? series.
It is also possible to get the database engine to enforce this with an indexed view
It needs a helper table with 2 rows as CTEs and UNION
are not allowed in indexed views. The idea is that the view definition should always return zero rows and this doubles any rows that are returned if there is a violation. Therefore causing a breach of the unique constraint on the view and causing an error to occur and the statement to fail.
CREATE TABLE dbo.TwoNums
(
Num INT PRIMARY KEY
)
INSERT INTO dbo.TwoNums
VALUES (1),
(2)
Then the view definition
CREATE VIEW dbo.PreventOverCapacity
WITH SCHEMABINDING
AS
SELECT V.Venueid,
E.EventId,
E.Expected,
V.Capacity
FROM dbo.Venues V
JOIN dbo.Events E
ON E.venueid = V.venueid
AND E.Expected > V.Capacity
CROSS JOIN dbo.TwoNums
And a unique index on the View
CREATE UNIQUE CLUSTERED INDEX [UIX_PreventOverCapacity (Venueid, EventId, Expected, Capacity)]
ON dbo.PreventOverCapacity(Venueid, EventId, Expected, Capacity)
The reason for including all four columns is so that all the required values are shown in the error message.
Cannot insert duplicate key row in object 'dbo.PreventOverCapacity' with unique index 'UIX_PreventOverCapacity (Venueid, EventId, Expected, Capacity)'.
The duplicate key value is (1, 97, 110, 100).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With