如 cmets 中所述,避免由于并行运行的进程之间的时间问题而插入重复的一种方法是将测试是否存在行与使用 WHERE 子句的 INSERT 语句相结合。
我建议动态 SQL 是一种可能的解决方案,但如果客户端的约束设置存储在数据库中,这里有一种使用位掩码的替代方法可能对您有用。我做了一些假设,所以这可能对你没有帮助。
请注意,此代码已简化为仅使用三列(而不是 OP 中提到的十五列)。如果您决定将其生产化,最好将逻辑包装在存储过程中。
-- run this code for different values of @ClientId and @DataN to test the behaviour
DECLARE
@ClientId int = 103,
@Data1 int = 1,
@Data2 int = 2,
@Data3 int = 3
DECLARE @clientConstraint TABLE (ClientId int PRIMARY KEY, Data1 bit, Data2 bit, Data3 bit)
DECLARE @clientData TABLE (Id int IDENTITY PRIMARY KEY, ClientId int, Data1 int, Data2 int, Data3 int)
-- set up four clients with different constraints for testing purposes
INSERT @clientConstraint (ClientId, Data1, Data2, Data3)
VALUES
(100,0,0,0),
(101,1,0,0),
(102,0,1,0),
(103,1,0,1)
-- set up an existing row in the data table for each client
INSERT @clientData (ClientId, Data1, Data2, Data3)
VALUES
(100,1,2,3),
(101,1,2,3),
(102,1,2,3),
(103,1,2,3)
-- build a bitmask of the client's unique columns
DECLARE @ClientConstraintMask bigint = 0
SELECT @ClientConstraintMask = Data1 + (Data2 * 2) + (Data3 * 4)
FROM @clientConstraint
WHERE ClientId = @ClientId
-- insert the data, building a uniqueness bitmask and comparing to client's settings
INSERT @clientData (ClientId, Data1, Data2, Data3)
SELECT @ClientId,@Data1, @Data2, @Data3
WHERE ( SELECT
CASE WHEN c1.Data1 = @Data1
THEN @ClientConstraintMask & 1
ELSE 0
END +
CASE WHEN c1.Data2 = @Data2
THEN @ClientConstraintMask & 2
ELSE 0
END +
CASE WHEN c1.Data3 = @Data3
THEN @ClientConstraintMask & 4
ELSE 0
END
FROM @clientData AS c1
WHERE c1.ClientId = @ClientId
) <> @ClientConstraintMask
-- view the results
SELECT * FROM @clientData
可能还值得一提的是,根据客户端数据量,您可能很难有效地索引客户端数据表以保持插入性能良好。如果单独对 ClientId 的索引性能不够好,请考虑对最常用的唯一列集进行索引。