包装器存储过程,用于为事务复制创建发布

时间:2012-04-06 17:03:25

标签: sql-server sql-server-2008 tsql replication transactional-replication

我创建了一个包装器存储过程来为SQL Server 2008 Standard Edition SP3的事务复制创建发布。但是当我执行该过程时,我收到以下错误。 “file_exists”列不是用户定义的。这个错误对我没有任何意义。这适用于Dev环境,但相同的代码不适用于测试环境。据我所知,Dev和Test是完全相同的。我还试图明确设置选项,使它们成为5496(SELECT @@ OPTIONS)。非常感谢任何帮助。

- 错误

Msg 50000, Level 16, State 1, Procedure CreatePublicationForDB, Line 161
Invalid column name 'file_exists'.

- 开始编写脚本

CREATE DATABASE TestPublication

GO
USE TestPublication

CREATE TABLE Orders(
    OrderID INT PRIMARY KEY,
    CustomerID INT,
    ProductID INT,
    UpdatedAt DATETIME,
    UpdatedBy DATETIME
)
GO
CREATE TABLE Products(
ProductID INT PRIMARY KEY,
ProductName VARCHAR(100)
)
GO
CREATE VIEW V_Order
AS
SELECT o.OrderID,o.CustomerID, p.ProductName
FROM Orders o 
JOIN Products p
    ON o.ProductID = p.ProductID

GO
CREATE SCHEMA repl
GO
CREATE TABLE repl.ReplicationTables
(
    DBName sys.sysname NOT NULL DEFAULT('TestPublication'),
    SchemaOwner sys.sysname NOT NULL DEFAULT('dbo'),
    TableName sys.sysname NOT NULL
) 
GO
INSERT INTO repl.ReplicationTables (tablename)
VALUES('Orders'),('Products'),('V_Order')
GO
USE TestPublication
GO
CREATE PROCEDURE CreatePublicationForDB( @databaseName sysname, @publicationName sysname = @databaseName,   @allow_initialize_from_backup NVARCHAR(5) = 'true')
AS
BEGIN

