确保外键的外键与基本外键匹配

Ensure foreign key of a foreign key matches a base foreign key

基本上假设我有一个 "Business" 拥有它所服务的邮政编码。我们还假设我有另一个设置费用的关系 table。

CREATE TABLE [dbo].[BusinessPostalCodes] 
(
    [BusinessPostalCodeId]         INT           IDENTITY (1, 1) NOT NULL,
    [BusinessId]                   INT           NOT NULL,
    [PostalCode]                    VARCHAR (10)  NOT NULL
)

CREATE TABLE [dbo].[BusinessPostalCodeFees]
(
    [BusinessId] INT NOT NULL, 
    [BusinessProfileFeeTypeId] INT NOT NULL,
    [BusinessPostalCodeId] INT NOT NULL, 
    [Fee] SMALLMONEY NULL
)

我想知道是否可以在 BusinessPostalCodeFees 上设置外键(或其他东西)以确保 BusinessPostalCodes 的相关 BusinessIdBusinessIdBusinessPostalCodeFees

我知道我可以完全删除 BusinessId,但我更愿意保留此专栏并有办法保证它们相同。有什么我可以做的吗?

这听起来像是(如果我错了请纠正我)您正在尝试确保 BusinessPostalCodeFees 的 BusinessId 和 BusinessPostalCodeId 列中的任何条目与 BusinessPostalCodes table 中的条目相匹配。如果是这样,那么可以 definitely have a foreign key that references a compound primary key.

但是,如果您需要保留 BusinessId,我建议您对 table 进行规范化,比您做的更进一步。您最终将按原样获得重复数据。

附带说明一下,我建议您不要使用 SQL 中的货币数据类型:See here.

最后,Jeffrey 的解决方案并不完全适合我的具体情况。关系中的两列都必须是唯一的(如复合键)。结果这里的答案(对我来说)是 Checked Constraint.

创建一个您希望约束通过或失败的函数:

CREATE FUNCTION [dbo].[MatchingBusinessIdPostalCodeAndProfileFeeType]
(
    @BusinessId int,
    @BusinessPostalCodeId int,
    @BusinessProfileFeeTypeId int
)
RETURNS BIT
AS
BEGIN

    -- This works because BusinessPostalCodeId is a unique Id.
    -- If businessId doesn't match, its filtered out.   
    DECLARE @pcCount AS INT 
    SET @pcCount = (SELECT COUNT(*) 
        FROM BusinessPostalCodes 
        WHERE BusinessPostalCodeId = @BusinessPostalCodeId AND 
            BusinessId = @BusinessId)


    -- This works because BusinessProfileFeeTypeId is a unique Id.
    -- If businessId doesn't match, its filtered out.   
    DECLARE @ftCount AS INT 
    SET @ftCount = (SELECT COUNT(*) 
        FROM BusinessProfileFeeTypes
        WHERE BusinessProfileFeeTypeId = @BusinessProfileFeeTypeId AND 
            BusinessId = @BusinessId)

    -- Both should have only one record
    BEGIN IF (@pcCount = 1 AND @ftCount = 1)
        RETURN 1
    END

    RETURN 0
END

然后将其添加到您的 table:

CONSTRAINT [CK_BusinessPostalCodeFees_MatchingBusinessIdPostalCodeAndProfileFeeType] 
CHECK (dbo.MatchingBusinessIdPostalCodeAndProfileFeeType(
    BusinessId, 
    BusinessPostalCodeId, 
    BusinessProfileFeeTypeId) = 1)