2013-03-26 17 views
5

Ich versuche, ein einfaches Skript zu erstellen, um die Ergebnisse einer komplexen Ansicht in eine Tabelle für die Berichterstattung auszugeben. Ich habe Synonyme verwendet, um die Ansichts- und Tabellennamen zu optimieren.Wie kann ich überprüfen, ob die Tabelle hinter einem Synonym existiert

Die Idee ist, dass der Benutzer des Skripts den Namen der Ansicht, die sie als Quelle verwenden möchten, und den Namen der Zielberichterstattungstabelle am Anfang und weg von ihnen setzen. Wenn die Tabelle nicht existiert, sollte das Skript sie erstellen. Wenn die Tabelle bereits existiert, sollte das Skript nur die Datensätze aus der Sicht kopieren, die noch nicht in der Tabelle enthalten sind.

Das Skript unten deckt alle diese Anforderungen, aber ich kann nicht eine schöne Art und Weise zu überprüfen, ob der Tisch hinter dem Synonym bereits vorhanden finden:

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 

Ich weiß, ich könnte nur erhalten die Benutzer des Skripts Kopieren Sie den Tabellennamen sowohl in die Zeile 'information_schema' als auch in das Synonym oben, was jedoch Fehlermöglichkeiten bietet.

Ich weiß auch, ich könnte etwas schmutzig tun wie den Tabellennamen in eine Variable und Blat die SQL-out als String, aber das macht mich ein bisschen krank fühlen!

Gibt es eine elegante SQL-Methode, mit der ich überprüfen kann, ob die Tabelle hinter dem Synonym existiert? Oder ein ganz anderer Weg, um ein Problem zu lösen?

+2

Sie bitte Ihre Frage mit den spezifischen RDBMS Tag, nicht nur "SQL" – Barmar

+1

Sorry, Rookie Fehler. Danke für die Bearbeitung. – Tom

+0

Können wir die Synonympunkte in der Datenbank annehmen, in der sich das Synonym befindet, oder auf eine andere db zeigen? –

Antwort

3

Nicht die eleganteste Lösung, aber Sie könnten die sys.synonyms Tabelle mit der sys.tables Tabelle verbinden, um zu überprüfen, ob die Tabelle existiert.

Wenn die Tabelle nicht existiert, schlägt der Join fehl und Sie erhalten 0 Zeilen (daher wird IF EXISTS falsch sein). Wenn die Tabelle nicht vorhanden ist, der Wille Erfolg kommen und Sie werden 1 Zeile (und true) erhalten:

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' Ersetzen mit je nachdem, was Synonym Sie prüfen möchten.

+0

Danke das funktioniert gut. Obwohl Sie sagen, dass es nicht die schönste Abfrage ist, bedeutet es zumindest, dass der Benutzer des Skripts den Tabellennamen nicht an mehreren Stellen einfügen muss. – Tom

+1

Statt 'REPLACE' zu verwenden, wäre eine zuverlässigere Methode, die Tabellen- und Schemainformationen zu erhalten, die' PARSENAME'-Funktion. Siehe: https://msdn.microsoft.com/en-us/library/ms188006.aspx – Nathan

1

Sie können dies mit dynamischem 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; 

Dies funktioniert nicht mit nicht-dynamischen SQL, weil das Synonym Bezug zur Compile-Zeit gefangen. Das bedeutet, dass der Code nur mit einer Nachricht fehlschlägt und nicht vom try/catch Block erfasst wird. Mit dynamischem SQL fängt der Block den Fehler ab.

+0

Danke. Ich sehe nicht ganz, wie das hilft. Es ist nicht die Tabelle information_schema, die ich versuche, den Namen zu bekommen, es ist die reale Tabelle hinter dem Synonym (das in meinem obigen Skript 'TargetReportingTable' genannt wird). Habe ich etwas verpasst? – Tom

+0

@Tom. . . Dies sind nur Beispiele, die zeigen, dass der Code funktioniert. In der Datenbank, die ich teste, existiert 'b' nicht, also wird' 0' zu '@existiert' zugewiesen. Wenn auf eine existierende Tabelle gesetzt ist, wird '1' zugewiesen. –

2

Die obigen Lösungen funktionierten nicht für mich, wenn das Synonym eine andere Datenbank referenzierte. Ich entdeckte vor kurzem die Funktion [fn_my_permissions], die zur Darstellung von Berechtigungen für ein bestimmtes Datenbankobjekt nützlich ist, so ich heraus diese verwendet werden könnten, wie folgt:

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

Ich musste "sy.sname" in meiner Version von Oracle verwenden. Auch ich habe Kreuz nicht gefunden, das für meine Zwecke notwendig ist – Mangusta

1

spät zur Party, ich habe eine Abfrage erstellt zu testen, die Existenz von Synonyms und teilen Sie mit Ihnen.

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

Sie können testen, ob Synonym in der Datenbank existiert, um die OBJECT_ID Funktion avaliable in SQL Server mit

IF OBJECT_ID('YourDatabaseName..YourSynonymName') IS NOT NULL 
    PRINT 'Exist SYNONYM' 
ELSE 
    PRINT 'Not Exist SYNONYM'