小编典典

一组记录中唯一值相同的约束

sql

DBMS: MS Sql Server 2005,标准版

我想对一个表进行约束,使其只有一个记录在表的子集内具有特定的值(其中行在特定列中共享一个值)。这可能吗?

示例:
我在myTable中有一个记录,该记录具有一个非唯一的外键(fk1),以及一个称为isPrimary的位列,以指出此特定记录应由我们的应用程序用于特殊逻辑。

在摘要中,它看起来像这样:

myTable
-------------
pk1       (int, not null)
name      (varchar(50), null)
fk1       (int, not null)
isPrimary (bit, not null)

我想确保对于fk1的每个唯一值, 只有一个 记录的isPrimary标志设置为1。

数据示例:这应该合法:

pk1     name     fk1    isPrimary
----    -----    -----  ----------
1       Bill     111    1
2       Tom      111    0
3       Dick     222    1
4       Harry    222    0

但这 应该是(fk = 111时不止一个):

pk1     name     fk1    isPrimary
----    -----    -----  ----------
1       Bill     111    1
2       Tom      111    1
3       Dick     222    1
4       Harry    222    0

而且也不应该这样(在fk = 222时不存在):

pk1     name     fk1    isPrimary
----    -----    -----  ----------
1       Bill     111    1
2       Tom      111    0
3       Dick     222    0
4       Harry    222    0

有没有办法用表约束做到这一点?

更新 尽管我将在即将发布的版本中推动JohnFx的重构,但我现在已经接受了Martin
Smith的回答,因为这是最好的长期解决方案。但是,我想根据Raze2dust的答案发布更新的UDF,以防将来的读者认为这更适合他们的需求。

CREATE FUNCTION [dbo].[OneIsPrimaryPerFK1](@fk1 INT, @dummyIsPrimary BIT)
RETURNS INT
AS 
BEGIN
    DECLARE @retval INT;
    DECLARE @primarySum INT;
    SET @retval = 0;
    DECLARE @TempTable TABLE (
    fk1 INT,
    PrimarySum INT)

INSERT INTO @TempTable
    SELECT fk1, SUM(CAST(isPrimary AS INT)) AS PrimarySum
    FROM FacAdmin
    WHERE fk1 = @fk1
    GROUP BY fk1;

    SELECT @primarySum = PrimarySum FROM @TempTable;
    IF(@primarySum=1)
        BEGIN
            SET @retval = 1
        END
    RETURN @retval
END;

变化:

  1. 使用@tempTable而不是

udf要求的tempTable(在内存v。中写入磁盘)

  1. 传递@ fk1作为参数,这样我就可以在一组fk1值中选择唯一性。
  2. 棘手的 是,即使函数的逻辑不是必需的,也必须传递isPrimary,否则,在更新isPrimary时,SQL2005优化器将不会运行检查约束。

阅读 150

收藏
2021-04-22

共1个答案

小编典典

快照约束或多行更新下,在检查约束中使用UDF可能会失败。

假设所有的fk1和pk1值当前都是(并且将始终是)正值,则可以使用以下定义创建一个计算列

CASE WHEN isPrimary = 1 THEN fk1 ELSE -pk1 END

然后为其添加唯一约束。或者,如果无法做出该假设,那么也许

CASE WHEN isPrimary = 0 THEN 1.0/pk1 ELSE fk1 END
2021-04-22