【问题标题】:Ensure foreign key of a foreign key matches a base foreign key确保外键的外键与基础外键匹配
【发布时间】:2016-10-03 19:54:18
【问题描述】:

基本上假设我有一个“企业”,它拥有它所服务的邮政编码。我们还假设我有另一个设置费用的关系表。

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 的相关BusinessIdBusinessPostalCodeFeesBusinessId 相同。

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

【问题讨论】:

  • 在触发器中编写逻辑并回滚违反规则的事务
  • @techspider 感谢您的提示,但我认为检查约束在这里非常有效。

标签: sql-server tsql foreign-key-relationship


【解决方案1】:

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

但是,如果您需要保留 BusinessId,我建议您进一步规范化您的表格。您最终会得到原样的重复数据。

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

【讨论】:

  • 我完全没想过要那样做,但这很有意义。我认为您是对的,因为我最终应该将其标准化,因为我会更加努力地看待它。这是很好的信息,谢谢!
  • 如果您不介意,请跟进。 PostalCodes 和 FeeTypes 都有一个 BusinessId。关系表中是否有任何方法可以确保这些匹配?
  • 没关系,保留列并为两列执行双复合键按我想要的方式工作。再次感谢!
【解决方案2】:

最后,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

然后将其添加到您的表中:

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

【讨论】:

    猜你喜欢
    • 2016-09-28
    • 1970-01-01
    • 2012-07-08
    • 2016-03-23
    • 2020-12-01
    • 2021-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多