Ответ 1
Иногда триггер BEFORE
может быть заменен на AFTER
one, но это не похоже на ситуацию в вашей ситуации, поскольку вам явно нужно предоставить значение до того, как вставка будет выполнена. Таким образом, для этой цели наиболее близкой функциональностью, по-видимому, является триггер INSTEAD OF
, поскольку @marc_s предложил в своем комментарии.
Обратите внимание, однако, что, как указывают названия этих двух типов триггеров, существует принципиальное различие между триггером BEFORE
и INSTEAD OF
. Хотя в обоих случаях триггер выполняется в то время, когда действие, определенное оператором, вызывающим триггер, не произошло, в случае триггера INSTEAD OF
действие никогда не должно происходить вообще. Реальное действие, которое вам нужно сделать, должно выполняться самим триггером. Это очень не похоже на триггерную функциональность BEFORE
, где инструкция всегда должна выполняться, если, конечно, вы явно откатываете ее обратно.
Но есть еще одна проблема для решения на самом деле. Как показывает ваш Oracle script, триггер, который нужно преобразовать, использует другую функцию, не поддерживаемую SQL Server, которая имеет значение FOR EACH ROW
. В SQL Server нет триггеров для каждой строки, только для каждого оператора. Это означает, что вам всегда нужно помнить, что вставленные данные представляют собой набор строк, а не только одну строку. Это добавляет больше сложности, хотя это, вероятно, завершит список вещей, которые вам нужно учитывать.
Итак, это действительно две вещи, которые нужно решить тогда:
-
заменить функциональность
BEFORE
; -
замените функциональность
FOR EACH ROW
.
Моя попытка решить их ниже:
CREATE TRIGGER sub_trg
ON sub1
INSTEAD OF INSERT
AS
BEGIN
DECLARE @new_super TABLE (
super_id int
);
INSERT INTO super (subtype_discriminator)
OUTPUT INSERTED.super_id INTO @new_super (super_id)
SELECT 'SUB1' FROM INSERTED;
INSERT INTO sub (super_id)
SELECT super_id FROM @new_super;
END;
Вот как это работает:
-
Такое же количество строк, которые вставляются в
sub1
, сначала добавляется кsuper
. Сгенерированные значенияsuper_id
сохраняются во временном хранилище (табличная переменная называется@new_super
). -
Вновь вставленные
super_id
теперь вставляются вsub1
.
На самом деле ничего слишком сложного, но выше будет работать, только если у вас нет других столбцов в sub1
, чем те, которые вы указали в своем вопросе. Если есть другие столбцы, вышеуказанный триггер должен быть немного сложнее.
Проблема состоит в том, чтобы назначить новую super_id
каждой вставленной строке отдельно. Один из способов реализации сопоставления может быть следующим:
CREATE TRIGGER sub_trg
ON sub1
INSTEAD OF INSERT
AS
BEGIN
DECLARE @new_super TABLE (
rownum int IDENTITY (1, 1),
super_id int
);
INSERT INTO super (subtype_discriminator)
OUTPUT INSERTED.super_id INTO @new_super (super_id)
SELECT 'SUB1' FROM INSERTED;
WITH enumerated AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rownum
FROM inserted
)
INSERT INTO sub1 (super_id, other columns)
SELECT n.super_id, i.other columns
FROM enumerated AS i
INNER JOIN @new_super AS n
ON i.rownum = n.rownum;
END;
Как вы можете видеть, в @new_user
добавлен столбец IDENTIY(1,1)
, поэтому временно вставленные значения super_id
будут дополнительно перечислены начиная с 1. Чтобы обеспечить сопоставление между новым super_id
и новыми данными строки, функция ROW_NUMBER
используется для перечисления строк INSERTED
. В результате каждая строка в наборе INSERTED
теперь может быть связана с одним super_id
и, таким образом, дополняется полной строкой данных, которая должна быть вставлена в sub1
.
Обратите внимание, что порядок, в котором вставлен новый super_id
, может не соответствовать порядку, в котором они назначены. Я считал, что это не проблема. Все новые созданные строки super
идентичны, кроме идентификаторов. Итак, все, что вам нужно, это просто взять одну новую super_id
за новую строку sub1
.
Если, однако, логика вставки в super
более сложна и по какой-то причине вам нужно точно запомнить, какой новый super_id
был создан для новой строки sub
, вы, вероятно, захотите рассмотреть метод отображения, обсуждаемый в этом вопросе: