I want to create lists of items and prevent the entry of 2 identical lists, using a unique constraint on a computed column.
CREATE TABLE test_cc
(
list_id int,
list_item int,
list_items AS STRING_AGG(CONVERT(varchar(10), list_item),',') OVER (PARTITION BY list_id) WITHIN GROUP (ORDER BY list_item),
UNIQUE(bs)
);
INSERT INTO test_cc VALUES (1, 1),(1,2),(2,1),(2,2);
/*should not be possible.*/
Executing this on SQL Server 2019 returns Error Msg 4113 Level 16 during table creation.
Is declaring a unique constraint on an expression a good practice ?
My data volume for this table is not huge.
CodePudding user response:
Making sure that lists are unique are difficult. As I mentioned in the comments you can't use aggregate function in a computed column; a computed column is a value calculated based on the row, not the table.
You also can't use an Indexed View with a UNIQUE INDEX
on a STRING_AGG
'd column, as STRING_AGG
isn't allowed to be used in an indexed view.
One method, therefore, is to use a TRIGGER
, however, this won't be performant; in fact as your table grows this is going to get increasingly slower. For a small dataset it should be fine.
CREATE TRIGGER dbo.UnqTrg_list_items_test_cc ON dbo.test_cc
AFTER INSERT,UPDATE,DELETE AS
BEGIN
IF EXISTS (SELECT 1
FROM (SELECT STRING_AGG(cc.list_item,',') WITHIN GROUP (ORDER BY cc.list_item) AS list_items
FROM dbo.test_cc cc
GROUP BY cc.list_id) SA
GROUP BY list_items
HAVING COUNT(list_items) > 1)
THROW 96432, N'Violation of Unique Trigger logic ''UnqTrg_list_items_test_cc''. Cannot insert duplicate list in object ''dbo.test_cc''. The statement has been aborted.',10;
END;
db<>fiddle demonstrating INSERT
,DELETE
and UPDATE
failing.