December 8, 2012 at 7:14 am
How do I write a check constraint which precludes this situtation in a hierarchy table:
Child |Parent
-------------------
Tom |Joe
Joe |Tom
Thanks,
Tom (but not Joe)
December 8, 2012 at 6:03 pm
trapnell (12/8/2012)
How do I write a check constraint which precludes this situtation in a hierarchy table:Child |Parent
-------------------
Tom |Joe
Joe |Tom
Thanks,
Tom (but not Joe)
In T-SQL, you either need a Trigger to check or a Scalar Function which would be used in a table level constraint. Like this.
Here's a function to the check on the EmployeeID and ManagerID of a table called dbo.Employee.
CREATE FUNCTION dbo.IsReversePresent
(@EmployeeID INT, @ManagerID INT)
RETURNS INT
AS
BEGIN
RETURN (
SELECT ReversePresent = COUNT(*)
FROM dbo.Employee
WHERE EmployeeID = @ManagerID
AND ManagerID = @EmployeeID
)
END
;
The table would look like this...
--===== Do this in a nice, safe place that everyone has
USE tempdb;
--===== Conditionaly drop the test table so we can do reruns more easily
IF OBJECT_ID('tempdb.dbo.Employee','U') IS NOT NULL
DROP TABLE tempdb.dbo.Employee;
--===== Create the test table with a clustered PK and an FK to itself to make
-- sure that a ManagerID is also an EmployeeID.
CREATE TABLE dbo.Employee
(
EmployeeID INT NOT NULL,
ManagerID INT NULL,
EmployeeName VARCHAR(10) NOT NULL,
CONSTRAINT PK_Employee
PRIMARY KEY CLUSTERED (EmployeeID),
CONSTRAINT FK_Employee_Employee
FOREIGN KEY (ManagerID)
REFERENCES dbo.Employee (EmployeeID)
ON UPDATE NO ACTION
ON DELETE NO ACTION
)
;
--===== Create an additional index to speed things up
CREATE UNIQUE INDEX By_ManagerID_EmployeeID
ON TempDB.dbo.Employee (ManagerID,EmployeeID)
;
All you have to do is add the table level constraint like this...
--===== Add new constraint to check for reversals
ALTER TABLE dbo.Employee WITH CHECK
ADD CONSTRAINT CheckForReverse
CHECK (dbo.IsReversePresent(EmployeeID,ManagerID)=(0))
;
When you try to run something like the following, the constraint will produce an error.
--===== Add new constraint to check for reversals
ALTER TABLE dbo.Employee WITH CHECK
ADD CONSTRAINT CheckForReverse
CHECK (dbo.IsReversePresent(EmployeeID,ManagerID)=(0))
;
[font="Courier New"]Msg 547, Level 16, State 0, Line 2
The INSERT statement conflicted with the CHECK constraint "CheckForReverse". The conflict occurred in database "tempdb", table "dbo.Employee".
The statement has been terminated.[/font]
If you typically insert more than one row at a time, a trigger is likely going to be much more effective because it can check more than one row at a time in a high performance set-based manner.
--Jeff Moden
Change is inevitable... Change for the better is not.
December 14, 2012 at 5:00 am
Hi Jeff,
Pefect! An answer which not only works, but explains clearly.
Thanks much,
Tom
December 14, 2012 at 6:30 am
Thanks for the feedback, Tom.
--Jeff Moden
Change is inevitable... Change for the better is not.
Viewing 4 posts - 1 through 3 (of 3 total)
You must be logged in to reply to this topic. Login to reply