Создание триггера сервера SQL к переходу из натурального ключа к суррогатному ключу

StackOverflow https://stackoverflow.com/questions/3938287

Вопрос

Бросок

На работе, где мы планируем обесценение натурального ключевого столбца в одной из наших основных таблиц. Проект состоит из 100+ приложений, ссылающихся на эту таблицу / столбец; 400+ хранимых процедур, которые ссылаются на этот столбец напрямую; и огромный массив общих таблиц между этими приложениями, которые также ссылаются на этот столбец.

Большой взрыв и начать с нуля методов находятся из картины. Мы собираемся обесценить эту колонку одно приложение за раз, подтверждают изменения и переходите к следующему ... и у нас есть длительная целевая цель, чтобы приложить это усилие.

Проблема, которую у меня есть, так это то, что многие из этих приложений имеют общие хранимые процедуры и таблицы. Если я полностью преобразую все приложения A в таблицах / хранимых процедурах приложения B и C будут разбиты до преобразования. Они, в свою очередь, могут нарушать приложения D, E, F ... etc. У меня уже есть стратегия, реализованная для классов кода и хранимых процедур, часть я застрял, это переходное состояние базы данных.

Вот а базовый Пример того, что у нас есть:

Users
---------------------------
Code          varchar(32) natural key

Access
---------------------------
UserCode      varchar(32) foreign key
AccessLevel   int

И мы стремимся сейчас только для переходного состояния, как это:

Users
---------------------------
Code          varchar(32) 
Id            int         surrogate key

Access
---------------------------
UserCode      varchar(32)   
UserID        int         foreign key      
AccessLevel   int

Идея, находящаяся в том, что во время переходных фазе не перенесенные приложениями и хранимыми процедурами все еще смогут получить доступ к всем соответствующим данным, и новые могут начать толкать в правильные столбцы - после завершения миграции для всех сохраненных процедур и приложений, которые мы можем, наконец, Снимите дополнительные столбцы.

Я хотел использовать триггеры SQL Server, чтобы автоматически перехватить любую новую вставку / обновление и сделать что-то вроде следующего на каждом из затронутых таблиц:

CREATE TRIGGER tr_Access_Sync
ON Access
INSTEAD OF INSERT(, UPDATE)
AS
BEGIN
  DIM @code as Varchar(32)
  DIM @id as int

  SET @code = (SELECT inserted.code FROM inserted)
  SET @id = (SELECT inserted.code FROM inserted)

  -- This is a migrated application; find the appropriate legacy key
  IF @code IS NULL AND @id IS NOT NULL
     SELECT Code FROM Users WHERE Users.id = @id

  -- This is a legacy application; find the appropriate surrogate key
  IF @id IS NULL AND @code IS NOT NULL
     SELECT Code FROM Users WHERE Users.id = @id

  -- Impossible code:
  UPDATE inserted SET inserted.code=@code, inserted.id=@id
END

Вопрос

2 огромных задачи, которые я до сих пор:

  1. Я не могу сделать «после вставки», потому что нулевые ограничения сделают вставку сбой.
  2. «Невозможный код», который я упомянул, как я хотел бы чисто прокси оригинальный запрос; Если исходный запрос имеет x, y, z столбцы в нем или просто х, я в идеале хотел бы тот же триггер, чтобы сделать это. И если я добавлю / удалю другой столбец, я бы хотел, чтобы триггер оставаться функциональным.

У кого-нибудь есть код примера, где это может быть возможно, или даже альтернативное решение для сохранения этих столбцов правильно заполнено, даже когда только один из значений передается на SQL?

Это было полезно?

Решение 3

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

CREATE TRIGGER tr_Access_Sync
ON Access
INSTEAD OF INSERT
AS 
BEGIN

    /*-- Create a temporary table to modify because "inserted" is read-only */
    /*-- "temp" is actually "#temp" but it throws off stackoverflow's syntax highlighting */
    SELECT * INTO temp FROM inserted

    /*-- If for whatever reason the secondary table has it's own identity column */
    /*-- we need to get rid of it from our #temp table to do an Insert later with identities on */
    ALTER TABLE temp DROP COLUMN oneToManyIdentity

    UPDATE temp 
    SET 
        UserCode = ISNULL(UserCode, (SELECT UserCode FROM Users U WHERE U.UserID = temp.UserID)),
        UserID = ISNULL(UserID, (SELECT UserID FROM Users U WHERE U.UserCode = temp.UserCode))

    INSERT INTO Access SELECT * FROM temp

END

Другие советы

Хитрый бизнес ...

Хорошо, прежде всего: этот триггер будет НЕТ Работа во многих обстоятельствах:

SET @code = (SELECT inserted.code FROM inserted)
SET @id = (SELECT inserted.code FROM inserted)

Триггер может быть вызван с набором строк в Inserted псевдо таблицы - какой из них вы собираетесь выбрать здесь ?? Вам нужно написать ваш триггер таким образом, что он будет работать, даже когда вы получаете 10 строк в Inserted стол. Если оператор SQL вставляет 10 строк, ваш триггер будет нет быть уволенным в десять раз - один для каждого ряда - но только однажды Для всей пакеты - вам нужно принять это во внимание!

Второй момент: я бы попытался сделать идентификатор IDENTITY Поля - тогда они всегда получат значение - даже для «устаревших» приложений. Эти «старые» приложения должны предоставлять вместо этого наследие - так что вы должны быть там хорошими. Единственная проблема, которую я вижу и не знаю, как вы справляетесь с тем, что это вставки из уже преобразованного приложения - делают ли они наследие «Старый стиль» наследие? Если нет - как быстро вам нужно иметь такой ключ?

Я думаю, что я думаю, будет «работой очистки», которая будет проходить через стол и получить все строки с нулевым устаревшим ключом, а затем обеспечить для него некоторое значимое значение. Сделайте эту регулярную хранимую процедуру и выполните ее каждый день, четыре часа, 30 минут - все, что подходит для ваших потребностей. Тогда вам не нужно иметь дело с триггерами и всеми ограничениями, которые у них есть.

Разве невозможно было бы сделать схему изменения «BigBang», но создайте виды на вершину этих таблиц, которые «скрыть» изменение?

Я думаю, что вы можете обнаружить, что вы просто откладываете прерывки в более поздний момент времени: «Мы собираемся обесценить эту колонку одно приложение за раз» - это может быть моим наимелостью, но я не вижу, как это когда-либо работать.

Конечно, худший беспорядок может возникнуть, когда разные приложения делают вещи по-разному?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top