全部产品
云数据库 RDS 版

使用 SSMS 和 BCP 迁移 SQL Server 数据库

更新时间:2017-08-23 11:32:05   分享:   

本文以本地 SQL Server 数据库到阿里云 RDS SQL Server 2012 数据库的数据全量迁移为例,介绍了如何通过使用 SQL Server Management Studio (SSMS)和大容量复制程序实用工具(BCP)来迁移 SQL Server 数据库。

适用场景

  • SQL Server 数据库的结构迁移。

  • 数据的全量迁移,不支持数据的增量迁移。

  • 本地数据库到本地数据库、本地数据库到阿里云 RDS SQL Server 数据库和阿里云 RDS SQL Server 数据库间的数据全量迁移。

背景信息

SSMS 是用于管理 SQL Server 基础架构的集成环境,提供用于配置、监视和管理 SQL Server 实例的工具。 此外,它还提供了用于部署、监视和升级数据层组件(如应用程序使用的数据库和数据仓库)的工具以生成查询和脚本。

BCP 可以在 SQL Server 实例和用户指定格式的数据文件间大容量复制数据,您可以通过 BCP 实用工具将大量新行导入 SQL Server 表,或将表数据导出到数据文件。

所以,本文直接使用 SSMS 的功能来生成源端数据库对象结构的创建脚本,然后在目标数据库中去执行,进行数据库结构的迁移;再配合使用 BCP 命令行来进行数据库数据的导出和导入操作,进行数据的全量迁移。下面将介绍如何将本地 SQL Server 2012 数据库 AdventureWorks2012 的数据全量迁移到阿里云 RDS SQL Server 2012 数据库。

前提条件

目标数据库主机需要有充足的存储空间来存放导入的数据和因此而带来的日志文件增长,两者加起来的空间增长大概是源端数据库大小的 2-3 倍(如果数据库是 Full 模式)。如果目标数据库是在本地自建环境,请确保宿主机有足够的存储空间;如果是阿里云 RDS SQL Server,请确保已经购买了充足的存储空间。

注意事项

  • 在创建目标数据库时,要确保目标数据库和源端数据库排序规则的一致性,否则很可能会导致全量数据迁移失败。

  • 为防止数据全量迁移过程报错,需要在目标数据库中禁用外键、索引和触发器,然后再启用,以此来避免错误发生和提高数据导入效率。

  • BCP 导入计算列或时间戳(timestamp)列时,会忽略它们的列值,SQL Server 将自动分配该列的值。

操作步骤

视频介绍

