Fonction MSSQL dans la contrainte de vérification

Je voudrais créer une table avec la contrainte CHECK, où CHECK appelle une fonction scalaire définie par l'user. J'ai lu sur plusieurs sites que c'est possible, aussi qu'il a de mauvaises performances. Même si je voudrais le faire.

J'ai cette table

CREATE TABLE [book_history] ( id int NOT NULL IDENTITY PRIMARY KEY, user_id int NOT NULL, library_id int NOT NULL, book_id int NOT NULL, borrow_time datetime DEFAULT GETDATE(), return_policy datetime DEFAULT DATEADD(DAY, 30, GETDATE()), return_time datetime, CHECK (dbo.fn_check_duplicate(user_id, library_id, book_id) = 0) ); 

et fonction

 DROP FUNCTION IF EXISTS fn_check_duplicate GO CREATE FUNCTION fn_check_duplicate (@user_id int, @library_id int, @book_id int) RETURNS int BEGIN RETURN (SELECT COUNT(*) FROM [book_history] WHERE user_id = @user_id AND library_id = @library_id AND book_id = @book_id AND return_time IS NULL) END GO 

Lorsque j'essaie d'insert une nouvelle ligne dans cette table book_history (qui est vide), j'obtiens une erreur indiquant que l' The INSERT statement conflicted with the CHECK constraint "CK__book_history__267ABA7A". The conflict occurred in database "library", table "dbo.book_history". The INSERT statement conflicted with the CHECK constraint "CK__book_history__267ABA7A". The conflict occurred in database "library", table "dbo.book_history".

COUNT est supposé renvoyer un type de données int basé sur la documentation MSDN.
Je suis propriétaire des deux, de la table et de la fonction.

Quelqu'un peut-il me dire ce que je fais mal?

Changez-le pour check (dbo.fn_check_duplicate(user_id, library_id, book_id) = 1)

La check va regarder l'état de la table après l'insertion, donc vous voulez que le count soit 1.

Testez-le sur rextester: http://rextester.com/AWDNP40594 en décommentant la seconde insertion.


Vous pouvez également replace cette contrainte de vérification lente par un index unique filtré comme suit:

 create unique nonclustered index uix_book_history_user_library_book on dbo.book_history (user_id, library_id, book_id) where return_time is null 

Cela pourrait être plus de ce que vous essayez de faire, si chaque book_id est un livre individuel:

 create unique nonclustered index uix_book_history_library_book on dbo.book_history (library_id, book_id) where return_time is null 

Parce que cela permettrait à un livre d'être extrait seulement par un user à la fois.