Home > front end >  Making a foreign key reference only a subset of rows in the referenced table
Making a foreign key reference only a subset of rows in the referenced table

Time:07-27

I'm using MS SQL SERVER 2019.

In my database I have a table Events which stores events offered by a club

Events (Theme, Event_Date, Place, Event_Hour, Type)

Then I also have a table Reservations which stores reservations for those events:

Reservations (Id, Event_Theme)       FK(Event_Theme) --> PK(Events.Theme)

My goal is to allow insertion of new rows in Reservations only if Event_Theme for that row is a theme of a future event (i.e one with Event_Date > CURRENT DATE): obviously reservations are not allowed for past events.

My attempt was the creation, inside Reservations table's creation, of the following check constraint:

  CONSTRAINT CHK_Reservations_Event_Theme   CHECK (Event_Theme IN (SELECT STRING_AGG(E.Theme, ',') WITHIN GROUP (ORDER BY E.Theme ASC)
                                                                   FROM Events E
                                                                   WHERE E.Event_Date>=(CAST( GETDATE() AS Date))))

But I then remembered that subqueries aren't supported for check constraints

What is an alternative way to implement the same logic?

CodePudding user response:

As you can see in the example event number 2 is outdated, so a new row is not inserted.

Event number 1 can be inserted.

you can add more and more conditions to the WHERE for example if only 100 reservations can be made

CREATE TABLE Events (Theme int , Event_Date date, Place varchar(4), Event_Hour int, Type int)
INSERT INTO Events VALUES(1, DATEADD(month, 1, getdate()), 'A',1,1),
(2, DATEADD(day, -1, getdate()), 'B',2,2)
CREATE tABLE Reservations (Id int, Event_Theme int) 
 CREATE TRIGGER tr_Reservations ON Reservations
INSTEAD OF INSERT 
AS
BEGIN 

INSERT INTO [Reservations](
  [Id],
  [Event_Theme])
SELECT  Id,[Event_Theme]  
FROM INSERTED
WHERE Event_Theme IN (SELECT STRING_AGG(E.Theme, ',') WITHIN GROUP (ORDER BY E.Theme ASC)
                                                                   FROM [Events] E
                                                                   WHERE E.Event_Date>=(CAST( GETDATE() AS Date)));
PRINT 'success.';

  END
INSERT INTO Reservations VALUES (1,1),(2,2)

success. 3 rows affected

SELECT * FROM Reservations
Id | Event_Theme
-: | ----------:
 1 |           1

db<>fiddle here

CodePudding user response:

I found also a way without using a trigger.

I created the following stored function:

CREATE FUNCTION usf_CHECK_THEME(@Event_Theme VARCHAR(45))
RETURNS VARCHAR(45)
BEGIN
    DECLARE @Theme VARCHAR(45);
    SET @Theme =NULL;
    SET @Theme = (SELECT E.Theme
                 FROM  Events E
                 WHERE E.Theme=@Event_Theme  AND E.Event_Date>(CAST(GETDATE() AS Date)));
RETURN @Theme;
END;

Theme is PK In table Events.

And then in the check constraint:

CONSTRAINT CHK_Reservations_Event_Theme CHECK (usf_SCEGLINOME(Eventi_Pubblici_Tema) IS NOT NULL) 
  • Related