2016-10-03 3 views
0

В принципе, у меня есть «Бизнес», которому принадлежат почтовые индексы, которые он обслуживает. Предположим также, что у меня есть другая реляционная таблица, которая устанавливает плату.Убедитесь, что внешний ключ внешнего ключа соответствует внешнему ключу базы

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, что гарантирует, что соответствующий BusinessId из BusinessPostalCodes является такой же, как BusinessId из BusinessPostalCodeFees.

Я понимаю, что могу полностью удалить BusinessId, но я бы предпочел сохранить эту колонку и иметь способ гарантировать, что они будут одинаковыми. Я могу что-нибудь сделать?

+0

написать логику триггера и откат транзакции, которая нарушает ваше правило – techspider

+0

@techspider Спасибо за подсказку, но я думаю, что проверенное ограничение работает очень хорошо. –

ответ

0

В конце концов, решение Джеффри не совсем работа для моей конкретной ситуации. Оба столбца в отношении должны быть уникальными (например, составной ключ). Оказалось, что ответ здесь (для меня) является Проверено ограничение.

Создайте функцию, которую вы хотите иметь ограничение проход или потерпеть неудачу:

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) 
1

Похоже, что (и исправьте меня, если я ошибаюсь), что вы пытаетесь убедиться, что любая запись в столбцах BusinessOd и BusinessPostalCodeId в BusinessPostalCodeFees соответствует записи в таблице BusinessPostalCodes. Если это так, то да, вы можете definitely have a foreign key that references a compound primary key.

Однако, если вам нужно сохранить BusinessId, я бы рекомендовал нормализовать ваши таблицы на шаг дальше, чем у вас есть. Вы получите дубликаты данных как есть.

На стороне записки, я рекомендовал бы вам не использовать типы денежных данных в SQL: See here.

+0

Я совершенно не думал об этом, но это имеет большой смысл. Я думаю, что вы правы, хотя я должен в конечном счете нормализовать его, поскольку я смотрю на это немного сложнее. Это отличная информация, спасибо! –

+0

Добро пожаловать, счастливая база данных! –

+0

Последующие действия, если вы не возражаете. В PostalCodes и FeeTypes есть BusinessId. Есть ли какой-либо путь в реляционной таблице для обеспечения соответствия? –

Смежные вопросы