BEGIN TRY
SET ANSI_WARNINGS ON
SET ANSI_PADDING ON
SET ANSI_NULLS ON
SET ARITHABORT ON
SET QUOTED_IDENTIFIER ON
SET ANSI_NULL_DFLT_ON ON
SET CONCAT_NULL_YIELDS_NULL ON 
        DECLARE @sp_replicationdboption varchar(MAX) = ' USE '+@databaseName +';',
                @sp_addpulication VARCHAR(MAX) = ' USE '+@databaseName +';', 
                @sp_addpublication_snapshot VARCHAR(MAX) = ' USE '+@databaseName +';', 
                @sp_addarticle VARCHAR(MAX) = ' USE '+@databaseName +';',
                @sp_startpublication_snapshot VARCHAR(MAX) = ' USE '+@databaseName +';'

        DECLARE @allow_anonymous NVARCHAR(5) = CASE WHEN @allow_initialize_from_backup = 'false' OR @allow_initialize_from_backup IS NULL THEN 'true' ELSE 'false' END

        DECLARE @immediate_sync NVARCHAR(5) = @allow_anonymous, @publisher sysname = @@SERVERNAME
        -- set up database publication
        SET @sp_replicationdboption += '
        exec sp_replicationdboption @dbname = N'''+@databaseName+ ''', 
                                @optname = N''publish'', 
                                @value = N''true'''
        -- Publication
        SET @sp_addpulication += '
        exec sp_addpublication @publication = N'''+@publicationName+ ''', 
                            @description = N''Transactional publication of database '+@databaseName+' from Publisher '+@publisher+''', 
                            @sync_method = N''concurrent'', 
                            @retention = 0, 
                            @allow_push = N''true'', 
                            @allow_pull = N''true'', 
                            @allow_anonymous = N'''+@allow_anonymous+ ''' , 
                            @enabled_for_internet = N''false'', 
                            @snapshot_in_defaultfolder = N''true'', 
                            @compress_snapshot = N''false'', 
                            @ftp_port = 21, 
                            @ftp_login = N''anonymous'', 
                            @allow_subscription_copy = N''false'', 
                            @add_to_active_directory = N''false'', 
                            @repl_freq = N''continuous'', 
                            @status = N''active'', 
                            @independent_agent = N''true'', 
                            @immediate_sync =  N'''+@immediate_sync+ ''' , 
                            @allow_sync_tran = N''false'', 
                            @autogen_sync_procs = N''false'', 
                            @allow_queued_tran = N''false'', 
                            @allow_dts = N''false'', 
                            @replicate_ddl = 1, 
                            @allow_initialize_from_backup =  N'''+COALESCE(@allow_initialize_from_backup, 'false')+ ''' , 
                            @enabled_for_p2p = N''false'', 
                            @enabled_for_het_sub = N''false'''

        IF @allow_initialize_from_backup = 'false'
        BEGIN
            -- publication snapshot
            SET @sp_addpublication_snapshot +='
            exec sp_addpublication_snapshot @publication = N'''+@publicationName+ ''', 
                                        @frequency_type = 1, 
                                        @frequency_interval = 0, 
                                        @frequency_relative_interval = 0, 
                                        @frequency_recurrence_factor = 0, 
                                        @frequency_subday = 0, 
                                        @frequency_subday_interval = 0, 
                                        @active_start_time_of_day = 0, 
                                        @active_end_time_of_day = 235959, 
                                        @active_start_date = 0, 
                                        @active_end_date = 0, 
                                        @job_login = null, 
                                        @job_password = null, 
                                        @publisher_security_mode = 1'

            SET @sp_startpublication_snapshot+=' exec sys.sp_startpublication_snapshot @publication = N'''+@publicationName+ ''''
        END
        -- Articles
        IF OBJECT_ID('tempdb..#t') IS NULL
            BEGIN
                PRINT 'creating temp table t'
                CREATE TABLE #t (NAME sysname,objectid INT, sch_owner sysname  NULL, article sysname NOT NULL, isIndexed BIT NULL, IsSchemaBound BIT NULL, TYPE CHAR(2) NULL)
            END
        INSERT INTO #t(NAME,objectid, sch_owner,isIndexed,IsSchemaBound, TYPE,article)
        EXEC('
        USE '+@databaseName + '
        SELECT f.Name, f.object_id,f.sch, f.IsIndexed,f.IsSchemaBound, f.type,CASE WHEN ROW_NUMBER() OVER (PARTITION BY f.name ORDER BY f.sch) > 1 THEN f.name + CAST((ROW_NUMBER() OVER (PARTITION BY f.name ORDER BY f.sch) - 1) AS VARCHAR(2)) ELSE f.name END AS Article
        FROM(
        SELECT t.Name, t.object_id,t.sch, IsIndexed,IsSchemaBound, type
        FROM 
            (SELECT DBName, SchemaOwner, TableName
            FROM TestPublication.repl.ReplicationTables
            GROUP BY DBName, SchemaOwner, TableName )rt JOIN
        (SELECT o.Name, o.object_id,s.name AS sch,  objectproperty(o.object_id, ''IsIndexed'') AS IsIndexed,objectproperty(o.object_id, ''IsSchemaBound'') AS IsSchemaBound, o.type
        FROM
        sys.objects o
        JOIN sys.schemas s ON o.schema_id = s.schema_id
        WHERE o.type IN (''U'',''V'')
            AND ObjectProperty(o.object_id, ''IsMSShipped'') = 0
            AND (ObjectProperty(o.object_id, ''TableHasPrimaryKey'') = 1 OR ObjectProperty(o.object_id, ''TableHasPrimaryKey'') IS NULL)
        ) t ON rt.tablename = t.name AND rt.SchemaOwner = t.sch
        WHERE rt.DBName = '''+@databaseName + '''
        ) f'
        )
        SELECT @sp_addarticle += 
                'exec sp_addarticle 
                @publication = N''' +@databaseName +
                ''', @article = N''' +t.article+
                ''', @source_owner = N''' +t.sch_owner +
                ''', @source_object = N''' + t.NAME +
                ''', @type = N''' +
                CASE WHEN t.type = 'U' THEN 'logbased'
                     WHEN t.type = 'V' AND (IsIndexed = 1 OR IsSchemaBound = 1 )THEN 'indexed view schema only'
                     WHEN t.type = 'V' AND IsIndexed = 0 THEN 'view schema only' END

                    +''', @description = null,@creation_script = null,@pre_creation_cmd = N''drop'', 
                @schema_option = '+
                    CASE WHEN t.type = 'U' THEN '0x000000000803509F'
                     WHEN t.type = 'V' THEN '0x0000000008000001' END+
                ',@destination_table = N'''+t.Name+
                ''',@destination_owner = N'''+t.sch_owner+''''+
                CASE WHEN t.TYPE = 'U' THEN
                        ', @identityrangemanagementoption = N''manual'',@vertical_partition = N''false'',
                @ins_cmd = N''CALL sp_MSins_'+t.sch_owner+''+t.Name+
                ''', @del_cmd = N''CALL sp_MSdel_'+t.sch_owner+''+t.Name+''',
                @upd_cmd = N''SCALL sp_MSupd_'+t.sch_owner+''+t.Name+''''
                        ELSE ''
                    END
                    +';'

        FROM #t t

        PRINT 'Now running sp_replicationdboption'
        PRINT @sp_replicationdboption
        EXEC(@sp_replicationdboption)

        PRINT 'Now running sp_addpulication'
        PRINT @sp_addpulication
        EXEC(@sp_addpulication)

        IF @allow_initialize_from_backup = 'false'
        BEGIN
            PRINT 'Now running sp_addpulication_snapshot and starting snapshot'
            PRINT @sp_addpublication_snapshot
            EXEC(@sp_addpublication_snapshot)
            EXEC(@sp_startpublication_snapshot)
        END

        PRINT 'Now running sp_addarticles'
        PRINT @sp_addarticle
        EXEC(@sp_addarticle)

    -- exec sp_droppublication @publication = N'Products'   
    END TRY

    BEGIN CATCH
        IF @@trancount > 0
            ROLLBACK

            DECLARE @ERROR_SEVERITY INT, @ERROR_STATE INT, @ERROR_MESSAGE NVARCHAR(4000)
            SELECT @ERROR_SEVERITY = ERROR_SEVERITY(), @ERROR_STATE = ERROR_STATE(), @ERROR_MESSAGE = ERROR_MESSAGE()
            RAISERROR(@ERROR_MESSAGE, @ERROR_SEVERITY, @ERROR_STATE)
    END CATCH


END
GO

最后执行

EXEC CreatePublicationForDB 'TestPublication'

- 如果您想再次运行上述内容,请删除复制。

exec TestPublication.dbo.sp_droppublication @publication = 'TestPublication'
exec TestPublication.dbo.sp_replicationdboption @dbname = 'TestPublication', @optname = 'publish', @value = 'false'

- 清理数据库

DROP DATABASE TestPublication

2 个答案:

答案 0 :(得分:3)

对不起,老帖子我知道,但我遇到了一个非常相似的情况并绕过它。我还没有在其他任何地方找到可行的解决方案。我包括我的经验,以帮助他人。

我的情况总结是我有一个msbuild进程,它从一个事务中的清单文件(带有一系列脚本名称的文本文件)运行一系列脚本。用于创建和配置代理作业的脚本始终以相同的错误消失。 (列名“file_exists”无效)

我失败的脚本中使用的过程:

msdb.dbo.sp_add_category
msdb.dbo.sp_add_job
msdb.dbo.sp_add_jobstep
msdb.dbo.sp_update_job
msdb.dbo.sp_add_jobschedule
msdb.dbo.sp_add_jobserver

注释掉对msdb.dbo.sp_add_jobstep的调用,可以完成脚本。

我在脚本中也有@ database_name = N'$(DatabaseName)'形式的SQL命令变量。这导致了一些错误的尝试,试图使用转义宏,如sp_add_jobstep文档中[@ command =]'command'下的“重要”注释中所述。

https://msdn.microsoft.com/en-us/library/ms187358.aspx

如果我运行构建到但不包括作业创建脚本并重新开始,则会成功。

经过多次试验和错误后,我发现,即使procs被认定为[MSDB],除非我实际包含了USE语句,否则该过程失败。通过以“USE [MSDB] GO”开始脚本,然后切换回我的构建目标(即USE [MyBuildDB] GO),我不再收到错误。

我的代理作业按预期创建,并且构建中的多个脚本运行时没有错误。

答案 1 :(得分:0)

如果没有看到所有代码并拥有架构,很难说问题是什么。我建议不要创建一个包装来创建出版物。创建发布脚本可以在需要时保存并按需执行 - 无需使用包装器。