Ошибка из-за передачи параметров в файл SQL с помощью Invoke-SQLCmd - PullRequest
0 голосов
/ 25 апреля 2019

У меня есть простой файл SQL, который создает новую базу данных на основе 3 отправленных входных параметров: dbName, datafileName и logfileName

Но когда я вызываю этот скрипт через powershell, вызывая командлет Invoke-Sqlcmd, я получаю следующую ошибку:

Incorrect syntax near 'CommonDB'.
Incorrect syntax near '\'.
Incorrect syntax near 'CommonDB'.
Incorrect syntax near 'E:'.
The label 'E' has already been declared. Label names must be unique within a query batch or stored procedure.
Incorrect syntax near 'E:'.
The label 'E' has already been declared. Label names must be unique within a query batch or stored procedure.
Incorrect syntax near 'CommonDB'.
The label 'E' has already been declared. Label names must be unique within a query batch or stored procedure.
The label 'E' has already been declared. Label names must be unique within a query batch or stored procedure.
At line:1 char:1
+ Invoke-Sqlcmd -ServerInstance localhost\sql2012 -Database master -Use ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Invoke-Sqlcmd], SqlPowerShellSqlExecutionException
    + FullyQualifiedErrorId : SqlError,Microsoft.SqlServer.Management.PowerShell.GetScriptCommand

Моя версия Powershell:

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      16299  1004

Это мой файл CreateDatabase.sql:

USE MASTER
GO

SET QUOTED_IDENTIFIER ON;
GO

DECLARE 
    @DbName nvarchar(50),
    @sql nvarchar(max),
    @datafileName nvarchar(500),
    @logfileName nvarchar(500)


SET @sql = N''

SELECT @DbName = N'$(dbName)'
SELECT @datafileName = N'$(datafileName)'
SELECT @logfileName = N'$(logfileName)'

IF NOT EXISTS (SELECT * FROM master.sys.databases WHERE name = @DbName)
BEGIN
SELECT @sql = 
    N'CREATE DATABASE "' + @DbName + N'"'
    + N' ON PRIMARY ( NAME = ['  + @DbName  + '] ,'
    + N' FILENAME = [' +  @datafileName  + '],'
    + N' SIZE = 1GB , MAXSIZE = UNLIMITED, FILEGROWTH = 512MB  )'
    + N' LOG ON ( NAME = [' + @DbName + '_log] ,'
    + N' FILENAME = ['  + @logfileName + '], SIZE = 100MB , FILEGROWTH = 10% )'
END

IF (@sql <> N'')
EXEC (@sql)
GO

SET QUOTED_IDENTIFIER OFF;
GO

Это мой файл PS1 Содержание:

$params=@("dbName='CommonDB'", "datafileName='E:\my files\sql.2012\data\CommonDb.mdf'", "logfileName='E:\my files\sql.2012\data\CommonDb_log.ldf'")

Invoke-Sqlcmd -ServerInstance localhost\sql2012 -Database master -Username sa -Password xxxx -ErrorAction Stop -InputFile .\CreateDatabase.sql -Variable $params

Но, если я запускаю это из приглашения PS, он работает просто отлично:

PS E:\My Scripts> Invoke-Sqlcmd -ServerInstance localhost\sql2012 -Database master -Username sa -Password xxxx -ErrorAction Stop -InputFile .\CreateDatabase.sql -Variable dbName='CommonDB', datafileName='E:\my files\sql.2012\data\CommonDb.mdf', logfileName='E:\my files\sql.2012\data\CommonDb_log.ldf'

Ответы [ 2 ]

0 голосов
/ 26 апреля 2019

Хорошо, я заставил эту штуку работать в общем виде, сгенерировав скрипт, необходимый для вызова-sqlcmd.Написал функцию, которая берет файл сценария и его параметры и генерирует ScriptBlock из того же:

<#
.SYNOPSIS
#

.DESCRIPTION
This function invokes sql in a .sql file and passes the parameters to it as needed. 

.PARAMETER script_file
 $script_file - The relative or absolute path to the sql file that needs to be executed
 $parameter_names - a list of string containing the names of the parameters which need to be passed to the sql file

.EXAMPLE
For example if there is a SQL file which takes 3 parameters: dbName, datafileName, and logfileName, whose values are: 
"CommonDB", "E:\my files\sql.2012\data\CommonDb.mdf", and "E:\my files\sql.2012\data\CommonDb_log.ldf" repectively, 
this function first generates the following ScriptBlock for the same and then executes it by calling the Invoke-Command cmdlet: 

$dbName = "CommonDB"
$datafileName = "E:\my files\sql.2012\data\CommonDb.mdf"
$logfileName = "E:\my files\sql.2012\data\CommonDb_log.ldf"
Invoke-Sqlcmd -ServerInstance localhost\sql2012 -Database master -Username sa -Password xxxx -ErrorAction Stop -InputFile .\CreateDatabase.sql -Variable dbName=$dbName, datafileName=$datafileName, logfileName=$logfileName

#>

Function Invoke-SQLFile( [string] $script_file, [System.Collections.Generic.List[string]]$parameter_names) {

    #Assuming that $serverInstance, $db, $username, and $password are global variables
    $invokeSql_Script = "Invoke-Sqlcmd -ServerInstance `"$serverInstance`" -Database `"$db`" -Username `"$username`" -Password `"$password`" -ErrorAction Stop -InputFile `"$script_file`" "

    $scriptStr = ""

    #The script file may or may not accept parameters
    if(($null -ne $parameter_names) -and ($parameter_names.Count -gt 0)){
        $invokeSqlVariableStr = ""
        foreach($param in $parameter_names){
            #There would be a global variable with the same name as the parameter_name 
            # e.g. If the param name is "databaseName", there should be a global variable called $databaseName
            $paramVal = Get-Variable -Name $param | Select-Object -Property Value 
            $scriptStr = "$scriptStr `$$param = `"$($paramVal.Value)`";`r`n" 
            $invokeSqlVariableStr = "$invokeSqlVariableStr $param=`"`$$param`", "
        }
        #remove the trailing ".," from the string
        $invokeSqlVariableStr = $invokeSqlVariableStr -replace ".{2}$"
        $scriptStr = "$scriptStr $invokeSql_Script -Variable $invokeSqlVariableStr"
    }
    else {
        #if no parameters need to be passed, then the $invokeSql_Script is good enough
        $scriptStr = $invokeSql_Script
    }
    $scriptBlock = [System.Management.Automation.ScriptBlock]::Create($scriptStr)
    Invoke-Command -ScriptBlock $scriptBlock    
}

Спасибо @rAJ за эту идею.

Тем не менее, я до сих пор не знаю, почему мой первоначальный скрипт не работал.И указатели там ценятся.

0 голосов
/ 25 апреля 2019

Попробуйте:

$params=@{"dbName"="CommonDB"; "datafileName"="E:\my files\sql.2012\data\CommonDb.mdf"; "logfileName"="E:\my files\sql.2012\data\CommonDb_log.ldf"}

ИЛИ

$dbName = "CommonDB"
$datafileName = "E:\my files\sql.2012\data\CommonDb.mdf"
$logfileName = "E:\my files\sql.2012\data\CommonDb_log.ldf"
Invoke-Sqlcmd -ServerInstance localhost\sql2012 -Database master -Username sa -Password xxxx -ErrorAction Stop -InputFile .\CreateDatabase.sql -Variable dbName=$dbName, datafileName=$datafileName, logfileName=$logfileName
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...