使用生成的DDL时,“必须是查询批处理中的第一个语句”

时间:2022-09-17 21:51:58

I have a server with over 100 databases linked to other database servers. These databases have views of the linked tables. I need to update the views weekly for any object changes in the linked servers, ie column adds.

我有一个服务器,有超过100个数据库链接到其他数据库服务器。这些数据库具有链接表的视图。我需要每周更新视图,以获得链接服务器中的任何对象更改,ie列补充说。

I create this script to loop through all the databases and grab all the views and refresh them by doing alter view. sp_refreshview does not work with linked servers.

我创建了这个脚本,以循环遍历所有数据库,并通过执行alter view获取所有视图并刷新它们。sp_refreshview不使用链接服务器。

When I print the @sql variable, it works fine in another query window. When I try to execute the @sql variable, it gives me the following error:

当我打印@sql变量时,它可以在另一个查询窗口中正常工作。当我尝试执行@sql变量时,它会给我以下错误:

Msg 111, Level 15, State 1, Line 3
'ALTER VIEW' must be the first statement in a query batch.

I think it has something to do with the LF/CR. I have tried many ways with no luck.

我想这和LF/CR有关系。我尝试过很多方法,但运气不好。

Any ideas?

什么好主意吗?

DECLARE @command varchar(1000) 
CREATE TABLE #tempViewSQL (DBName VARCHAR(255)
                          ,ViewSQL VARCHAR(4000))

SELECT @command = 'IF ''?'' NOT IN(''master''
                                 , ''model''
                                 , ''msdb''
                                 , ''tempdb''
                                 ,''pubs''
                                 ,''AuditProduction''
                                 ,''AuditProductionTest''
                                 ,''IID_Support''
                                 ,''Insurance_Files''
                                 ,''LoansAnalysis''
                                 ,''QualityAudit''
                                 ,''QualityAuditTest'') 
                BEGIN 
                  USE ? 
               INSERT INTO #tempViewSQL 
               SELECT TABLE_CATALOG, replace(view_definition,''create view'',''alter view'') 
                 FROM information_schema.views 
                WHERE TABLE_NAME NOT IN (''syssegments'',''sysconstraints'')
                 END' 

EXEC sp_MSforeachdb @command


DECLARE @SQLCursor VARCHAR(2000)
DECLARE @SQL VARCHAR(2000)
DECLARE @DbName VARCHAR(255)
DECLARE MyCursor CURSOR FOR
SELECT DBName, ViewSQL FROM  #tempViewSQL

OPEN MyCursor

FETCH NEXT FROM MyCursor INTO @DbName,@SQLCursor

WHILE @@FETCH_STATUS = 0   
BEGIN   


SET @SQL = 'USE ' + @DBName + CHAR(10) + CHAR(13) + 'GO' + CHAR(10) + CHAR(13) + @SQLCursor 
--PRINT (@SQL)
EXECUTE (@SQL)

FETCH NEXT FROM MyCursor INTO @DbName,@SQLCursor

END

CLOSE MyCursor   
DEALLOCATE MyCursor 

DROP TABLE #tempViewSQL

3 个解决方案

#1


3  

"GO" is not actually valid T-SQL. It's just a string which various SQL tools such as SSMS recognize as a batch separator (as if you ran each chunk separately).

“GO”实际上不是有效的T-SQL。它只是一个字符串,各种SQL工具(如SSMS)将其识别为批处理分隔符(就像您分别运行每个块一样)。

So you probably got an error along the lines of "Incorrect syntax near 'GO'" as well.

因此,你可能会在“GO”附近出现“不正确语法”的错误。

In order to create a view in another database, you will need to run sp_executesql in the context of that database, such as:

为了在另一个数据库中创建视图,您需要在该数据库的上下文中运行sp_executesql,例如:

EXEC OtherDatabase.dbo.sp_executesql @SQL;

Credit to Bob Pusateri's blog for that insight.

这要归功于Bob Pusateri的博客。

However, you have a dynamic database name, which makes it extra complicated. I believe you could probably EXEC dynamic SQL which contained the sp_executesql command qualified with the dynamic database name, Incpetion-style. But you'll have to be careful about your single quote encoding.

但是,您有一个动态数据库名称,这使它更加复杂。我相信您可以执行动态SQL,其中包含sp_executesql命令,该命令具有动态数据库名称incpe风格。但是你必须小心你的单引号编码。

#2


1  

You can try to execute query inside of specific database through using sp_executesql SP like below::

您可以尝试使用sp_executesql SP在特定数据库内部执行查询,如下所示:

