【问题标题】:Why does this command work in SQL Server Management Studio but not from PowerShell为什么此命令在 SQL Server Management Studio 中有效,但在 PowerShell 中无效
【发布时间】:2018-04-01 14:55:02
【问题描述】:

我有以下 SQL 命令读取我的数据库的索引碎片,称为Logik

USE Logik

SELECT 
    OBJECT_NAME(ind.OBJECT_ID) AS TableName,
    ind.name AS IndexName, indexstats.index_type_desc AS IndexType,
    indexstats.avg_fragmentation_in_percent
FROM 
    sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) indexstats
INNER JOIN 
    sys.indexes ind ON ind.object_id = indexstats.object_id
                    AND ind.index_id = indexstats.index_id
WHERE 
    indexstats.avg_fragmentation_in_percent > 0

在 SQL Server Management Studio 中,这没有问题,并返回带有碎片的表。

昨天,这也适用于 PowerShell。我没有更改任何代码,但今天它不再工作了。有谁知道为什么?

$Data 将保持为空:

param(
    [string]$connectionstring = "Server=some\instance;uid=sa;pwd=dfdfdfdf;Database=Logik;Integrated Security=False;MultipleActiveResultSets=True;Connection Timeout=900;"
)

# Stop bei Fehler
$ErrorActionPreference = "SilentlyContinue"
$database = "logik"

# Database Connection herstellen
$con = New-Object System.Data.SqlClient.SqlConnection
$con.ConnectionString = $connectionstring
Try { $con.Open() } 
Catch { Throw $_.Exception.Message }

# command einlesen um Fragmentation zu lesen
$command = "
USE Logik
SELECT OBJECT_NAME(ind.OBJECT_ID) AS TableName,
ind.name AS IndexName, indexstats.index_type_desc AS IndexType,
indexstats.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) indexstats
INNER JOIN sys.indexes ind 
ON ind.object_id = indexstats.object_id
AND ind.index_id = indexstats.index_id
WHERE indexstats.avg_fragmentation_in_percent > 0"

# Command Zusammensetzen
$cmd = New-Object System.Data.SqlClient.SqlCommand
$cmd.CommandText = $command
$cmd.Connection = $con
$cmd.CommandTimeout = 2000

# Execute Command
Try { $result = $cmd.ExecuteReader() }
Catch { Throw $_.Exception.Message }

# Output von Resultat
$Data = New-Object System.Data.DataTable
$Data.load($result)

整个事情很奇怪,因为我加载数据后,将其放入另一个变量$tables,并且我想在$tables为空时抛出。

我使用这段代码检查是否有任何数据加载,它为$tables返回一个空行,但$tables.count返回8。这怎么可能?

# Logik Tabellen
$tables = $Data | ? { $_.avg_fragmentation_in_percent -ge 5 -and $_.IndexName -ne 0 }
if (!$tables) { Throw "Keine Datenbank gefunden, oder keine Höher als 5% Fragmentation" }
$tables.count ; $tables ; pause

【问题讨论】:

  • USE 后面应该跟着 GO - 确实是切换上下文;
  • @revoua 没有。 USE 是一个 batch 命令,只有 SSMS 和 sqlcmd 才能理解。这不是 T-SQL 命令
  • @SimonS USE 根本不应该使用。首先连接到您想要的数据库。 USE是SSMS或sqlcmd理解的批处理命令,不是T-SQL命令。
  • @PanagiotisKanavos 谢谢
  • @SimonS still no luck 不是错误消息。这次怎么了? 在 SSMS 中运行查询时是否有任何结果?确定没有错别字?

标签: sql-server powershell


【解决方案1】:

USE 根本不应该使用。这是 SSMS 或 sqlcmd 理解的批处理命令,而不是 T-SQL 命令。

在这种情况下,连接字符串已经连接到Logik 数据库。没有理由使用USE 切换到它。

只需使用:

$command = "
SELECT OBJECT_NAME(ind.OBJECT_ID) AS TableName,
ind.name AS IndexName, indexstats.index_type_desc AS IndexType,
...

如果您想在同一查询中使用来自不同数据库的表,请使用由三部分组成的名称,例如:MyDatabase.dbo.ThatTableName

您应该在 Powershell 脚本中使用 ADO.NET 库。如果您拼错变量名,Powershell 不会抱怨,它会创建一个新的空变量名。

请改用SQL Server Powershell provider。这样就可以编写如下代码:

Import-Module Sqlps -DisableNameChecking;
cd SQL\MyRemoteServer\DEFAULT\Databases\MyDatabase
$result=Invoke-SqlCmd -Query "SELECT @@VERSION;"

$result 变量将保存之后的查询结果。

如果查询返回多行,或者甚至是具有多个字段的单行,您将返回一个具有与列匹配的属性的对象数组。

以下查询:

$tables=Invoke-SqlCmd -Query "SELECT * from sys.tables"

将返回sys.tables 表的内容。您可以访问单个列作为属性。此脚本将返回所有表名:

$tables | %{ $_.name;}

链接在一起:

Invoke-SqlCmd -Query "SELECT * from sys.tables" | % {$_.name}

【讨论】:

  • 谢谢,不过我的脚本不走运。奇怪的是,$tables 中没有输出。但如果我使用$tables.count,它会返回8。奇怪
  • 如果您不提及问题所在,至少是一条错误消息,没有人可以提供帮助。顺便说一句,您为什么使用 ADO.NET 类而不是 SQL Server Powershell cmdlet?如果你拼错一个变量,Powershell 不会抱怨,它会创建一个 new empty 名称拼错的变量
  • 我在问题中非常清楚地解释了我的问题。我不使用 sqlserver cmdlet,因为我不在 SQL Server 本身上。
  • @SimonS 不幸的是,你没有解释它。 “它是空的”可能只是意味着你有一个错字。事实上,这就是 99% 的情况下结果为空的原因。请注意我提供的查询。我没有在本地服务器上运行它们。在我的机器上,我实际上使用了远程服务器的 IP
猜你喜欢
  • 1970-01-01
  • 2014-08-13
  • 1970-01-01
  • 1970-01-01
  • 2021-09-10
  • 1970-01-01
  • 1970-01-01
  • 2018-12-05
  • 2020-06-06
相关资源
最近更新 更多