I use a T-SQL command which I found here to get the fragmentation of my database tables. When I execute the T-SQL in the Management Studio, everything works. If I use it inside PowerShell, I get the following error (translated from German):
Exception when calling "ExecuteReader" with 0 Argument(s):
"Incorrect syntax near 'GO'.
Incorrect syntax near 'GO'."
In Zeile:17 Zeichen:6
+ $Result = $cmd.ExecuteReader()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SqlException
This is the part of my script which throws the error
foreach ($table in $tables)
{
$Data = New-Object System.Data.DataTable
$cmd = New-Object System.Data.SqlClient.SqlCommand
$getFragRate = "
-- SQL Command von Microsoft um die Index Fragmentation zu überprüfen
USE Logik;
GO
SELECT a.index_id, name, avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats (DB_ID(N'Logik'), OBJECT_ID(N'$($table)'), NULL, NULL, NULL) AS a
JOIN sys.indexes AS b ON a.object_id = b.object_id AND a.index_id = b.index_id;
GO
"
$cmd.CommandText = $getFragRate
$cmd.Connection = $con
$Result = $cmd.ExecuteReader()
$Data.Load($Result)
$Data
}
Why does this error occur?
The User I use to do this has sysadmin, db_ddladmin and db_owner permission.
Edit: Another T-SQL Command to get all tables of my database worked without a problem from PowerShell.
GO is NOT a T-SQL command - therefore you cannot have it in T-SQL statements being executed from PowerShell.
GO is a batch separator used by SQL Server Management Studio.
You need to break up that statement into several individual statements yourself and execute them one by one.
Related
I'm having an odd issue using the System.Data.SqlClient in PowerShell. The following works, using MSSMS:
INSERT INTO [dbo].[secDb_AADDevices]
([objectGuid]
,[displayName]
,[deviceGuid])
VALUES
('test','here','now')
But when doing this in PowerShell:
$sqlQuery = "INSERT INTO secDb_AADDevices ('objectGuid','displayName','deviceGuid') VALUES('test','here','now')"
$sqlCmd=new-object system.Data.SqlClient.SqlCommand($sqlQuery, $sqlConn)
$sqlCmd.ExecuteNonQuery()
It fails;
Exception calling "ExecuteNonQuery" with "0" argument(s): "Invalid column name 'objectGuid'.
Invalid column name 'displayName'.
Invalid column name 'deviceGuid'."
At line:4 char:1
+ $sqlCmd.ExecuteNonQuery()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SqlException
The column types in MSSQL are nvarchar(50) not null.
I've simplified it as much as possible to reduce complexity while debugging, will parameterize when this part works.
I've triple-verified that MSSQL and PowerShell ($sqlConn object) are connected to the same server and database instance, using the exact same user.
We are going to migrate from SQL Server 2008 to 2016. I am in the process of identifying errors and I get the following error in a trigger:
Incorrect syntax near '51001'.
I looked through the Raiserror documentation on the Microsoft website and it did not help. The following is the SQL. Any help would be appreciated.
IF (SELECT count(*) FROM dbo.u_sample_concrete ref, deleted
WHERE ref.lab_cd = deleted.lab_id) > 0
BEGIN
RAISERROR 51001 ''Trigger td_tblLAB on table dbo.tblLAB: Primary key values found in table dbo.u_sample_concrete (lab_cd). Delete restricted; the transaction is being rolled back.''
ROLLBACK TRANSACTION
RETURN
END
Adding to #DaleK's answer with the proper syntax, the problem RAISERRROR syntax is long obsolete. IIRC, it was deprecated 20 years ago (with the SQL Server 2000 release) and removed entirely in SQL Server 2012.
Below is a powershell script that uses the T-SQL Script DOM (also available with the Dacfx NuGet package) to identify existing T-SQL modules with invalid syntax. It won't catch problems in dynamic SQL, though.
$connectionString = "Data Source=.;Initial Catalog=YourDatabase;Integrated Security=SSPI"
try {
$query = #"
SELECT
QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + N'.' + QUOTENAME(OBJECT_NAME(object_id)) AS ObjectName
, OBJECTPROPERTY(object_id, 'ExecIsQuotedIdentOn') AS ExecIsQuotedIdentOn
, definition
FROM sys.sql_modules;
"#
Add-Type -Path "C:\Program Files (x86)\Microsoft SQL Server\140\DAC\bin\Microsoft.SqlServer.TransactSql.ScriptDom.dll"
$connection = New-Object Data.SqlClient.SqlConnection($connectionString)
$command = New-Object Data.SqlClient.SqlCommand($query, $connection)
$connection.Open()
$reader = $command.ExecuteReader()
while ($reader.Read()) {
# use TSqlParser appropriate for your SQL Server version
$parser = New-Object Microsoft.SqlServer.TransactSql.ScriptDom.TSql130Parser($reader["ExecIsQuotedIdentOn"])
$parseErrors = New-Object Collections.Generic.List[Microsoft.SqlServer.TransactSql.ScriptDom.ParseError]
$scriptReader = New-Object IO.StringReader($($reader["definition"]))
Write-Host "Parsing $($reader["ObjectName"]) ..."
[void]$parser.Parse($scriptReader, [ref]$parseErrors)
if($parseErrors.Count -ne 0) {
Write-Host "Parsing errors for object $($reader["ObjectName"]): $($parseErrors | ConvertTo-Json)" -ForegroundColor Yellow
}
}
$connecton.Close()
}
catch {
throw
}
The Microsoft Documentation does indeed show 4 things wrong with your statement.
The parameters must be inside brackets raiserror().
4 parameters are expected when msd_id (51001) is used - you are providing 2.
Parameters should be separated by commas ,.
You are double quoting the string, when it should be single quoted.
RAISERROR (51001, -1,- 1, 'Trigger td_tblLAB on table dbo.tblLAB: Primary key values found in table dbo.u_sample_concrete (lab_cd). Delete restricted; the transaction is being rolled back.')
Note: its best practice now to use throw rather than raiserror.
I've spitted Glenn Berry's Performance Query in 14 queries but one of them (number 9) is not working.
This is my PowerShell code:
#Provide SQLServerName
$SQLServer ="localhost"
#Provide Database Name
$DatabaseName ="master"
#Prompt for user credentials
$credential = Get-Credential
$Query1= "-- 09 Index Sizes
-- Note: THIS IS SLOW as it reads index blocks. SAMPLED is not that high, but watch for prod I/O impact if using 'DETAILED'
SELECT DB_NAME() AS DatabaseName,
Object_name(i.object_id) AS TableName
,i.index_id, name AS IndexName
,i.type_desc
,ips.page_count, ips.compressed_page_count
,CAST(ips.avg_fragmentation_in_percent as DECIMAL(5,1)) [fragmentation_pct]
,CAST(ips.avg_page_space_used_in_percent as DECIMAL(5,1)) [page_space_used_pct]
,ips.index_depth, ips.page_count ,ips.forwarded_record_count, ips.record_count
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, 'SAMPLED') AS ips -- or SAMPLED
INNER JOIN sys.indexes AS i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
where ips.page_count > 1
ORDER BY ips.record_count desc;"
Invoke-Sqlcmd -Database $DatabaseName -ServerInstance $Server -Credential $credential -Query $Query1 | Format-Table
The error returned says:
Invoke-Sqlcmd : Duplicate column names are not permitted in SQL PowerShell. To repeat a column, use a column alias for the duplicate
column in the format Column_Name AS New_Name.
At C:\Users\FrancescoM\Desktop\CSV\Test.ps1:23 char:1
+ Invoke-Sqlcmd -Database $DatabaseName -ServerInstance $Server -Crede ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : SyntaxError: (:) [Invoke-Sqlcmd], SqlPowerShellSqlExecutionException
+ FullyQualifiedErrorId : DuplicateColumnNameErrorMessage,Microsoft.SqlServer.Management.PowerShell.GetScriptCommand
Not sure what is the duplicate column because if I run the query called into the PowerShell script on SSMS I don't see any duplicate column:
Arrived at home I formatted the query in a decent way and thanks to Notepad++, after clicking on each column I found out that ips.page_count was called twice.
So there was indeed a column called twice.
Use the following parameter for the Invoke-Sqlcmd command.
-OutputSqlErrors $False
It will suppress the error.
Documentation:
https://learn.microsoft.com/en-us/powershell/module/sqlserver/invoke-sqlcmd?view=sqlserver-ps
You get this error when you have duplicate column names in resultset of the query.
invoke-sqlcmd : Duplicate column names are not permitted in SQL PowerShell
Suppose you used below query as to see result-set in your invoke-sqlcmd query-
select test, * from testtable
Now the test column will be duplicate in the result and invoke sqlcmd execution will fail.
To Resolve this use like this-
select test as testColumn, * from testtable
Edit: It was a !##$ typo. In addition to the whitespace, the problem view used a hyphen where the naming convention required an underscore. Somehow I missed it.
I'm using Powershell to test queries on certain SQL Server tables and views, one of which has whitespace in its name. The schema looks like this:
TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE
------------- ------------ ---------- ----------
my_database dbo my_table BASE TABLE
my_database dbo my_view VIEW
my_database dbo my_other view VIEW
This script works perfectly on tables:
$table = "my_table"
$query = "SELECT * FROM $table"
$server = new-Object Microsoft.SqlServer.Management.Smo.Server("my_server")
$db = New-Object Microsoft.SqlServer.Management.Smo.Database
$db = $server.Databases.Item("my_database")
$dt = $db.ExecuteWithResults($query)
$dt.Tables[0] | Format-Table
But if I change line 1 to $table = "my_view", I get the following error:
Exception calling "ExecuteWithResults" with "1" argument(s): "Execute with results failed for Database 'my_database'. "
At line:6 char:1
+ $dt = $db.ExecuteWithResults($query)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : FailedOperationException
It works, though, when I enclose the view name in square brackets:
$table = "[my_view]"
However, $table = "[my_other view]" still throws that error.
What is the correct syntax to query a view with a space in the name?
Try using the syntax:
$table = "['my_other view']"
Where you use single quotes around the table name inside of square brackets.
Solved. It was a stupid, stupid typo. The problem view had a long name with a hyphen where the naming convention called for an underscore. I was focused on the whitespace and somehow missed it.
I'm trying to set a database name in powershell using Microsoft.SqlServer.SMO. When I execute my script it runs in error with the following error text:
format-default : Index was outside the bounds of the array.
+ CategoryInfo : NotSpecified: (:) [format-default], IndexOutOfRangeException
+ FullyQualifiedErrorId : System.IndexOutOfRangeException,Microsoft.PowerShell.Commands.FormatDefaultCommand
The server is set as follows
$srv = New-Object "Microsoft.SqlServer.Management.SMO.Server" $server
$srv.ConnectionContext.LoginSecure=$false;
$srv.ConnectionContext.set_Login("login");
$srv.ConnectionContext.set_Password("password")
$srv.Databases | Select name,
shows me the proper databases, but when setting the database,
$db = $srv.Databases[$database]
the error is thrown.
This scrip does work in other sqlservers.
Any solutions for this issue?
It looks like the database "CRD_DEV" does not exist on the server where the script throws the error.
That or the user does not have access to that database.
The IndexOutOfRangeException is thrown because there is no item in $srv.Databases that matches "CRD_DEV"