文本介绍

  1. 打开 SSMS 客户端。

  2. 分别连接源数据库 AdventureWorks2012 和阿里云 RDS SQL Server 数据库。

  3. 执行如下代码,在源数据库创建具有读写权限的用户。代码中的 testdbo 是指用户名称,XXXXXXXX 是该用户的登录密码,在执行代码前请将这两个参数改成您想要的用户名和密码。若您的数据库中已存在具有读写权限的用户,请跳过此步骤。

    1. USE MASTER
    2. GO
    3. CREATE LOGIN testdbo
    4. WITH PASSWORD = N'XXXXXXXX',CHECK_POLICY = OFF
    5. GO
    6. USE AdventureWorks2012
    7. GO
    8. CREATE USER testdbo FOR LOGIN testdbo;
    9. EXEC sys.sp_addrolemember 'db_owner','testdbo'
    10. GO
  4. 禁用掉 TCP/IP 协议,以断开源数据库的所有客户端连接,以确保源端数据迁移前后的一致性。

  5. 重启 SQL Server 服务。

    注意:禁用掉 TCP/IP 协议后,远端应用程序将无法通过 TCP/IP 端口来访问本地实例,在使用 BCP 进行数据导出时,必须在该实例所在的物理机上进行。

  6. 执行如下命令,在阿里云 RDS SQL Server 2012 的实例上创建数据库。

    1. create database db01 DEFAULT CHARACTER SET gbk COLLATE gbk_chinese_ci;
  7. 执行如下代码,分别查看源端数据库和目标数据库的排序规则。

    1. -- Check Collation name
    2. SELECT name,collation_name
    3. FROM sys.databases
    4. WHERE name = 'adventureworks2012'
  8. 若结果显示的排序规则不同,在目标数据库执行如下代码,将 SQL_Latin1_General_CP1_CI_AS 替换成跟跟源端数据库一致的排序规则。若排序规则一致,请跳过此步骤。

    1. -- change the collate if need.
    2. USE master;
    3. GO
    4. ALTER DATABASE adventureworks2012
    5. COLLATE SQL_Latin1_General_CP1_CI_AS;
    6. GO
  9. 在目标数据库中执行如下代码,创建与步骤 3 中一致的源端数据库用户。

    1. USE MASTER
    2. GO
    3. CREATE LOGIN testdbo
    4. WITH PASSWORD = N'XXXXXXXX',CHECK_POLICY = OFF
    5. GO
    6. USE AdventureWorks2012
    7. GO
    8. CREATE USER testdbo FOR LOGIN testdbo;
    9. EXEC sys.sp_addrolemember 'db_owner','testdbo'
    10. GO
  10. 在源端数据库生成对象信息创建脚本。操作步骤如下:

    1. 单击源数据库中的 Databases

    2. 右击 AdventureWorks2012

    3. 选择 Tasks > Generate Scripts,如下图所示。

      生成脚本

    4. 进入生成脚本的界面后,单击 Next

    5. 选中 Select specific database objects,选择除 Users 以外所有的迁移对象,然后单击 Next。如下图所示。

      选择迁移对象

    6. Set Scripting Options 页面,单击 Advanced,然后进行如下设置:

      • 单击 Script for Server Version,将其值设成与目标数据库一致的数据库版本,本示例中使用的是 SQL Server 2012.

      • 单击 Script for the database engine edition,将其值设成 Microsoft SQL Server Enterprise Edition。

      • Script Object-Level PermissionsScript OwnerScript USE DATAABASE 的值设成 True。

      • 单击 Types of data to script,将其值设成 Schema only。

        注意:该选项不能设成 Schema and data,否则会生成 schema 文件和 INSERT 语句文件,造成效率低下。

      • 建议将 Table/View Options 中的所有选项值都设置成 True。

        详情如下图所示:

        脚本高级设置

    7. 单击 OK。导出的脚本文件会放在页面上显示的 File name 中所示的位置。

    8. 单击 NextNextFinish,完成脚本生成工作。

  11. 在目标数据库中执行在上一步中创建的脚本文件。

  12. 当创建对象信息的脚本文件执行完毕后,执行如下代码,并将参数 @is_disable BIT 的值设成 1,以禁用外键约束、索引和触发器。

    说明:表外键约束的存在会导致数据导入失败,而表索引和触发器的存在会导致数据导入效率降低,所以需要将其禁用。

    1. USE [adventureworks2012]
    2. GO
    3. --public variables: need init by users.
    4. DECLARE
    5. @is_disable BIT = 1 -- 1: disalbe indexes, foreign keys and triggers;
    6. -- 0: enable indexes, foreign keys and triggers;
    7. ;
    8. --================ Private variables
    9. DECLARE
    10. @sql NVARCHAR(MAX)
    11. , @sql_index NVARCHAR(MAX)
    12. , @tb_schema SYSNAME
    13. , @tb_object_name SYSNAME
    14. , @tr_schema SYSNAME
    15. , @tr_object_name SYSNAME
    16. , @ix_name SYSNAME
    17. ;
    18. --================= Disable/Enable indexes on all tables
    19. DECLARE
    20. cur_indexes CURSOR LOCAL STATIC FORWARD_ONLY READ_ONLY
    21. FOR
    22. SELECT
    23. ix_name = ix.name
    24. , tb_schema = SCHEMA_NAME(obj.schema_id)
    25. , tb_object_name = obj.name
    26. FROM sys.indexes as ix
    27. INNER JOIN sys.objects as obj
    28. ON ix.object_id = obj.object_id
    29. WHERE ix.type >= 2
    30. AND obj.is_ms_shipped = 0
    31. AND ix.is_disabled = (1 - @is_disable)
    32. OPEN cur_indexes;
    33. FETCH NEXT FROM cur_indexes INTO @ix_name, @tb_schema, @tb_object_name;
    34. WHILE @@FETCH_STATUS = 0
    35. BEGIN
    36. SET
    37. @sql_index = N'ALTER INDEX ' + QUOTENAME(@ix_name)
    38. + N' ON ' + QUOTENAME(@tb_schema) + N'.' + QUOTENAME(@tb_object_name)
    39. + CASE @is_disable
    40. WHEN 1 THEN N' DISABLE;'
    41. WHEN 0 THEN N' REBUILD; '
    42. ELSE N''
    43. END;
    44. RAISERROR(N'%s', 10, 1, @sql_index) WITH NOWAIT;
    45. EXEC sys.sp_executesql @sql_index
    46. FETCH NEXT FROM cur_indexes INTO @ix_name, @tb_schema, @tb_object_name;
    47. END
    48. CLOSE cur_indexes;
    49. DEALLOCATE cur_indexes;
    50. --================= Disable/Enable foreign keys on all tables
    51. --disable
    52. IF @is_disable = 1
    53. BEGIN
    54. SELECT
    55. @sql = N'
    56. RAISERROR(N''ALTER TABLE ? NOCHECK CONSTRAINT ALL;'', 10, 1) WITH NOWAIT
    57. ALTER TABLE ? NOCHECK CONSTRAINT ALL;'
    58. ;
    59. END
    60. ELSE --enable
    61. BEGIN
    62. SELECT
    63. @sql = N'
    64. RAISERROR(N''ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL;'', 10, 1) WITH NOWAIT
    65. ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL;'
    66. ;
    67. END
    68. EXEC sys.sp_MSforeachtable @sql
    69. --================= Disable/Enable triggers on all tables
    70. DECLARE
    71. cur_triggers CURSOR LOCAL STATIC FORWARD_ONLY READ_ONLY
    72. FOR
    73. SELECT
    74. tb_schema = SCHEMA_NAME(tb.schema_id)
    75. ,tb_object_name = tb.name
    76. ,tr_schema = SCHEMA_NAME(obj.schema_id)
    77. ,tr_object_name = obj.name
    78. FROM sys.objects as obj
    79. INNER JOIN sys.tables as tb
    80. ON obj.parent_object_id = tb.object_id
    81. INNER JOIN sys.triggers as tr
    82. ON obj.object_id = tr.object_id
    83. WHERE obj.type = 'TR'
    84. AND obj.is_ms_shipped = 0
    85. AND tr.is_disabled = (1 - @is_disable)
    86. ORDER BY tb_schema, tb_object_name
    87. OPEN cur_triggers;
    88. FETCH NEXT FROM cur_triggers INTO @tb_schema, @tb_object_name, @tr_schema, @tr_object_name;
    89. WHILE @@FETCH_STATUS = 0
    90. BEGIN
    91. SET @sql = CASE @is_disable
    92. WHEN 1 THEN N'DISABLE TRIGGER '
    93. WHEN 0 THEN N'ENABLE TRIGGER '
    94. ELSE N''
    95. END
    96. + QUOTENAME(@tr_schema) + N'.' + QUOTENAME(@tr_object_name)
    97. + N' ON '
    98. + QUOTENAME(@tb_schema) + N'.' + QUOTENAME(@tb_object_name)
    99. ;
    100. RAISERROR(N'%s', 10, 1, @sql) WITH NOWAIT;
    101. EXEC sys.sp_executesql @sql;
    102. FETCH NEXT FROM cur_triggers INTO @tb_schema, @tb_object_name, @tr_schema, @tr_object_name;
    103. END
    104. CLOSE cur_triggers;
    105. DEALLOCATE cur_triggers;
    106. GO
  13. 在源端数据库和目标数据库中分别执行如下代码,查询数据库的对象汇总信息。

    1. USE AdventureWorks2012
    2. GO
    3. ;WITH objs
    4. AS(
    5. -- check objects
    6. SELECT
    7. database_name = LOWER(DB_NAME())
    8. , object_type = type
    9. , objet_desc = type_desc
    10. , object_count = COUNT(1)
    11. FROM sys.all_objects WITH(NOLOCK)
    12. WHERE is_ms_shipped = 0
    13. GROUP BY type,type_desc
    14. UNION ALL
    15. --check indexes
    16. SELECT
    17. database_name = LOWER(DB_NAME())
    18. , object_type = CAST(ix.type AS VARCHAR)
    19. , objet_desc = ix.type_desc
    20. , object_count = COUNT(1)
    21. FROM sys.indexes as ix
    22. INNER JOIN sys.objects as obj
    23. ON ix.object_id = obj.object_id
    24. WHERE obj.is_ms_shipped = 0
    25. GROUP BY ix.type,ix.type_desc
    26. )
    27. SELECT * FROM objs
    28. ORDER BY object_type
  14. 查询结果返回后,对比源端数据库和目标数据库的对象信息。若结果显示一致,则说明所有对象信息已经从源数据库迁移到了目标数据库。

    注意:

    • 为方便对比和避免人眼观察带来的人为错误,建议您使用对比工具来对比对象汇总信息。本文推荐您使用 Araxis Merge 2001 v6.0 Professional。

    • 阿里云 RDS SQL Server 目标数据库的名称仅支持小写字母,而源数据库名称可能含有大写字母,在使用工具进行对比时,请将其设置为忽略字母大小写的检查。若您使用的是 Araxis Merge 2001 v6.0 Professional,可以通过选择 View > Options,然后再选中 Ignore differences in character case 来设置。

  15. 在源端数据库上执行如下脚本,执行前请按实际情况修改如下参数:

    • source_User:源数据库中的登录用户名。

    • source_Password:登录源数据库的用户名所对应的密码。

    • destination_Instance:将 XXXX 改成目标数据库的实例名称。

    • destination_Database:目标端的数据库名称。若为空,则表示与源端数控保持一致。

    • destination_User:目标数据库中登录的用户名,与源端数据库一致。

    • destination_Password:登录目标数据库中的用户名所对应的密码。

      1. USE AdventureWorks2012
      2. GO
      3. -- declare public variables, need to init by user
      4. DECLARE
      5. @source_Instance sysname
      6. , @source_Database sysname
      7. , @source_User sysname
      8. , @source_Passwd sysname
      9. , @destination_Instance sysname
      10. , @destination_Database sysname
      11. , @destination_User sysname
      12. , @destination_Passwd sysname
      13. , @batch_Size int
      14. , @transfer_table_list nvarchar(max)
      15. ;
      16. -- Public variables init.
      17. SELECT
      18. @source_Instance = @@SERVERNAME -- Source Instance Name
      19. , @source_Database = DB_NAME() -- Source Database is current database.
      20. , @source_User = 'XXX' -- Source Instance Connect User Name
      21. , @source_Passwd = N'XXX' -- Source Instance User Password
      22. , @destination_Instance = N'XXXX.sqlserver.rds.aliyuncs.com,3433' -- Destination Instance Name
      23. , @destination_Database = N'' -- Destination Database name: NULL/empty: Keep the same as source db
      24. , @destination_User = 'XXX' -- Destination Instance User Name
      25. , @destination_Passwd = N'XXX' -- Destination Instance User Password
      26. , @transfer_table_list = N'' --NULL/empty: ALL Tables are needed to be transfered.
      27. , @batch_Size = 50000 -- BCP IN Batch Size, by default, it is 50000. Must between 1 and 50000.
      28. ;
      29. -- Private variables, there is no need to init.
      30. DECLARE
      31. @transfer_table_list_xml xml
      32. , @timestamp char(14)
      33. ;
      34. -- correct the variables init by user.
      35. SELECT
      36. @source_Instance = RTRIM( LTRIM(@source_Instance) )
      37. , @source_User = RTRIM( LTRIM( @source_User ) )
      38. , @source_Passwd = RTRIM( LTRIM( @source_Passwd ) )
      39. , @destination_Instance = RTRIM( LTRIM( @destination_Instance ) )
      40. , @destination_Database = CASE
      41. WHEN ISNULL(@destination_Database, N'') = N'' THEN @source_Database
      42. ELSE @destination_Database
      43. END
      44. , @destination_User = RTRIM( LTRIM( @destination_User ) )
      45. , @destination_Passwd = RTRIM( LTRIM( @destination_Passwd ) )
      46. , @batch_Size = CASE
      47. WHEN (@batch_Size>0 AND @batch_Size<=50000) THEN @batch_Size
      48. ELSE 50000
      49. END
      50. , @transfer_table_list_xml = '<V><![CDATA[' + REPLACE(
      51. REPLACE(
      52. REPLACE(
      53. @transfer_table_list,CHAR(10),']]></V><V><![CDATA['
      54. ),',',']]></V><V><![CDATA['
      55. ),CHAR(13),']]></V><V><![CDATA['
      56. ) + ']]></V>'
      57. , @timestamp =
      58. REPLACE(
      59. REPLACE(
      60. REPLACE(
      61. CONVERT(CHAR(19), GETDATE(), 120), N'-', '')
      62. , N':', N'')
      63. , CHAR(32), N'')
      64. ;
      65. IF OBJECT_ID('tempdb..#tb_list', 'U') IS NOT NULL
      66. DROP TABLE #tb_list
      67. CREATE TABLE #tb_list(
      68. RowID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY
      69. ,Table_name SYSNAME NOT NULL
      70. )
      71. IF ISNULL(@transfer_table_list, '') = ''
      72. BEGIN
      73. INSERT INTO #tb_list
      74. SELECT name
      75. FROM sys.tables AS tb
      76. WHERE tb.is_ms_shipped = 0
      77. END
      78. ELSE
      79. BEGIN
      80. INSERT INTO #tb_list
      81. SELECT table_name = T.C.value('(./text())[1]','sysname')
      82. FROM @transfer_table_list_xml.nodes('./V') AS T(C)
      83. WHERE T.C.value('(./text())[1]','sysname') IS NOT NULL
      84. END
      85. ;
      86. SELECT
      87. BCP_OUT = N'BCP ' + @source_Database + '.' + sch.name + '.' + tb.name
      88. + N' Out '
      89. + QUOTENAME( REPLACE(@source_Instance, N'\', N'_')+ '.' + @source_Database + '.' + sch.name + '.' + tb.name, '"')
      90. + N' /N /U ' + @source_User +N' /P ' + @source_Passwd +N' /S ' + @source_Instance
      91. + N' >> BCPOUT_' + @timestamp +N'.txt'
      92. ,BCP_IN = N'BCP ' + @destination_Database + '.' + sch.name + '.' + tb.name
      93. + N' In '
      94. + QUOTENAME( REPLACE(@source_Instance, N'\', N'_')+ '.' + @source_Database + '.' + sch.name + '.' + tb.name, '"')
      95. + N' /N /E /q /k /U ' + @destination_User + N' /P ' + @destination_Passwd + N' /b '
      96. + CAST(@batch_Size as varchar) + N' /S ' + @destination_Instance
      97. + N' >> BCPIN_' + @timestamp + N'.txt'
      98. --,*
      99. FROM sys.tables as tb
      100. LEFT JOIN sys.schemas as sch
      101. ON tb.schema_id = sch.schema_id
      102. WHERE tb.is_ms_shipped = 0
      103. AND tb.name IN (SELECT Table_name FROM #tb_list)
  16. 分别将生成的 BCP_OUT 和 BCP_IN 文件保存至本地。

  17. 运行本地保存的 BCP_OUT.bat 文件,生成源数据库的数据导出文件。

  18. BCP_OUT.bat 文件运行结束后,双击其日志文件 BCPOUT_YYYYMMDDHHMMSS.txt(YYYYMMDDHHMMSS 为文件生成时间),查看数据导出过程是否全部成功。

  19. 运行本地保存的 BCP_IN.bat 文件,将从源数据库中导出的文件从本地导入到远端目标数据库中。

    说明:由于目标数据库是在阿里云上,由于网络原因,BCP_IN.bat 文件的运行时间会比 BCP_OUT.bat 文件的运行时间长。

  20. BCP_IN.bat 文件运行结束后,双击其日志文件 BCPOUT_YYYYMMDDHHMMSS.txt,查看数据导入过程是否全部成功。

  21. 若确保数据已经全部从源端数据库导入到目标数据库中,删除磁盘上 BCP 在步骤 17 中导出的中间临时文件,如下图所示。

    BCP导出文件

  22. 分别在源端数据库和目标数据库中执行如下代码,查询源端数据库和目标数据库中的表记录总数。

    1. USE AdventureWorks2012
    2. GO
    3. SELECT
    4. schema_name = SCHEMA_NAME(tb.schema_id)
    5. ,table_name = OBJECT_NAME(tb.object_id)
    6. ,row_count = SUM(CASE WHEN ps.index_id < 2 THEN ps.row_count ELSE 0 END)
    7. FROM sys.dm_db_partition_stats as ps WITH(NOLOCK)
    8. INNER JOIN sys.tables as tb WITH(NOLOCK)
    9. ON ps.object_id = tb.object_id
    10. WHERE tb.is_ms_shipped = 0
    11. GROUP BY tb.object_id,tb.schema_id
    12. ORDER BY schema_name,table_name
  23. 使用对比工具对比源端数据库和目标数据库中的表记录总数。若数据一致,则说明源数据库的所有数据已经全部导入目标数据库中。

  24. 执行如下代码,并将参数 @is_disable BIT 的值设成 0,启用外键约束、索引和触发器,完成数据库迁移。

    1. USE [adventureworks2012]
    2. GO
    3. --public variables: need init by users.
    4. DECLARE
    5. @is_disable BIT = 1 -- 1: disalbe indexes, foreign keys and triggers;
    6. -- 0: enable indexes, foreign keys and triggers;
    7. ;
    8. --================ Private variables
    9. DECLARE
    10. @sql NVARCHAR(MAX)
    11. , @sql_index NVARCHAR(MAX)
    12. , @tb_schema SYSNAME
    13. , @tb_object_name SYSNAME
    14. , @tr_schema SYSNAME
    15. , @tr_object_name SYSNAME
    16. , @ix_name SYSNAME
    17. ;
    18. --================= Disable/Enable indexes on all tables
    19. DECLARE
    20. cur_indexes CURSOR LOCAL STATIC FORWARD_ONLY READ_ONLY
    21. FOR
    22. SELECT
    23. ix_name = ix.name
    24. , tb_schema = SCHEMA_NAME(obj.schema_id)
    25. , tb_object_name = obj.name
    26. FROM sys.indexes as ix
    27. INNER JOIN sys.objects as obj
    28. ON ix.object_id = obj.object_id
    29. WHERE ix.type >= 2
    30. AND obj.is_ms_shipped = 0
    31. AND ix.is_disabled = (1 - @is_disable)
    32. OPEN cur_indexes;
    33. FETCH NEXT FROM cur_indexes INTO @ix_name, @tb_schema, @tb_object_name;
    34. WHILE @@FETCH_STATUS = 0
    35. BEGIN
    36. SET
    37. @sql_index = N'ALTER INDEX ' + QUOTENAME(@ix_name)
    38. + N' ON ' + QUOTENAME(@tb_schema) + N'.' + QUOTENAME(@tb_object_name)
    39. + CASE @is_disable
    40. WHEN 1 THEN N' DISABLE;'
    41. WHEN 0 THEN N' REBUILD; '
    42. ELSE N''
    43. END;
    44. RAISERROR(N'%s', 10, 1, @sql_index) WITH NOWAIT;
    45. EXEC sys.sp_executesql @sql_index
    46. FETCH NEXT FROM cur_indexes INTO @ix_name, @tb_schema, @tb_object_name;
    47. END
    48. CLOSE cur_indexes;
    49. DEALLOCATE cur_indexes;
    50. --================= Disable/Enable foreign keys on all tables
    51. --disable
    52. IF @is_disable = 1
    53. BEGIN
    54. SELECT
    55. @sql = N'
    56. RAISERROR(N''ALTER TABLE ? NOCHECK CONSTRAINT ALL;'', 10, 1) WITH NOWAIT
    57. ALTER TABLE ? NOCHECK CONSTRAINT ALL;'
    58. ;
    59. END
    60. ELSE --enable
    61. BEGIN
    62. SELECT
    63. @sql = N'
    64. RAISERROR(N''ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL;'', 10, 1) WITH NOWAIT
    65. ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL;'
    66. ;
    67. END
    68. EXEC sys.sp_MSforeachtable @sql
    69. --================= Disable/Enable triggers on all tables
    70. DECLARE
    71. cur_triggers CURSOR LOCAL STATIC FORWARD_ONLY READ_ONLY
    72. FOR
    73. SELECT
    74. tb_schema = SCHEMA_NAME(tb.schema_id)
    75. ,tb_object_name = tb.name
    76. ,tr_schema = SCHEMA_NAME(obj.schema_id)
    77. ,tr_object_name = obj.name
    78. FROM sys.objects as obj
    79. INNER JOIN sys.tables as tb
    80. ON obj.parent_object_id = tb.object_id
    81. INNER JOIN sys.triggers as tr
    82. ON obj.object_id = tr.object_id
    83. WHERE obj.type = 'TR'
    84. AND obj.is_ms_shipped = 0
    85. AND tr.is_disabled = (1 - @is_disable)
    86. ORDER BY tb_schema, tb_object_name
    87. OPEN cur_triggers;
    88. FETCH NEXT FROM cur_triggers INTO @tb_schema, @tb_object_name, @tr_schema, @tr_object_name;
    89. WHILE @@FETCH_STATUS = 0
    90. BEGIN
    91. SET @sql = CASE @is_disable
    92. WHEN 1 THEN N'DISABLE TRIGGER '
    93. WHEN 0 THEN N'ENABLE TRIGGER '
    94. ELSE N''
    95. END
    96. + QUOTENAME(@tr_schema) + N'.' + QUOTENAME(@tr_object_name)
    97. + N' ON '
    98. + QUOTENAME(@tb_schema) + N'.' + QUOTENAME(@tb_object_name)
    99. ;
    100. RAISERROR(N'%s', 10, 1, @sql) WITH NOWAIT;
    101. EXEC sys.sp_executesql @sql;
    102. FETCH NEXT FROM cur_triggers INTO @tb_schema, @tb_object_name, @tr_schema, @tr_object_name;
    103. END
    104. CLOSE cur_triggers;
    105. DEALLOCATE cur_triggers;
    106. GO
本文导读目录
本文导读目录
以上内容是否对您有帮助?