【问题标题】:Copy a view definition from one database to another one in SQL Server在 SQL Server 中将视图定义从一个数据库复制到另一个数据库
【发布时间】:2016-02-11 10:27:39
【问题描述】:

我正在开发一个脚本,允许我在另一个数据库 (database2) 中创建 database1 中存在的所有视图。

我正在尝试使用在 database1 的所有视图上循环的游标来执行此操作,然后尝试在第二个数据库上执行该视图的定义。

不幸的是,它不起作用。我收到以下错误:

语法不正确 vers 'go'。
Msg 111、Niveau 15、État 1、Ligne 14
'CREATE VIEW' doit être la première instruction d'un traitement de requêtes.

这是我的代码

declare @database2 varchar(50), @database1 varchar(50)
set @database2 = 'Local'
set @database1 = 'prod'

declare @Query nvarchar(max), @view_definition nvarchar(max), @count int

set @count = 0

declare curseur cursor for SELECT top 1 view_definition FROM prod.information_schema.VIEWS 
open curseur
fetch curseur into  @view_definition
While @@FETCH_STATUS = 0
Begin
    set @count = @count + 1
    --Print 'Vue N° ' + cast(@count as varchar) + ':'
    set @Query = N'Use ' + @database2 +CHAR(13)+CHAR(10)+ 'go' + @view_definition +CHAR(13)+CHAR(10)+ 'go'
    print @Query
    exec sp_executesql @Query
    fetch curseur into  @view_definition
End
Close curseur
deallocate curseur

此代码是从 database1 执行的。

但是,当我执行“打印@Query”指令的结果时,它起作用了!!

有人可以帮我解决问题吗?

提前致谢

【问题讨论】:

  • 为什么不在第一个数据库中生成CREATE 视图脚本并在第二个数据库中执行?
  • 你能翻译一下doit être la première instruction d'un traitement de requêtes吗?
  • 这个法语表达意味着创建视图的指令必须在进程中的第一个位置
  • 你能显示你的打印语句显示的内容吗?
  • 你好 steve,这是打印语句显示:--Vue N° 1: Use wi_vigicolisLocal go CREATE VIEW [dbo].[PlateformeCollaborative] AS select rc.category_id,cc.category_name rc.RCode_Text from rcode rc left join rcodeprocessing rcp on rc.rcode_id=rcp.rcode_id inner join categorycontent cc on rc.category_id=cc.category_id and language_id='FR' inner join rshipper rs on rc.rshipper_id=rs.rshipper_id 其中 rcp.RCodeProcessing_ID 为空去。 go 子句单独换行

标签: sql-server cursor


【解决方案1】:

这里有两件事:

  1. 您不能在存储过程中使用另一个数据库,尽管另一个数据库在同一台服务器上,您可以使用CREATE VIEW databasename.schemaname.viewname (...。如果它在另一台服务器上,yiu 可以尝试将其设置为链接服务器并使用 servername.database.schema.viewname。
  2. sp_executesql 需要一个语句,并且不接受 GO 到我的 知识(这是错误告诉你的)。你可以尝试 放入';'相反(如果你这样做,你不需要CHAR(13) 虽然它们更容易阅读)。

【讨论】:

    【解决方案2】:

    如果这对将来的某人有所帮助,这是我对这个问题的解决方案。我如何想出它的完整历史在Stored Procedure to Copy Views from Current Database to Another

    CREATE PROCEDURE [dbo].[usp_Copy_View_To_Database]
        @ViewName SYSNAME, -- The name of the view to copy over
        @DatabaseName SYSNAME, -- The name of the database to copy the view to    
        @overwrite bit = 1 -- Whether to overwrite any existing view
    AS
        IF DB_ID(@DatabaseName) IS NULL -- Validate the database name exists
        BEGIN
           RAISERROR('Invalid Destination Database Name passed',16,1)
           RETURN
        END    
        SET NOCOUNT ON
        IF @overwrite = 1 -- If set to overwrite, try to drop the remote view
        BEGIN    
            DECLARE @DropViewStatement NVARCHAR(MAX) =
                'EXEC ' + QUOTENAME(@DatabaseName) + '.sys.sp_executesql N''DROP VIEW IF EXISTS ' + QUOTENAME(@ViewName) + ';'';'
            EXEC (@DropViewStatement);
        END
        -- Extract the saved definition of the view
        DECLARE @ViewDefinition NVARCHAR(MAX);
        SELECT @ViewDefinition = definition FROM sys.sql_modules WHERE [object_id] = OBJECT_ID(@ViewName);
        -- Check for a mismatch between the internal view name and the expected name (TODO: Resolve this automatically?)
        IF @ViewDefinition NOT LIKE ('%' + @ViewName + '%')
        BEGIN
           DECLARE @InternalName NVARCHAR(MAX) = SUBSTRING(@ViewDefinition, 3, CHARINDEX(char(10), @ViewDefinition, 3)-4);
           PRINT ('Warning: The view named '+@ViewName+' has an internal definition name that is different ('+@InternalName+'). This may have been caused by renaming the view after it was created. You will have to drop and recreate it with the correct name.')
        END
        -- Substitute any hard-coded references to the current database with the destination database
        SET @ViewDefinition = REPLACE(@ViewDefinition, db_name(), @DatabaseName); 
        -- Generate the dynamic SQL that will create the view on the remote database
        DECLARE @CreateViewStatement NVARCHAR(MAX) =
            'EXEC ' + QUOTENAME(@DatabaseName) + '.sys.sp_executesql N''' + REPLACE(@ViewDefinition,'''','''''') + ''';'
        --PRINT '@CreateViewStatement: ' + @CreateViewStatement -- Can be used for debugging
        -- Execute the create statement
        EXEC (@CreateViewStatement);
    

    简单来说就是需要两层嵌套的动态SQL:

    • 执行“CREATE VIEW”语句的内层,必须单独执行。这是使用EXEC SomeDatabase.sys.sp_executesql @CreateViewSQL 执行的
    • 再增加一层,通过参数动态指定“SomeDatabase”(假设您需要灵活地将其复制到脚本编写时未知的数据库)。

    在原发帖者的暂定解决方案的内循环中调用上述存储过程应该可以解决将视图复制到另一个数据库的问题。

    请注意,如果视图相互依赖,那么简单地循环遍历所有视图可能会带来挑战。可能存在一些额外的复杂性,涉及解析视图的依赖树并以正确的顺序复制它们。或者,一种“简单而简单”的方法可能是遍历所有视图,忽略失败,并不断重复该过程,直到创建所有视图。

    【讨论】:

      猜你喜欢
      • 2010-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-27
      • 2012-05-29
      • 1970-01-01
      • 2023-03-15
      相关资源
      最近更新 更多