web-dev-qa-db-ja.com

SQL Serverでリンクサーバーのシノニムの列をフェッチする方法

ローカル(システムで実行されているSQL Server)とリモート(別のシステムで実行されているSQL Server)の2つのサーバーを使用しています。ローカルサーバーに、リモートサーバーにあるテーブルのシノニムを作成しました。

使用されている同義語-CREATE SYNONYM [dbo].[test] FOR remoteserver_name .[database_name].[schema_name].object_name

要件

シノニムの列をフェッチする必要があります。

SQLサーバーで以下のクエリを使用して、シノニムの列を取得できます。

select * from dbo.test

場所

dboはシノニムで作成されたスキーマ名(ローカルサーバースキーマ名)で、testはシノニム名です。

以下のクエリを使用してシノニムの列を取得しようとしましたが、列をフェッチできません

SELECT sys.schemas.name   AS SCHEMA_NAME,
       sys.synonyms.name  AS view_name,
       sys.columns.name   AS COL_NAME,
       sys.types.name     AS data_typename
FROM   sys.columns
       INNER JOIN sys.synonyms
            ON  OBJECT_ID(sys.synonyms.base_object_name) = sys.columns.object_id
       INNER JOIN sys.schemas
            ON  sys.schemas.schema_id = sys.synonyms.schema_id
       LEFT OUTER JOIN sys.types
            ON  sys.columns.system_type_id = sys.types.system_type_id
WHERE  sys.types.system_type_id = sys.types.user_type_id
       AND sys.schemas.name = N'scehmaname'
       AND sys.synonyms.name = N'synonymname'

シノニムの列を取得する別の方法を提案したり、上記のクエリを修正したりできますか?

あなたのエラーは、別のリモートサーバーからのオブジェクトについてlocalサーバーに質問することです。

OBJECT_ID(sys.synonyms.base_object_name)はローカルサーバー内で動作するため、コードからのOBJECT_ID()はローカルサーバーで解決されますが、リモートサーバーから名前を渡すため、NULL ここに。

リモートオブジェクトの_object_id_を取得する場合は、次のように実行する必要があります。

_exec ('select object_id(''[remote_db].[remote_schema].[remote_table]'')') at [remote_server]
_

そして一般的に、リモートオブジェクトの列を取得したい場合は、remoteサーバーでコードを実行し、remoteオブジェクトの列をリモート _sys.columns_ remoteデータベースで、たとえば、次のように:

_declare @obj_name sysname = '[remote_server].[remote_db].[remote_table]';
declare @code nvarchar(4000) =
N'select c.name   AS COL_NAME,
       t.name     AS data_typename
from sys.columns c
     join sys.types t
        on c.system_type_id = t.system_type_id
where c.object_id = object_id(@obj_name)';

declare @param_def nvarchar(400) = N'@obj_name sysname';

execute [remote_server].[remote_db].dbo.sp_executesql @code, @param_def, @obj_name = @obj_name;
_

更新

シナリオ:2つのデータベース(database1と(database2)を持つサーバーAがあります。database1にシノニムを作成しました。CREATESYNONYM [dbo]。[synonym] FOR database2。[dbo]。[objectname]クエリを一般的に書き込む方法このシナリオとリモートオブジェクトのobject_idを取得しますか?

Scott Hodginが述べたように、PARSENAME()を使用して、次のようにオブジェクトのremote_serverの部分を取り除くことができます。

_declare @cmd varchar(8000) = (select 
       'select object_id(' + 
       quotename (
       PARSENAME(base_object_name,3)  + '.' + 
       PARSENAME(base_object_name,2)  + '.' + 
       PARSENAME(base_object_name,1), '''')+ ')'
from sys.synonyms )

exec (@cmd) at [server_A];
_

更新1

ローカルサーバー(サーバーA)からリモートサーバー(サーバーB)のストアドプロシージャにアクセスできるかどうかを知りたい。

...

ストアドプロシージャのリストを取得できません。

次のコードを使用して、リモートストアドプロシージャのリストを取得できます。

_select *
from remote_server.remote_db.sys.objects
where type = 'p';
_
4
sepupic

sepupic の回答に賛成しました。

これは、これを行う方法のもう1つの例です。要件に応じて調整する必要がある場合があります。

動的SQLと sp_columns を使用しています。

私の例では、次のようにsyntestという同義語を作成しました。

CREATE SYNONYM [dbo].[SynTest] FOR [SqlCompare].[SCOPERATIONAL_DBCC].[SCFBDM].[CFG_LINE_BUS]

この同義語は、サーバーSqlCompare、データベースSCOPERATIONAL_DBCC、スキーマSCFBDM、およびテーブルCFG_LINE_BUSを指します。

select * from sys.synonyms where name = 'syntest'を発行すると、base_object_nameが[SqlCompare].[SCOPERATIONAL_DBCC].[SCFBDM].[CFG_LINE_BUS]であることがわかります。 [〜#〜] parsename [〜#〜] を使用して、base_object_nameの個々の部分を抽出し、動的SQLステートメントを作成できます

Declare @Cmd nvarchar(4000)

select @Cmd = 
    'exec ' + PARSENAME(base_object_name,4) + '.' + 
    PARSENAME(base_object_name,3) + 
    '.dbo.sp_columns @table_name = ' + '''' + 
    PARSENAME(base_object_name,1) + 
    ''',@table_owner = ' + 
    '''' +  PARSENAME(base_object_name,2) + ''''
    from sys.synonyms where name = 'syntest'    --<<<< The name of your synonym
PRINT @CMD
exec sp_executesql @cmd

PRINTステートメントは、構築された動的SQLを次のように示します。

exec SqlCompare.SCOPERATIONAL_DBCC.dbo.sp_columns @table_name = 'CFG_LINE_BUS',@table_owner = 'SCFBDM'

3
Scott Hodgin