SQL 服务器:对来自两个不同表的列施加唯一性的方法
SQL Server: Ways to impose Uniqueness on columns from two different tables
示例 tables:
- dbo.TransactionHeader (HeaderID, BillID, FileID) -- HeaderID is the PK here
- dbo.TransactionGroup (FileID, SurityID) -- All these make a composite PK
我想对 table dbo.TransactionHeader
中的 BillID
和另一个 table dbo.TransactionGroup
中的另一列 (SurityID
) 施加唯一性。 SurityID
在 dbo.TransactionHeader
table 中不可用。
我想在 dbo.TransactionHeader
table 上添加唯一性,以不插入任何具有 (BillID, SurityID
) 组合的重复项。
我无法在 dbo.TransactionHeader
中添加新的物理列(比如 SurityID
),因为它是一个包含大量数据的遗留数据库,这将是一个很大的变化。
Options tried:
尝试创建计算列并尝试使用函数获取基于 FileID
的 SurityID
。但是不能在计算列上创建唯一约束,因为函数 returns 是一个非确定性值
任何help/ideas将不胜感激。
您可以使用索引视图执行此操作。示例:
CREATE VIEW dbo.v1 WITH SCHEMABINDING AS
SELECT H.HeaderID, H.BillID, H.FileId, G.SurityID
FROM dbo.TransactionHeader H
JOIN dbo.TransactionGroup G
ON H.FileID = G.FileID;
GO
CREATE UNIQUE CLUSTERED INDEX v1idx ON dbo.v1 (BillID, SurityID) ;
经过多方研究,发现我们也可以使用CHECK
约束来实现这一点。
步骤:
创建一个 user defined function
,它将 return 0
或 1
,在检查是否存在重复项后,如下所示:
CREATE FUNCTION [dbo].[udf_TransactionHeader_Bill_ID_Surity_ID](@File_ID INT,@Bill_ID VARCHAR(10))
RETURNS BIT
AS
BEGIN
IF(SELECT COUNT(*) FROM [dbo].[TransactionHeader] AS th
WHERE th.Bill_ID = @Bill_ID) > 0
BEGIN
DECLARE @Surity_ID SMALLINT = (SELECT Surity_ID FROM [dbo].[TransactionGroup] WHERE File_ID = @File_ID)
IF (SELECT COUNT(*)
FROM [dbo].[TransactionHeader] AS th
INNER JOIN [dbo].[TransactionGroup] AS tg ON tg.File_ID = th.File_ID
WHERE th.Bill_ID = @Bill_ID
AND tg.Surity_ID = @Surity_ID) > 1
BEGIN
RETURN 1
END
END
RETURN 0
END
GO
现在在 dbo.TransactionHeader
(Bill_ID
)
上添加一个 CHECK
约束
列并将上述函数嵌入到 CHECK
约束表达式中,如下所示:
ALTER TABLE [dbo].[TransactionHeader] WITH NOCHECK
ADD CONSTRAINT CK_TransactionHeader_Bill_ID
CHECK (dbo.udf_TransactionHeader_Bill_ID_Surity_ID(SurityID,Bill_ID) = 0);
这应该可以实现。
示例 tables:
- dbo.TransactionHeader (HeaderID, BillID, FileID) -- HeaderID is the PK here
- dbo.TransactionGroup (FileID, SurityID) -- All these make a composite PK
我想对 table dbo.TransactionHeader
中的 BillID
和另一个 table dbo.TransactionGroup
中的另一列 (SurityID
) 施加唯一性。 SurityID
在 dbo.TransactionHeader
table 中不可用。
我想在 dbo.TransactionHeader
table 上添加唯一性,以不插入任何具有 (BillID, SurityID
) 组合的重复项。
我无法在 dbo.TransactionHeader
中添加新的物理列(比如 SurityID
),因为它是一个包含大量数据的遗留数据库,这将是一个很大的变化。
Options tried:
尝试创建计算列并尝试使用函数获取基于 FileID
的 SurityID
。但是不能在计算列上创建唯一约束,因为函数 returns 是一个非确定性值
任何help/ideas将不胜感激。
您可以使用索引视图执行此操作。示例:
CREATE VIEW dbo.v1 WITH SCHEMABINDING AS
SELECT H.HeaderID, H.BillID, H.FileId, G.SurityID
FROM dbo.TransactionHeader H
JOIN dbo.TransactionGroup G
ON H.FileID = G.FileID;
GO
CREATE UNIQUE CLUSTERED INDEX v1idx ON dbo.v1 (BillID, SurityID) ;
经过多方研究,发现我们也可以使用CHECK
约束来实现这一点。
步骤:
创建一个 user defined function
,它将 return 0
或 1
,在检查是否存在重复项后,如下所示:
CREATE FUNCTION [dbo].[udf_TransactionHeader_Bill_ID_Surity_ID](@File_ID INT,@Bill_ID VARCHAR(10))
RETURNS BIT
AS
BEGIN
IF(SELECT COUNT(*) FROM [dbo].[TransactionHeader] AS th
WHERE th.Bill_ID = @Bill_ID) > 0
BEGIN
DECLARE @Surity_ID SMALLINT = (SELECT Surity_ID FROM [dbo].[TransactionGroup] WHERE File_ID = @File_ID)
IF (SELECT COUNT(*)
FROM [dbo].[TransactionHeader] AS th
INNER JOIN [dbo].[TransactionGroup] AS tg ON tg.File_ID = th.File_ID
WHERE th.Bill_ID = @Bill_ID
AND tg.Surity_ID = @Surity_ID) > 1
BEGIN
RETURN 1
END
END
RETURN 0
END
GO
现在在 dbo.TransactionHeader
(Bill_ID
)
CHECK
约束
列并将上述函数嵌入到 CHECK
约束表达式中,如下所示:
ALTER TABLE [dbo].[TransactionHeader] WITH NOCHECK
ADD CONSTRAINT CK_TransactionHeader_Bill_ID
CHECK (dbo.udf_TransactionHeader_Bill_ID_Surity_ID(SurityID,Bill_ID) = 0);
这应该可以实现。