2013-03-26 8 views
5

複雑なビューの結果をレポートのためにテーブルにダンプする簡単なスクリプトを作成しようとしています。シノニムを使用して、ビュー名とテーブル名を簡単に調整しました。シノニムの後ろにテーブルが存在するかどうかを確認するには

考えられるのは、スクリプトのユーザーは、ソースとして使用するビューの名前と、ターゲットレポートテーブルの名前を開始時と終了時に入れられるということです。テーブルが存在しない場合、スクリプトはそれを作成する必要があります。テーブルがすでに存在する場合、スクリプトは、テーブルの上にまだ存在しないビューからのレコードのみをコピーする必要があります。

以下のスクリプトは、これらすべての要件をカバーしていますが、私は同義語の後ろにテーブルが既に存在するかどうかを確認するための良い方法を見つけることができません。

CREATE SYNONYM SourceView FOR my_view 
CREATE SYNONYM TargetReportingTable FOR my_table 

-- Here's where I'm having trouble, how do I check if the underlying table exists? 
IF (SELECT COUNT(*) FROM information_schema.tables WHERE table_name = TargetReportingTable) = 0 
    BEGIN 
    -- Table does not exists, so insert into. 
    SELECT * INTO TargetReportingTable FROM SourceView 
    END 
ELSE 
    BEGIN 
    -- Table already exists so work out the last record which was copied over 
    -- and insert only the newer records. 
    DECLARE @LastReportedRecordId INT; 
    SET @LastReportedRecordId = (SELECT MAX(RecordId) FROM TargetReportingTable) 
    INSERT INTO TargetReportingTable SELECT * FROM SourceView WHERE RecordId > @LastReportedRecordId 
    END 

DROP SYNONYM SourceView 
DROP SYNONYM TargetReportingTable 

私はちょうどスクリプトの使用者を得ることができる知っていますテーブル名を 'information_schema'行にコピーして、一番上の同義語にコピーしますが、エラーのスコープが残ります。

私は変数にテーブル名を入れて、SQLを文字列として出すような、不潔なことをすることもできると知っていますが、それは私がちょっと気分が悪くなってしまいます!

シノニムの背後にある表が存在するかどうかを確認するうえで、洗練された洗練されたSQL方法がありますか?または、問題を解決する全く別の方法ですか?

+2

、特定のRDBMSとだけではなく、「SQL」 – Barmar

+1

申し訳ありませんが、新人のエラーをあなたの質問にタグを付けてくださいSQL ServerでOBJECT_ID関数avaliableを使用して、データベースに存在するかどうかをテストすることができます。編集していただきありがとうございます。 – Tom

+0

シノニムがデータベース内のシノニムポイントと見なすことはできますか?またはシノニムが他のデータベースを参照している可能性がありますか? –

答えて

3

最も洗練されたソリューションではありませんが、sys.synonymsテーブルをsys.tablesテーブルに参加させて、テーブルが存在するかどうかを確認できます。

テーブルが存在しない場合、結合は失敗し、0行が得られます(したがって、IF EXISTSはfalseになります)。テーブルが存在しない場合は、意志の成功に参加して、あなたは1行を取得(真)になります。

IF EXISTS( SELECT * 
       FROM sys.synonyms s 
       INNER JOIN sys.tables t ON REPLACE(REPLACE(s.base_object_name, '[', ''), ']', '') = t.name 
       WHERE s.name = 'TargetReportingTable') 
BEGIN 
    -- Does exist 
END 
ELSE 
BEGIN 
    -- Does not exist 
END 

はあなたがチェックしたい方同義語で'TargetReportingTable'を交換してください。

+0

ありがとうございます。最も美しいクエリではないと言っても、少なくともスクリプトのユーザーは複数の場所にテーブル名を貼り付ける必要はありません。 – Tom

+1

'REPLACE'を使用するのではなく、テーブルとスキーマの情報を取得する信頼性の高い方法は、' PARSENAME'関数を使うことです。参照:https://msdn.microsoft.com/en-us/library/ms188006.aspx – Nathan

1

