Объект не существует или недействителен с использованием sp_changeobjectowner - PullRequest
0 голосов
/ 22 сентября 2011

Я изменил схему таблицы с dbo на db_owner, используя приведенный ниже оператор SQL (SQL 2008 R2):

DECLARE @old sysname, @new sysname, @sql varchar(1000)

SELECT
  @old = 'db_owner'
  , @new = 'dbo'
  , @sql = '
  IF EXISTS (SELECT NULL FROM INFORMATION_SCHEMA.TABLES
  WHERE
      QUOTENAME(TABLE_SCHEMA)+''.''+QUOTENAME(TABLE_NAME) = ''?''
      AND TABLE_SCHEMA = ''' + @old + '''
  )
  EXECUTE sp_changeobjectowner ''?'', ''' + @new + ''''

EXECUTE sp_MSforeachtable @sql

Мне нужно изменить его обратно, переключив старые и новые параметры имени, но яполучение ошибки:

Сообщение 15001, уровень 16, состояние 1, процедура sp_changeobjectowner, строка 75 Объект '[db_owner]. [language_link]' не существует или не является допустимым объектом для этой операции.

Эта таблица существует, хотя и с этим старым db_owner.Любой способ исправить это?

Вот скриншот того, как я могу сказать, что он все еще принадлежит db_owner.Только некоторые столы были перемещены обратно должным образом:

enter image description here

1 Ответ

1 голос
/ 22 сентября 2011

Вы уверены, что должны использовать sp_changeobjectowner?(У объектов больше нет владельцев по состоянию на SQL 2005.) Как вы проверили существование db_owner.language_link?Лично я бы использовал ALTER SCHEMA для этого, и я также склонялся бы к представлениям каталога (sys.tables), а не information_schema.tables.Наконец, я бы не стал использовать недокументированный и неподдерживаемый sp_MSforeachtable - я выделил проблемы с sp_MSforeachdb, которые, вероятно, являются потенциальными проблемами здесь, потому что код очень похож.

DECLARE
    @old SYSNAME = N'db_owner',
    @new SYSNAME = N'dbo',
    @sql NVARCHAR(MAX) = N'';

SELECT @sql += CHAR(13) + CHAR(10) + 'ALTER SCHEMA ' + @new 
    + ' TRANSFER ' + QUOTENAME(SCHEMA_NAME([schema_id]))
    + '.' + QUOTENAME(name) + ';'
    FROM sys.tables AS t
    WHERE SCHEMA_NAME([schema_id]) = @old
    AND NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = t.name
    AND SCHEMA_NAME([schema_id]) = @new);

PRINT @sql;
--EXEC sp_executesql @sql;

EDIT добавление кодачтобы найти объекты, которые являются общими для обеих схем.И переместить те, что уже есть в новой схеме, в какую-то фиктивную схему:

CREATE SCHEMA dummy AUTHORIZATION dbo;
GO
DECLARE 
    @old SYSNAME = N'db_owner',
    @new SYSNAME = N'dbo',
    @sql NVARCHAR(MAX) = N'';

SELECT @sql += CHAR(13) + CHAR(10) + 'ALTER SCHEMA dummy TRANSFER '
    + QUOTENAME(@new) + '.' + QUOTENAME(t1.name) + ';'
    FROM sys.tables AS t1
    INNER JOIN sys.tables AS t2
    ON t1.name = t2.name
    WHERE t1.schema_id = SCHEMA_ID(@new)
    AND t2.schema_id = SCHEMA_ID(@old);

PRINT @sql;
-- EXEC sp_executesql @sql;

Но на самом деле это звучит так, будто вы что-то напутали, и это требует некоторой ручной очистки ...

РЕДАКТИРОВАТЬ добавляя доказательства, потому что OP, похоже, убежден, что этот код не работает, потому что невозможно перенести вещи в схему dbo.Нет, это не так, просто невозможно переместить dummy.floob -> dbo.floob, если уже есть объект с именем dbo.floob.Обратите внимание, что не может быть таблицей!

CREATE DATABASE schema_test;
GO
USE schema_test;
GO
CREATE SCHEMA floob AUTHORIZATION dbo;
GO
CREATE TABLE dbo.x(a INT);
CREATE TABLE dbo.y(a INT);
GO

Переместить все таблицы из dbo -> floob:

DECLARE
    @old SYSNAME = N'dbo',
    @new SYSNAME = N'floob',
    @sql NVARCHAR(MAX) = N'';

SELECT @sql += CHAR(13) + CHAR(10) + 'ALTER SCHEMA ' + @new 
    + ' TRANSFER ' + QUOTENAME(SCHEMA_NAME([schema_id]))
    + '.' + QUOTENAME(name) + ';'
    FROM sys.tables AS t
    WHERE SCHEMA_NAME([schema_id]) = @old
    AND NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = t.name
    AND SCHEMA_NAME([schema_id]) = @new);

EXEC sp_executesql @sql;
GO
SELECT SCHEMA_NAME([schema_id]),name FROM sys.tables;

Результаты:

enter image description here

Переместить все таблицы обратно из floob -> dbo:

DECLARE
    @old SYSNAME = N'floob',
    @new SYSNAME = N'dbo',
    @sql NVARCHAR(MAX) = N'';

SELECT @sql += CHAR(13) + CHAR(10) + 'ALTER SCHEMA ' + @new 
    + ' TRANSFER ' + QUOTENAME(SCHEMA_NAME([schema_id]))
    + '.' + QUOTENAME(name) + ';'
    FROM sys.tables AS t
    WHERE SCHEMA_NAME([schema_id]) = @old
    AND NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = t.name
    AND SCHEMA_NAME([schema_id]) = @new);

EXEC sp_executesql @sql;
GO
SELECT SCHEMA_NAME([schema_id]),name FROM sys.tables;

Результаты:

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...