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

4

6 回答 6

3

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

如果该表不存在,则连接将失败,您将获得 0 行(因此IF EXISTS为假)。如果表确实存在,则连接将成功,您将获得 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'为您要检查的任何同义词。

于 2013-03-26T15:00:17.997 回答
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!'
于 2015-04-09T13:45:31.073 回答
2

派对迟到了,我创建了一个查询来测试它的存在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
于 2015-10-16T09:33:08.060 回答
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,块会捕获错误。

于 2013-03-26T14:49:16.753 回答
0

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

IF OBJECT_ID('YourDatabaseName..YourSynonymName') IS NOT NULL
    PRINT 'Exist SYNONYM'
ELSE 
    PRINT 'Not Exist SYNONYM'
于 2017-07-14T17:37:09.523 回答
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 的那部分。

于 2019-05-29T20:56:49.703 回答