如何检查同义词后面的表是否存在

时间:2013-03-26 14:42:39

标签: sql sql-server rdbms synonym

我正在尝试创建一个简单的脚本,将复杂视图的结果转储到表格中进行报告。我使用同义词来简化视图和表名的调整。

这个想法是脚本的用户可以将他们想要用作视图的名称作为源,并将目标报告表的名称放在它们开始和离开的位置。如果该表不存在,那么脚本应该创建它。如果表已经存在,那么脚本应该只复制视图中尚未包含在表中的记录。

下面的脚本涵盖了所有这些要求,但我找不到一种很好的方法来检查同义词后面的表是否已经存在:

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方式来检查同义词后面的表是否存在?还是一种完全不同的解决问题的方法?

6 个答案:

答案 0 :(得分:3)

不是最优雅的解决方案,但您可以将sys.synonyms表加入sys.tables表以检查表是否存在。

如果该表不存在,则连接将失败,您将获得0行(因此IF EXISTS将为false)。如果表确实存在,则连接将成功,您将获得1行(和true):

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'替换为您要检查的同义词。

答案 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!'

答案 2 :(得分: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,块会捕获错误。

答案 3 :(得分: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

答案 4 :(得分:0)

您可以使用SQL Server中可用的Object_Id函数测试数据库中是否存在同义词

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

答案 5 :(得分:0)

另一个更简单的解决方案:

IF (EXISTS (SELECT * FROM sys.synonyms WHERE NAME ='mySynonymName'))
BEGIN
    UPDATE mySynonymName
    SET [Win] = 1
END

在这种情况下,我首先进行数据库设置。我先将所有同义词放入数据库(database1)中,然后运行SPROC为目标数据库(database2)中的所有表创建同义词。 database1中的某些SPROCS调用DB2中的表。如果DB2中不存在该表,则SPROC失败。如果DB2中不存在该表,则不会在数据库设置时自动创建同义字。因此,我只是使用以上方法检查同义词是否存在,如果不存在同义词,则跳过SPROC的那部分。