Sql 在具有复合主键的非规范化仓库表中强制1:1和1:Many基数

Sql 在具有复合主键的非规范化仓库表中强制1:1和1:Many基数,sql,sql-server,database,tsql,data-warehouse,Sql,Sql Server,Database,Tsql,Data Warehouse,我有一个名为“Accounts”的表,它有一个复合主键,由两列组成:Account\u key和Account\u Start\u date两列,数据类型均为int,另一列为Accountnumber(bigint)。 Account\u key应该有一个或多个Accountnumber(bigint),而不是相反,意思是1或多个Accountnumber只能有一个Account\u key。 如果您尝试插入相同的帐户密钥和相同的帐户开始日期,则主键约束将停止此操作,因为它们是主键 但是,如果您

我有一个名为“
Accounts
”的表,它有一个
复合主键
,由两列组成:
Account\u key
Account\u Start\u date
两列,数据类型均为
int
,另一列为
Accountnumber(bigint)。

Account\u key应该有一个或多个
Accountnumber(bigint)
,而不是相反,意思是1或多个Accountnumber只能有一个Account\u key。 如果您尝试插入相同的帐户密钥和相同的帐户开始日期,则
主键约束将停止此操作,因为它们是主键

但是,如果您插入具有不同非现有帐户开始日期的现有帐户密钥,那么您可以根据自己的意愿插入一个随机帐户编号,而不会有任何约束抱怨,突然间,您的帐户密钥和帐户编号之间有多对多关系的行,我们不希望这样

我尝试了很多限制,但没有任何运气。我只是不知道我做错了什么,所以请继续帮助我,谢谢! (注意:我不认为更改复合主键是一个选项,因为这样我们将失去缓慢更改的维度日期功能)

还有另一个表(case),其中1“Account_Key”只能与1“AccountNumber”相关,表示1..1关系,除它们之间应该有1..1关系外,其他所有内容都是相同的。
唯一的索引至少对我来说不是什么工作,只要考虑我想改变<代码>帐号<代码>表,或者设置一个触发器,甚至是一个索引,那么它将是“1”1关系,“Actudio KEY”和“Actudio编号”,

< P>如果我正确地理解了,你想要:

  • 任何给定的AccountNumber只能与一个AccountKey相关
  • 任何给定的AccountKey都可以与多个AccountNumber关联
  • 如果这是正确的,您可以通过调用UDF的
    检查约束来实现这一点

    编辑:

    检查约束的Psuedo逻辑可以是:

    IF EXISTS anotherRow 
    WHERE theOtherAccountNumber = thisAccountNumber 
    AND theOtherAccountKey <> thisAccountKey
    THEN False (do not allow this row to be inserted)
    ELSE True (allow the insertion)
    
    如果存在另一行
    其中theOtherAccountNumber=此AccountNumber
    还有另一个AccountKey这个AccountKey
    然后为False(不允许插入此行)
    ELSE True(允许插入)
    

    我会将此逻辑放在一个UDF中,该UDF返回true或false,以简化检查约束。

    创建一个额外的表AccountKeyNumber(名称当然是您的选择),其中包含Account\u Key和Account\u Number列

    将帐号设为主键

    请注意,您不能两次添加帐号,因此不能将其链接到此表中的两个不同帐号

    现在,在Account\u Number和Account\u Key上添加一个额外的唯一约束。在这个表中,您输入了所有帐号及其对应的键

    最后,在Accounts表的Account\u key加Account\u Number列上定义一个外键,引用AccountKeyNumber表中的唯一约束


    现在,您已经确保只有有效的键/数字组合可以插入帐户,并且没有两个AccountKey可以具有相同的数字。我们需要额外的唯一约束,它不影响AccountKeyNumbers表的数据完整性,只是为了创建外键,外键必须指向主约束或唯一约束。

    如果这是一个OLTP表,解决方案是将数据正确地规范化为两个表,但这是一个DW表,所以将其全部放在一个表中是有意义的

    在这种情况下,您应该在插入时的
    触发器
    之后为/
    添加一个
    ,更新对插入的伪表进行查询的。查询可以是一个简单的
    COUNT(DISTINCT Account\u Key)
    ,连接回主表(仅过滤添加/更新的
    AccountNumber
    值),在
    AccountNumber
    上执行
    分组,然后
    拥有COUNT(DISTINCT Account\u Key)>1
    。将该查询包装在
    中(如果存在)
    ,如果返回了一行,则执行
    回滚
    以取消DML操作,执行
    RAISERROR
    以发送有关取消操作原因的错误消息,然后执行
    返回

    CREATE TRIGGER dbo.TR_TableName_duplicateAccountNumber
    关于dbo.TableName
    插入后,更新
    作为
    不计数;
    如果(存在)(
    选择计数(不同的选项卡。帐户\u键)
    从dbo.TableName选项卡
    插入的内部联接
    在ins.AccountNumber=tab.AccountNumber上
    按tab.AccountNumber分组
    计数(不同的制表符科目)大于1
    ))
    开始
    回降;
    RAISERROR(N'AccountNumber不能与多个帐户_键'16,1'关联);
    返回;
    结束;
    
    对于
    Account\u Key
    AccountNumber
    之间关系为1:1的“other”表,您可以尝试执行以下操作:

    DECLARE@Found位=0;
    ;以cte为例
    (
    选择不同的tab.Account\u键,tab.AccountNumber
    从dbo.TableName选项卡
    插入的内部联接
    在ins.Account\u Key=tab.Account\u Key上
    或ins.AccountNumber=tab.AccountNumber
    ),算作
    (
    选择c.[帐户密钥],
    c、 [帐号],
    (按c.[Account\u键划分的)上的行数()
    按c.[Account_Key,c.[AccountNumber])作为[KeyCount]排序,
    (按c分区[AccountNumber]
    按c.[AccountNumber],c.[Account\u Key]作为[NumberCount]排序
    来自cte c
    )
    选择@Found=1
    从计数
    其中[KeyCount]>1
    或[NumberCount]>1;
    如果(@Found=1)
    开始
    回降;
    RAISERROR(N'AccountNumber不能与多个帐户_键'16,1'关联);
    返回;
    结束;
    
    通常在注册表项中输入开始日期。您的一个帐户是否可能有更多的t