我正在尝试创建一个简单的脚本,将复杂视图的结果转储到表格中进行报告。我使用同义词来简化视图和表名的调整。
这个想法是脚本的用户可以将他们想要用作视图的名称作为源,并将目标报告表的名称放在它们开始和离开的位置。如果该表不存在,那么脚本应该创建它。如果表已经存在,那么脚本应该只复制视图中尚未包含在表中的记录。
下面的脚本涵盖了所有这些要求,但我找不到一种很好的方法来检查同义词后面的表是否已经存在:
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方式来检查同义词后面的表是否存在?还是一种完全不同的解决问题的方法?
答案 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的那部分。