我有一个名为“Accounts
”的表,其复合主键
由两列组成:Account_key
和Account_Start_date
都具有数据类型 int
和另一个名为 Accountnumber(bigint).
Account_key 应该有一个或多个 Accountnumber(bigint)
而不是相反,这意味着 1 个或多个 Accountnumber 只能有 1 个 Account_key。
如果您尝试插入相同的 Account_key 和相同的 Account_Start_date,那么 primary key constraint
会停止这样做,因为它们是一起主键。
但是,如果您插入现有的 Account_key 和不同的不存在的 Account_Start_date,那么您可以根据需要插入一个随机的 Accountnumber,而不会受到任何约束,突然之间您有 Account_key 和 Accountnumber 之间存在多对多关系的行,我们不想要那个。
我已经尝试了很多约束但没有任何运气。我只是不知道我在这里做错了什么所以请继续帮助我,谢谢! (注意:我不认为更改复合主键是一种选择,因为那样我们将失去缓慢变化的维度日期功能)
还有另一个表(案例),其中 1 'Account_Key' 只能与 1 'AccountNumber' 相关,意思是 1..1 关系,除了它们之间应该有 1..1 关系之外,所有其他事情都是相同的。
唯一索引至少对我没有用,只要考虑我是否想更改 Accounts
表或放置触发器甚至索引,所以它是“Account_Key”和“AccountNumber”之间的 1..1 关系, ?
最佳答案
如果这是一个 OLTP 表,解决方案是将数据正确规范化为两个表,但这是一个 DW 表,因此将所有数据都放在一个表中是有意义的。
在这种情况下,您应该添加一个 FOR
/AFTER
触发器 ON INSERT, UPDATE
对插入的 执行查询
伪表。查询可以是一个简单的 COUNT(DISTINCT Account_Key)
,连接回主表(仅过滤正在添加/更新的 AccountNumber
值),执行 GROUP BY
AccountNumber
然后 HAVING COUNT(DISTINCT Account_Key) > 1
。将该查询包装在 IF EXISTS
中,如果返回一行,则执行 ROLLBACK
以取消 DML 操作,执行 RAISERROR
以发送有关取消操作原因的错误消息,然后 RETURN
。
CREATE TRIGGER dbo.TR_TableName_PreventDuplicateAccountNumbers
ON dbo.TableName
AFTER INSERT, UPDATE
AS
SET NOCOUNT ON;
IF (EXISTS(
SELECT COUNT(DISTINCT tab.Account_Key)
FROM dbo.TableName tab
INNER JOIN INSERTED ins
ON ins.AccountNumber = tab.AccountNumber
GROUP BY tab.AccountNumber
HAVING COUNT(DISTINCT tab.Account_Key) > 1
))
BEGIN
ROLLBACK;
RAISERROR(N'AccountNumber cannot be associated with more than 1 Account_Key', 16, 1);
RETURN;
END;
对于 Account_Key
和 AccountNumber
之间的关系为 1:1 的“其他”表,您可以尝试执行如下操作:
DECLARE @Found BIT = 0;
;WITH cte AS
(
SELECT DISTINCT tab.Account_Key, tab.AccountNumber
FROM dbo.TableName tab
INNER JOIN INSERTED ins
ON ins.Account_Key = tab.Account_Key
OR ins.AccountNumber = tab.AccountNumber
), counts AS
(
SELECT c.[Account_Key],
c.[AccountNumber],
ROW_NUMBER() OVER (PARTITION BY c.[Account_Key
ORDER BY c.[Account_Key, c.[AccountNumber]) AS [KeyCount],
ROW_NUMBER() OVER (PARTITION BY c.[AccountNumber]
ORDER BY c.[AccountNumber], c.[Account_Key) AS [NumberCount]
FROM cte c
)
SELECT @Found = 1
FROM counts
WHERE [KeyCount] > 1
OR [NumberCount] > 1;
IF (@Found = 1)
BEGIN
ROLLBACK;
RAISERROR(N'AccountNumber cannot be associated with more than 1 Account_Key', 16, 1);
RETURN;
END;
关于sql - 强制执行 1 :1 and 1:Many cardinality in denormalized warehouse table with composite Primary Key,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36334124/