2016-03-31 3 views
1

У меня есть таблица под названием «Accounts» с composite primary key, состоящими из 2-х колонка: Account_key и Account_Start_date как с типом данными int и другим, не ключевым столбцом с именем Accountnumber(bigint).Обеспечение 1: 1 и 1: Многая кардинальность в денормализованной складской таблице с композитным первичным ключом

Account_key должны иметь один или несколько Accountnumber(bigint), а не наоборот означает 1 или много ACCOUNTNUMBER может иметь только 1 Account_key. Если вы попытаетесь вставить одну и ту же учетную запись Account_key и тот же аккаунт_Start_date, то primary key constraint останавливает это, конечно, потому что они вместе являются первичным ключом.

Однако, если вы вставляете существующую учетную запись с другим несуществующим Account_Start_date, вы можете вставить случайный номер журнала, как хотите, без каких-либо ограничений, жалующихся на него, и вдруг у вас есть строки со многими и многими отношениями между Account_key и Accountnumber, и мы не делаем хочет это.

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

Существует еще одна таблица (случай), где 1 'Account_Key' может быть связан только с 1 ' AccountNumber 'означает отношение 1..1, все остальные вещи одинаковы, за исключением того, что между ними должно быть отношение 1..1. Уникальный индекс havent работает для меня, по крайней мере, просто подумайте, хочу ли я изменить таблицу Accounts или поставить триггер или даже индекс, так что это будет отношение 1..1 между «Account_Key» и «AccountNumber»,?

+0

Даты начала в ключе в обычном режиме. Возможно ли, чтобы у одной из ваших учетных записей было более 1 даты начала? –

+0

Да, 1 Номер счета может иметь более 1 Account_start_date. – Hankman3000

+0

ну, первая ошибка в том, что вы называете Account_Key не ключом. Кто создает этот ключ? Какие ограничения на него? – alessalessio

ответ

1

Если это была таблица OLTP, решение было бы правильно нормализовать данные в две таблицы, но это таблица DW, поэтому имеет смысл иметь все это в одной таблице.

В этом случае, вы должны добавить FOR/AFTER Trigger ON INSERT, UPDATE, который делает запрос к inserted псевдо-таблицы. Запрос может быть простым 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; 
+0

Большое спасибо за это. И да struzky это DW благодарит меня за понимание:) – Hankman3000

+0

Да, это сработало отлично! Существует еще одна таблица (случай), где 1 Account_Key может быть связан только с 1 AccountNumber значением 1..1, все остальные вещи одинаковы, за исключением того, что должно быть отношение 1..1 между ... - это то, что даже возможно с вашим триггером? – Hankman3000

+0

@Henrik Пожалуйста, добавьте это в вопрос. Но это должен быть просто уникальный Индекс (предполагая, что это, как вы сказали, другая таблица, а не та, в которой был начальный вопрос). Или у него также будет несколько дат? Опять же, пожалуйста, добавьте детали в вопрос. –

0

Если я вас правильно понял, вы хотите:

  1. Любой данный AccountNumber может быть связано только с одним AccountKey
  2. Любой данный AccountKey может быть связано с несколькими AccountNumbers

Если это правильно, вы можете достичь этого с помощью CHECK CONSTRAINT, который вызывает UDF.

EDIT:

псевдопользователей-логика для проверки ОГРАНИЧЕНИЙ может быть:

IF EXISTS anotherRow 
WHERE theOtherAccountNumber = thisAccountNumber 
AND theOtherAccountKey <> thisAccountKey 
THEN False (do not allow this row to be inserted) 
ELSE True (allow the insertion) 

Я бы поставил эту логику в UDF, которая возвращает истинное или ложное, чтобы сделать СНЕСК проще.

+0

Да! например, 10 учетных записей могут быть связаны только с одним AccountKey, а один AccountKey может быть связан с несколькими номерами AccountNumbers в той же таблице. – Hankman3000

+0

Тогда ПРОВЕРКА КОНСТРАИРОВАНИЯ - это путь. Вот как я это сделаю. ТРИГГЕР также будет работать, но я предпочитаю ограничения. –

+0

Звучит неплохо, Tab, вы можете уточнить его в какой-то логике или что-то еще? Так как я пробовал много сочетаний с ограничениями проверки, спасибо! Должен ли я использовать UDF, который вы предложили? – Hankman3000

0

Создайте дополнительную таблицу AccountKeyNumbers (это ваш выбор, конечно) со столбцами Account_Key и Account_Number.

Сделать номер_шт. Первичного ключа.

Обратите внимание, что вы не можете добавить учетную запись дважды и, следовательно, не можете связать ее с двумя разными учетными записями Account_Keys в этой таблице.

Теперь вы добавляете дополнительное уникальное ограничение на Account_Number плюс Account_Key. В этой таблице вы поместите все номера учетных записей и соответствующие им ключи.

Наконец, вы определяете внешний ключ в своей учетной записи в столбцах Account_Key plus Account_Number, ссылаясь на уникальное ограничение в таблице AccountKeyNumbers.

Теперь вы гарантировали, что в учетные записи могут быть вставлены только действительные комбинации клавиш/номеров, и ни один из двух учетных записей AccountKey не может иметь одинаковое число. Нам потребовалось дополнительное уникальное ограничение, которое не способствует целостности данных таблицы AccountKeyNumbers, просто чтобы создать внешний ключ, который должен указывать на первичное или уникальное ограничение.

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