在SQL Server

时间:2016-02-11 10:27:40

标签: sql-server cursor

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

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

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

  

Syntaxe incorrecte vers'go'。
  Msg 111,Niveau 15,État1,Ligne 14
  '创造视图'doitêtrelapremièreadmandd'un traitementderequê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执行的。

然而,当我执行'print @Query'指令的结果时,它可以工作!!

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

提前致谢

2 个答案:

答案 0 :(得分:0)

这里有两件事:

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

答案 1 :(得分:0)

以防万一将来对某人有所帮助,这是我对这个问题的解决方案。我如何提出此建议的完整历史已在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”(假设您需要灵活地将其复制到脚本编写时未知的数据库中)。

在原始发布者的试探性解决方案的内部循环中调用上述存储的proc应该可以解决将视图复制到另一个数据库的问题。

请注意,如果视图彼此依赖,则仅循环浏览所有视图可能会带来挑战。可能存在一些其他复杂性,其中包括解析视图的依赖关系树并以正确的顺序复制视图。另外,一种“笨拙且简单”的方法可能是遍历所有视图,忽略故障,并不断重复该过程,直到创建完所有视图为止。