sql-server - Invoke-SqlCmd 在包含另一个 Invoke-SqlCmd 的循环中使用时会生成异常
问题描述
Invoke-SqlCmd
当它包含第二个呼叫时,我遇到Invoke-SqlCmd
呼叫问题:
function Get-Foo
{
$query=`
@"
WITH data AS
(
SELECT 1 ID, 'A' NAME
UNION ALL
SELECT 2 ID, 'B' NAME
UNION ALL
SELECT 3 ID, 'C' NAME
)
SELECT *
FROM data
"@
Invoke-SqlCmd -ServerInstance "SERVER" -Database "DATABASE" -Query $query
}
function Get-Bar
{
param
(
[int]$ParentId
)
$query=`
@"
WITH data AS
(
SELECT 1 ID, 'A' NAME, 1 PARENT_ID
UNION ALL
SELECT 2 ID, 'B' NAME, 1 PARENT_ID
UNION ALL
SELECT 3 ID, 'C' NAME, 2 PARENT_ID
)
SELECT *
FROM data
WHERE parent_id = $ParentId
"@
Invoke-SqlCmd -ServerInstance "SERVER" -Database "DATABASE" -Query $query
}
Get-Foo | ForEach-Object {
Get-Bar -ParentId $_.ID
}
外循环的第一次迭代工作正常,但是当它尝试第二次迭代时,会生成异常:
Invoke-SqlCmd :无法从 BeginProcessing、ProcessRecord 和 EndProcessing 方法的覆盖范围之外调用 WriteObject 和 WriteError 方法,并且只能从同一线程中调用它们。验证 cmdlet 是否正确进行了这些调用,或联系 Microsoft 客户支持服务。在 Untitled-1.ps1:18 char:3 + Invoke-SqlCmd -ServerInstance "SERVER" -Database "DATABASE ... + ~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidResult: (SERVER:PSObject) [Invoke-Sqlcmd], PSInvalidOperationExceptio n + FullyQualifiedErrorId : ExecutionFailed,Microsoft.SqlServer.Management.PowerShell.GetScriptCommand
但是,此语法有效:
$foo = Get-Foo
$foo | ForEach-Object {
Get-Bar
}
我猜我需要关闭第一个Invoke-SqlCmd
,但也许还有另一种解决方案。
解决方案
这与 PowerShell 管道的工作方式有关(请参阅了解管道),以及Invoke-SqlCmd
它不喜欢并行运行多个查询的限制。
为了说明,让我们重写您的示例,如下所示:
function Invoke-SqlCmd
{
write-output "aaa";
write-output "bbb";
write-output "ccc";
}
function Get-Foo
{
write-host "Get-Foo started";
Invoke-SqlCmd;
write-host "Get-Foo finished";
}
function Get-Bar
{
param( $value )
write-host "Get-Bar '$value'";
}
现在运行这个脚本:
write-host "using pipelines"
Get-Foo | foreach-object { Get-Bar $_ }
这给出了这个输出:
using pipelines
Get-Foo started
Get-Bar 'aaa'
Get-Bar 'bbb'
Get-Bar 'ccc'
Get-Foo finished
如果您查看输出,您可以看到“Get-Bar”命令正在被调用,而 Get-Foo 在管道中仍处于“活动状态”。
与此相比:
write-host "using immediate evaluation"
(Get-Foo) | foreach { Get-Bar $_ }
这使:
using immediate evaluation
Get-Foo started
Get-Foo finished
Get-Bar 'aaa'
Get-Bar 'bbb'
Get-Bar 'ccc'
其中 Get-Foo 在值通过管道传输到 Get-Bar 之前执行完成。
您的具体错误是由于您的脚本使用多个并发管道步骤但Invoke-SqlCmd
不支持多个并发管道步骤。幸运的是,您可以通过几种不同的方式告诉 PowerShell 使用“立即评估”,包括其他答案中提到的方法:
- 首先将表达式分配给临时变量:
$foo = Get-Foo;
$foo | ForEach-Object { Get-Bar $_ }
- 在脚本中使用SubExpression 运算符(注意 $ 在某些情况下是可选的,根据 Powershell "$()" 中的“美元符号”是否可选?)
(Get-Foo) | Foreach-Object { Get-Bar $_ }
- 或将 Invoke-SqlCmd 包装在函数内的子表达式中。(这有点误导,因为 Get-Foo 在管道中仍然处于活动状态,但Invoke-SqlCmd 会立即评估)。
function Get-Foo
{
write-host "Get-Foo started";
(Invoke-SqlCmd);
write-host "Get-Foo finished";
}
推荐阅读
- java - 无法执行语句;SQL [不适用];约束 [PRIMARY]; 嵌套异常是 org.hibernate.exception.ConstraintViolationException
- java - 给定一个整数 N 和一个整数 G,找到所有 GCD 大于 G 的元素 <=N 对
- haskell - 具有多个相同变压器的 monad 堆栈
- firebase - Firestore 未将用户数据写入数据库
- go - 我的 div(4,2) 程序应该返回 (0, true) 并且 div(4,3) 应该返回 (1, false) 给出错误
- c++ - 如何通过继承实现移动构造函数和移动赋值运算符(抽象基类)
- javascript - jQuery each() 函数在 if 和 else 输出的 if/else 语句完成后不起作用
- c# - 如何获取字节数组内容
- python - 如何用我自己的自定义表单覆盖 django-rest-auth 中的表单?
- android - 无法解决:firebase-database-15.0.0。我修复了这个错误并得到另一个