あなたは、動的SQLでこれを行うことができます。

-- create synonym a for information_schema.tables 
create synonym a for b 

declare @exists int = 1; 
begin try 
    exec('select top 0 * from a'); 
end try 
begin catch 
    set @exists = 0; 
end catch 
select @exists; 

同義語の参照はコンパイル時にキャッチされるので、これは、非動的SQLでは動作しません。つまり、コードがメッセージで失敗し、ブロックtry/catchによってキャッチされません。動的SQLでは、ブロックはエラーをキャッチします。

+0

ありがとうございます。私はこれがどのように役立つのかよく分かりません。これは、私が名前を取得しようとしているinformation_schemaテーブルではありません。シノニムの後ろにある実際のテーブル(上記のスクリプトの中の 'TargetReportingTable')です。私は何かを逃したか? – Tom

+0

@Tom。 。 。これらはコードが動作することを示す単なる例です。私がテストしているデータベースでは、 'b'は存在しないので' 0'が '@ exists'に割り当てられます。存在するテーブルに設定すると、 '1 'が割り当てられます。 –

2

シノニムが別のデータベースを参照していた場合、上記の解決策は私にとっては役に立たなかった。私は最近、特定のデータベース・オブジェクトに対する権限を表示するのに便利ですので、私は次のようにこれを使用することができる把握関数[fn_my_permissions]を発見しました:パーティーへ

IF EXISTS 
(
select * 
from sys.synonyms sy 
cross apply fn_my_permissions(sy.base_object_name, 'OBJECT') 
WHERE sy.name = 'TargetReportingTable' 
) 
print 'yes - I exist!' 
+0

私はOracleのバージョンで "sy.sname"を使用する必要がありました。また、私の目的には十字架適用が必要ではない – Mangusta

1

後期、私はテストするクエリを作成しましたSynonymsの存在とあなたと共有する。

DECLARE @Synonyms table 
(
    ID int identity(1,1), 
    SynonymsDatabaseName sysname, 
    SynonymsSchemaName sysname, 
    SynonymsName sysname, 
    DatabaseName nvarchar(128), 
    SchemaName nvarchar(128), 
    ObjectName nvarchar(128), 

    Remark nvarchar(max), 
    IsExists bit default(0) 
) 

INSERT @Synonyms (SynonymsDatabaseName, SynonymsSchemaName, SynonymsName, DatabaseName, SchemaName, ObjectName) 
SELECT 
    DB_NAME() AS SynonymsDatabaseName, 
    SCHEMA_NAME(schema_id) AS SynonymsSchemaName, 
    name AS SynonymsName, 
    PARSENAME(base_object_name,3) AS DatabaseName, 
    PARSENAME(base_object_name,2) AS SchemaName, 
    PARSENAME(base_object_name,1) AS ObjectName 
FROM sys.synonyms 


SET NOCOUNT ON 

DECLARE @ID int = 1, @Query nvarchar(max), @Remark nvarchar(max) 

WHILE EXISTS(SELECT * FROM @Synonyms WHERE ID = @ID) 
BEGIN 

    SELECT 
     @Query = 'SELECT @Remark = o.type_desc FROM [' + DatabaseName + '].sys.objects o INNER JOIN sys.schemas s ON o.schema_id = s.schema_id WHERE s.name = ''' + SchemaName + ''' AND o.name = ''' + ObjectName + '''' 
    FROM @Synonyms WHERE ID = @ID 

    EXEC sp_executesql @Query, N'@Remark nvarchar(max) OUTPUT', @Remark OUTPUT; 

    UPDATE @Synonyms SET IsExists = CASE WHEN @Remark IS NULL THEN 0 ELSE 1 END, Remark = @Remark WHERE ID = @ID 

    SELECT @ID += 1, @Remark = NULL 
END 

SELECT * FROM @Synonyms 
0

シノニムが

IF OBJECT_ID('YourDatabaseName..YourSynonymName') IS NOT NULL 
    PRINT 'Exist SYNONYM' 
ELSE 
    PRINT 'Not Exist SYNONYM' 
関連する問題