Предварительно заполнить внешние ключи в SQL новой строкой

Я пытаюсь написать сценарий SQL, который будет проходить через таблицу с вновь созданным FK и предварительно заполнять ключ новой строкой во внешней таблице. Я не на 100% знаю, как это сделать или возможно ли это в одном выражении, но вот моя попытка:

UPDATE [dbo].[Blogs]
set AuthorSecurableId = inserted.Id
FROM  [dbo].[Blogs] updating
INNER JOIN 
    (INSERT INTO [dbo].[Securables] (Name) 
     OUTPUT Inserted.id, ROW_NUMBER() OVER (ORDER BY Inserted.Id) as rownum
        SELECT 'Admin : ' + Name
        FROM Blogs
        WHERE AuthorSecurableId is null) inserted ON ROW_NUMBER() OVER (ORDER BY updating.Id) = inserted.rownum 
WHERE updating.AuthorSecurableId is null

Когда я делаю это, я получаю следующую ошибку

Сообщение 10727, уровень 15, состояние 1, строка 5
Вложенные операторы INSERT, UPDATE, DELETE или MERGE не допускаются ни с одной стороны оператора JOIN или APPLY.

Ниже приведен простой вид схемы, которая у меня есть

введите здесь описание изображения

Я хотел бы создать защищаемый объект для каждого блога, у которого его нет, и заполнить эти блоги AuthorSecurableId ID вновь созданного защищаемого объекта.

Я думаю, что мог бы сделать это с помощью курсора, но мне было интересно, есть ли лучший подход с одним оператором


person Not loved    schedule 27.05.2013    source источник
comment
Вау, это безумно сложно сделать в одном запросе. Почему бы не создать хранимую процедуру, которая открывает курсор (выберите *, где ноль), перебирает его, вставляет новую защищенную таблицу, получает @@identity и обновляет запись в блоге?   -  person Steven Moseley    schedule 27.05.2013
comment
Какая версия SQL Server?   -  person gbn    schedule 27.05.2013
comment
@StevenMoseley, да, может быть, мне стоит просто стиснуть зубы и использовать курсор. Я не хочу делать это SP, так как на самом деле я хочу сделать это только один раз, весь смысл в том, чтобы обновить БД, а затем сделать столбец необнуляемым.   -  person Not loved    schedule 27.05.2013
comment
@gbn должен работать на SQL 2012 и SQL Azure.   -  person Not loved    schedule 27.05.2013
comment
Вы не можете сделать INSERT и UPDATE в одном выражении. Вы должны сделать их в 2 операторах.   -  person ypercubeᵀᴹ    schedule 27.05.2013
comment
ПОЧЕМУ вы хотите сделать это в одном выражении?   -  person David Abrahamsson    schedule 27.05.2013


Ответы (1)


Вы можете использовать слияние для Securables с выводом в табличную переменную или временную таблицу и отдельное обновление для Blogs.

declare @T table
(
  SecID int,
  BlogID int
);

merge Securables T
using (
      select 'Admin : '+B.Name as Name, B.Id
      from Blogs as B
      where B.AuthorSecurabledId is null
      ) as S
on 0 = 1
when not matched by target then
  insert (Name) values (S.Name)
output inserted.Id, S.Id
  into @T;

update Blogs
set AuthorSecurabledId = T.SecID
from @T as T
where Blogs.Id = t.BlogID;

скрипт SQL

person Mikael Eriksson    schedule 27.05.2013
comment
Спасибо, этот метод определенно работает. Я делаю это с помощью метода миграции базы данных EF, поэтому я предпочитаю избегать временных таблиц и курсоров, но, похоже, это самый простой способ. - person Not loved; 27.05.2013