DECLARE @AlterQuery NVARCHAR(MAX) = N'ALTER VIEW v1 AS SELECT * from T1' 
DECLARE @DbName NVARCHAR(MAX) = 'Test'
DELARE @Query NVARCHAR(MAX) = 'exec [' + @DbName + '].sys.sp_executesql N''' + REPLACE( @AlterQuery, '''', '''''' ) + ''''
EXECUTE( @Query )

#3


0  

I like to use Powershell for deployments like this where I store all of the server/database combinations in a table on a central server and then use this table to populate a list of servers to run across and then loop through them to run some logic. It's not a pure SQL solution, but it can be easily modified to get the job done...

我喜欢在这样的部署中使用Powershell,我将所有服务器/数据库组合存储在*服务器上的一个表中,然后使用这个表填充要运行的服务器列表,然后循环它们运行一些逻辑。它不是一个纯粹的SQL解决方案,但是可以很容易地修改它以完成任务……

function Get-ProductionDatabases
{
    param
    (
        [Parameter(Mandatory=$true)]
        [string]$centralServer,
        [Parameter(Mandatory=$true)]
        [string]$centralDatabase
    )

    $conn = New-Object System.Data.SqlClient.SqlConnection "Server=$centralServer;Database=$centralDatabase;Integrated Security=SSPI;"; 
    $dt   = New-Object System.Data.DataTable;    

    $cmd = $conn.CreateCommand(); 
    $cmd.CommandType = [System.Data.CommandType]::Text
    $cmd.CommandText = "Select  [ServerName], 
                                [DatabaseName]
                        From    [dbo].[ProductionDatabases];";

    $conn.Open();
    $dt.Load($cmd.ExecuteReader());
    $conn.Close();    

    $dt
}


$productionDatabases = Get-ProductionDatabases -centralServer "ProductionServer\Instance" -centralDatabase "CentralDatabase"

foreach($db in $productionDatabases)
{
    $conn = New-Object System.Data.SqlClient.SqlConnection "Server=$($db.ServerName);Database=$($db.DatabaseName);Integrated Security=SSPI;"; 
    $queryOut = New-Object System.Data.DataTable;    

    $cmd = $conn.CreateCommand(); 
    $cmd.CommandType = [System.Data.CommandType]::Text
    $cmd.CommandText = "Exec sp_refreshview;";                        

    $conn.Open();

    try
    {
        $queryOut.Load($cmd.ExecuteReader());
        $conn.Close();           
    }
    catch
    {
        "Warning: Error connecting to $($db.ServerName)."
    }
}

#1


3  

"GO" is not actually valid T-SQL. It's just a string which various SQL tools such as SSMS recognize as a batch separator (as if you ran each chunk separately).

“GO”实际上不是有效的T-SQL。它只是一个字符串,各种SQL工具(如SSMS)将其识别为批处理分隔符(就像您分别运行每个块一样)。

So you probably got an error along the lines of "Incorrect syntax near 'GO'" as well.

因此,你可能会在“GO”附近出现“不正确语法”的错误。

In order to create a view in another database, you will need to run sp_executesql in the context of that database, such as:

为了在另一个数据库中创建视图,您需要在该数据库的上下文中运行sp_executesql,例如:

EXEC OtherDatabase.dbo.sp_executesql @SQL;

Credit to Bob Pusateri's blog for that insight.

这要归功于Bob Pusateri的博客。

However, you have a dynamic database name, which makes it extra complicated. I believe you could probably EXEC dynamic SQL which contained the sp_executesql command qualified with the dynamic database name, Incpetion-style. But you'll have to be careful about your single quote encoding.

但是,您有一个动态数据库名称,这使它更加复杂。我相信您可以执行动态SQL,其中包含sp_executesql命令,该命令具有动态数据库名称incpe风格。但是你必须小心你的单引号编码。

#2


1  

You can try to execute query inside of specific database through using sp_executesql SP like below::

您可以尝试使用sp_executesql SP在特定数据库内部执行查询,如下所示:

DECLARE @AlterQuery NVARCHAR(MAX) = N'ALTER VIEW v1 AS SELECT * from T1' 
DECLARE @DbName NVARCHAR(MAX) = 'Test'
DELARE @Query NVARCHAR(MAX) = 'exec [' + @DbName + '].sys.sp_executesql N''' + REPLACE( @AlterQuery, '''', '''''' ) + ''''
EXECUTE( @Query )

#3


0  

I like to use Powershell for deployments like this where I store all of the server/database combinations in a table on a central server and then use this table to populate a list of servers to run across and then loop through them to run some logic. It's not a pure SQL solution, but it can be easily modified to get the job done...

我喜欢在这样的部署中使用Powershell,我将所有服务器/数据库组合存储在*服务器上的一个表中,然后使用这个表填充要运行的服务器列表,然后循环它们运行一些逻辑。它不是一个纯粹的SQL解决方案,但是可以很容易地修改它以完成任务……

function Get-ProductionDatabases
{
    param
    (
        [Parameter(Mandatory=$true)]
        [string]$centralServer,
        [Parameter(Mandatory=$true)]
        [string]$centralDatabase
    )

    $conn = New-Object System.Data.SqlClient.SqlConnection "Server=$centralServer;Database=$centralDatabase;Integrated Security=SSPI;"; 
    $dt   = New-Object System.Data.DataTable;    

    $cmd = $conn.CreateCommand(); 
    $cmd.CommandType = [System.Data.CommandType]::Text
    $cmd.CommandText = "Select  [ServerName], 
                                [DatabaseName]
                        From    [dbo].[ProductionDatabases];";

    $conn.Open();
    $dt.Load($cmd.ExecuteReader());
    $conn.Close();    

    $dt
}


$productionDatabases = Get-ProductionDatabases -centralServer "ProductionServer\Instance" -centralDatabase "CentralDatabase"

foreach($db in $productionDatabases)
{
    $conn = New-Object System.Data.SqlClient.SqlConnection "Server=$($db.ServerName);Database=$($db.DatabaseName);Integrated Security=SSPI;"; 
    $queryOut = New-Object System.Data.DataTable;    

    $cmd = $conn.CreateCommand(); 
    $cmd.CommandType = [System.Data.CommandType]::Text
    $cmd.CommandText = "Exec sp_refreshview;";                        

    $conn.Open();

    try
    {
        $queryOut.Load($cmd.ExecuteReader());
        $conn.Close();           
    }
    catch
    {
        "Warning: Error connecting to $($db.ServerName)."
    }
}