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