If your server collation is different to your database collation then you may find that you get an error similar to this
Cannot resolve the collation conflict between “SQL_Latin1_General_CP1_CI_AS” and “Latin1_General_CI_AS” in the equal to operation.
when your queries use the tempdb
It would be useful to be able to quickly test if that may be the case and with the dbatools module you can. There is a Test-DbaDatabaseCollation command which will do just that. This page will show you how to install dbatools if you have not already got it
As always you should start with Get-Help when looking at a PowerShell command
Get-Help TestDbaDatabaseCollation -ShowWindow
There are only 3 parameters Sqlserver, Credential and detailed
Lets start with SQLServer
Test-DbaDatabaseCollation -SqlServer SQLvNextN2
this gives a quick and simple output showing the server name, database name and an IsEqual property
So in this example we can see that the WideWorldImporters database does not have the same collation as the server. If we only wanted to see information about databases with a collation that does not match the server then we could use
(Test-DbaDatabaseCollation -SqlServer SQLvNextN2).Where{$_.IsEqual -eq $false}
That doesn’t give us any further information though. There is the detailed parameter as well. Lets see what that does
Test-DbaDatabaseCollation -SqlServer SQLvNextN2 -Detailed
This time we get the server name, server collation, database name , database collation and the IsEqual property. This is a collection of objects so we are not bound be just seeing them on the screen we can use them as I blogged about here
For example
## Output to a file Test-DbaDatabaseCollation -SqlServer SQLvNextN2 -Detailed |Out-File C:\Temp\CollationCheck.txt ## Output to CSV Test-DbaDatabaseCollation -SqlServer SQLvNextN2 -Detailed |Export-Csv C:\temp\CollationCheck.csv -NoTypeInformation <## Output to JSON Test-DbaDatabaseCollation -SqlServer SQLvNextN2 -Detailed | ConvertTo-Json | Out-file c:\temp\CollationCheck.json ## Look at the files notepad C:\temp\CollationCheck.json notepad C:\temp\CollationCheck.csv notepad C:\temp\CollationCheck.txt
Of course, you will probably want to test more than one server at a time. Lets pass an array of servers and see what happens
$SQLServers = (Get-VM -ComputerName beardnuc | Where-Object {$_.Name -like '*SQL*' -and $_.Name -ne 'SQL2008Ser2008' -and $_.State -eq 'Running'}).Name # Test Db collation Test-DbaDatabaseCollation -SqlServer $SQLServers -Detailed
In this example, I am querying my Hyper-V server for all VMs with SQL in the name,except for my broken SQL2008 box ,that are running. I love PowerShell’s Out-GridView command for many reasons. The ability to sort by columns quickly and simply is one of them. Lets add that to the code and sort by the IsEquals column
$SQLServers = (Get-VM -ComputerName beardnuc | Where-Object {$_.Name -like '*SQL*' -and $_.Name -ne 'SQL2008Ser2008' -and $_.State -eq 'Running'}).Name # Test Db collation Test-DbaDatabaseCollation -SqlServer $SQLServers -Detailed | Out-GridView
Excellent, that works a treat. How about Linux? Does this work if SQL is running on Linux? We will have to use the credential parameter as we need SQL Authentication. this time I have used the Format-Table command to format the output.
$cred = Get-Credential Test-DbaDatabaseCollation -SqlServer LinuxvNextCTP14 -Credential $cred -Detailed | Format-Table -AutoSize
Lets add some Pester tests. If we want to test a list of servers and see if any of their databases have an incorrect collation we can simply test if the IsEquals flag contains a false.
We can do this using TestCases. Test cases allow Pester to loop through a collection of ‘things’ The testcases parameter takes an array of hashtables. This all sounds very complicated to those unclear about PowerShell but here some code to do it.
$SQLServers = (Get-VM -ComputerName beardnuc | Where-Object {$_.Name -like '*SQL*' -and $_.Name -ne 'SQL2008Ser2008' -and $_.State -eq 'Running'}).Name $testCases= @() $SQLServers.ForEach{$testCases += @{Name = $_}}
The first line gathers the list of SQL Servers from the Hyper-V as before. You can get this from a text file, csv, Active Directory, CMS, registered servers list. The second line initiates the TestCases array and the third line iterates through the list of servers and adds a hashtable to the TestCases array
To make use of the test cases we have to use the -TestCases parameter in our It block of our Pester Test and add a param() so that the test knows where to get the values from. To add the value from the test cases into the title of the test we need to reference it inside <>
If you want to learn more about Pester. I highly recommend The Pester Book by Don Jones and Adam Bertram
Here is the code
Describe "Testing Database Collation" { $SQLServers = (Get-VM -ComputerName beardnuc | Where-Object {$_.Name -like '*SQL*' -and $_.Name -ne 'SQL2008Ser2008' -and $_.State -eq 'Running'}).Name $testCases= @() $SQLServers.ForEach{$testCases += @{Name = $_}} It "<Name> databases have the right collation" -TestCases $testCases { Param($Name) $Collation = Test-DbaDatabaseCollation -SqlServer $Name $Collation.IsEqual -contains $false | Should Be $false } }
If we save that as a PowerShell file, we can call it with Invoke-Pester
which shows which servers do not have databases with the correct collation. This may be all that is required but what about if you want to check each database on each server with Pester?
I could not see a way to do this with TestCases so I reverted to PowerShell. Pester is just PowerShell code after all.
Describe "Testing Database Collation" { $SQLServers = (Get-VM -ComputerName beardnuc | Where-Object {$_.Name -like '*SQL*' -and $_.Name -ne 'SQL2008Ser2008' -and $_.State -eq 'Running'}).Name foreach($Server in $SQLServers) { $CollationTests = Test-DbaDatabaseCollation -SqlServer $Server foreach($CollationTest in $CollationTests) { It "$($Collationtest.Server) database $($CollationTest.Database) should have the correct collation" { $CollationTest.IsEqual | Should Be $true } } } }
In this example, we again gather the names of our SQL servers and then iterate through them. Then set the results of the Test-DBADatabaseCollation to a variable and iterate through each of the results and test the IsEquals property. We can save that as a file and call it with Invoke-Pester and this time it looks like
Excellent we can quickly and easily see which database on which server doesnot have a matching collation. We cant see in the results of the Pester test what collation it should be though. Lets do that as well.
This time we need to use the Detailed parameter and test that the ServerCollation matches the DatabaseCollation. This will enable Pester to display that information to us. Here is the code
Describe "Testing Database Collation" { $SQLServers = (Get-VM -ComputerName beardnuc | Where-Object {$_.Name -like '*SQL*' -and $_.Name -ne 'SQL2008Ser2008' -and $_.State -eq 'Running'}).Name foreach($Server in $SQLServers) { $CollationTests = Test-DbaDatabaseCollation -SqlServer $Server -Detailed foreach($CollationTest in $CollationTests) { It "$($Collationtest.Server) database $($CollationTest.Database) should have the correct collation of $($CollationTest.ServerCollation)" { $CollationTest.DatabaseCollation | Should Be $CollationTest.ServerCollation } } } }
Now Pester shows us what collation it is expecting and what the collation of the database is as well when it fails the test. (I love the little arrow showing where the difference is!)
Hopefully this post has shown you how you can use Test-DbaDatabaseCollation from the dbatools module to test your servers and combine that with Pester. If you have any questions about the dbatools module go and ask in the dbatools channel in the SQL Community Slack channel