OBJECT_ID объекта в другой базе данных - как найти идентификатор базы данных или имя/полное имя объекта?
Пример:
USE AnotherDB
-- This works - same ID as from other DB
SELECT OBJECT_ID('AnotherDB.ASchema.ATable')
-- This works
SELECT OBJECT_NAME(OBJECT_ID('AnotherDB.ASchema.ATable'))
USE ThisDB
-- This works - same ID as from other DB
SELECT OBJECT_ID('AnotherDB.ASchema.ATable')
-- Gives NULL
SELECT OBJECT_NAME(OBJECT_ID('AnotherDB.ASchema.ATable'))
Очевидно, что функции метаданных ожидают текущую базу данных. Записи BOL обычно имеют такой язык для таких функций, как OBJECT_NAME
и т.д.:
База данных Microsoft SQL Server 2005 Engine предполагает, что object_id находится в контекст текущей базы данных. запрос, ссылающийся на object_id в другая база данных возвращает NULL или неправильные результаты.
Причины, по которым мне нужно это сделать:
-
Я не могу использовать другую базу данных из SP
-
Я не могу создать прокси UDF-заглушку (или изменить что-либо) в других базах данных или в master (или любой другой базе данных, кроме моей), чтобы помочь мне.
Итак, как я могу получить базу данных из OBJECT_ID('AnotherDB.ASchema.ATable')
, когда я в ThisDB?
Моя цель - взять возможно частично квалифицированное имя из таблицы конфигурации, разрешив его в текущем контексте на полное имя, использовать PARSENAME для получения имени базы данных, а затем динамического SQL для создания script, чтобы иметь возможность для непосредственного доступа к таблицам метаданных с помощью database.sys.*
или USE db; sys.*
Ответы
Ответ 1
Правильно ли я понимаю, что вам нужен идентификатор db из другогоDB?
SELECT *
FROM master..sysdatabases
WHERE name = 'AnotherDB'
В противном случае вы можете использовать другой db в динамическом SQL, если это помогает:
DECLARE @SQL NVARCHAR(MAX)
, @objId INT
SET @SQL = N'
USE AnotherDB
SELECT @id = OBJECT_ID(''customer'')
'
EXEC SP_EXECUTESQL @SQL
, N'@id INT OUTPUT'
, @id = @objId OUTPUT
SELECT @objId
ИЛИ Выполнить SP в других dbs с помощью:
EXEC AnotherDB.dbo.ProcedureName
@paramX = ...
, @paramY = ...
Ответ 2
Вы должны иметь возможность сделать это:
SELECT
name
FROM
AnotherDB.sys.objects --changes context
WHERE
object_id = OBJECT_ID('AnotherDB.ASchema.ATable')
Это то, что вы эффективно делаете с OBJECT_ID('AnotherDB.ASchema.ATable')
Это означает, что вы можете полагаться на dbname.sys.object и избегать путаницы с функциями метаданных.
Примечание: новые виды каталога предназначены для использования и не изменяются с версии на версию, как по ссылке. Раньше считалось, что плохая практика использует системные таблицы, но стигма все еще остается.
Таким образом, вы можете безопасно полагаться на sys.object, а не на функции метаданных.
Ответ 3
Взгляните на функцию PARSENAME в TSQL - позволит вам вытащить любую из 4 частей части полностью ( или не полностью) квалифицированное имя. Для базы данных в вашем примере:
select parsename('AnotherDB.ASchema.ATable',3)
возвращает:
AnotherDB
select parsename('AnotherDB.ASchema.ATable',2)
возвращает:
ASchema
Если вы не полностью квалифицированы, вы получите нулевые результаты, если вы попросите часть имени, которое не включено в строку:
select parsename('ASchema.ATable',3)
возвращает:
NULL
Ответ 4
У меня была такая же проблема, но с OJBECT_SCHEMA_NAME. После ответа chadhoc с использованием parseame работает с OBJECT_NAME, например:
DECLARE @OrigTableName NVARCHAR(MAX);
SELECT @OrigTableName = 'AnotherDB.ASchema.ATable'
SELECT OBJECT_NAME(OBJECT_ID(@OrigTableName), DB_ID(PARSENAME(@OrigTableName, 3)))
, OBJECT_SCHEMA_NAME(OBJECT_ID(@OrigTableName), DB_ID(PARSENAME(@OrigTableName, 3)))