SQL Server COLLATION ISSUE - sql

I have table has field CHAR(3) collation set as database-default.
Database default is SQL_Latin1_General_CP1_CI_AS
I run a query where I am dumping the result of a stored proc into a temp table where I declare the field in question as CHAR(3)
CREATE TABLE #TempTable (
...
FieldAChar3 CHAR(3) NOT NULL
...
)
No mention of collation so I assume it uses the default!?
I do a union of my table and temp table on the field in question
SELECT Field1Char3 FROM Table1
UNION
SELECT FieldAChar3 FROM #TempTable
and I get a collation error of:
Msg 468, Level 16, State 9, Line 90
Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "Latin1_General_CI_AS" in the UNION operation.
Obvious I can apply the collate statement of the default setting
collate database_default or
collate SQL_Latin1_General_CP1_CI_AS
to the second union statement as a work around but why am I getting the error in the first place?
Is it possible the collation was not applied like an SQL Server bug.
I can verify the collation was changed on the database prior to the creation of the table.

Your tempdb and database have different collation settings. This often happens when servers are upgraded from a version using the older collation defaults.
You could create the temp table with the SQL_Latin1_General_CP1_CI_AS collation.
There are few differences between SQL_Latin1_General_CP1_CI_AS and Latin1_General_CI_AS. They both use the same Locale (1033) and the same Code Page (1252).
The SQL_ Collations have been deprecated for some time and should be avoided if possible.

Related

"SQL_Latin1_General_CP1_CI_AS" in the equal to operation

Hi i am new to SQL queries
My query is
ALTER TABLE ValidIBAN NOCHECK CONSTRAINT FK_ValidIBAN_Countries
UPDATE t
SET t.CountryID = s.Corrected
from #TempNewCountryID s,Countries t
where
s.Existing = t.CountryID
but after running this query i am getting
Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AI" and "SQL_Latin1_General_CP1_CI_AS" in the equal to operation.
Error Please suggest.
Depends on which logic is required (Accent sensitive or insensitive), use COLLATE on both sides of your equal sign: WHERE s.Existing COLLATE SQL_Latin1_General_CP1_CI_AI = t.CountryID COLLATE SQL_Latin1_General_CP1_CI_AI
If you update collate on table, or database(if needed), even in the server(if needed), then you never such an error.
ALTER TABLE tbl1 CONVERT TO CHARACTER SET utf8mb4 COLLATE SQL_Latin1_General_CP1_CI_AI;
I think it is better to update collate on the table rather than using it on queries.

Collation Issue in Stored Procedure

I'm getting 'Cannot resolve the collation conflict between "Latin1_General_CI_AS" and "SQL_Latin1_General_CP1_CI_AS" in the equal to operation.' error.
The error is in a SP, I'm not specifying the collation anywhere, neither in the create table and when I use
select t.name, c.*, c.collation_name
from sys.columns c
left join sys.tables t
on c.object_id = t.object_id
order by c.collation_name
It says there is no 'Latin1_General_CI_AS' fields, all the fields are using the default collation. I'm returning a dataset but can't see where the error is. There are no joins. I am populating a temporary table, again, not specifying the collation yet it says there's an error. Any suggestions. Using SQL Server 2014.
Temporary tables use the collation of tempdb by default except if used in the context of a contained database.
You can specify COLLATE DATABASE_DEFAULT to have it use the collation of the current database.
CREATE TABLE #T
(
SomeColumn VARCHAR(50) COLLATE DATABASE_DEFAULT
)

How to compare varchar parameter to null in a natively compiled stored procedure?

I am migrating some tables and stored procedures to in-memory optimized tables and natively compiled stored procedures and am getting stuck on a null comparison.
Here is my code:
CREATE TABLE [dbo].[MyInMemTable]
(
[MyId] int NOT NULL IDENTITY(1,1),
[MyData] varchar(900) COLLATE Latin1_General_100_BIN2 not null
CONSTRAINT [PK_MyInMemTable] PRIMARY KEY NONCLUSTERED ([MyId])
) WITH (MEMORY_OPTIMIZED = ON, DURABILITY=SCHEMA_ONLY)
GO
CREATE PROCEDURE [dbo].[sp_InsertIntoMyInMemTable](#MyData varchar(900))
WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER
AS
BEGIN ATOMIC WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'English')
IF #MyData IS NOT NULL
BEGIN
INSERT INTO dbo.[MyInMemTable] (MyData) VALUES (#MyData)
SELECT SCOPE_IDENTITY()
END
ELSE
SELECT 0
END
I get the following error:
Msg 12327, Level 16, State 101, Procedure sp_InsertIntoMyInMemTable, Line 306
Comparison, sorting, and manipulation of character strings that do not use a *_BIN2 collation is not supported with natively compiled stored procedures.
How do I specify a collation on the parameter, or is there an alternative way to get this null comparison to work?
please see the comments from #Eric J, above.
You can add " Collate {Collation Value} " pretty much anywhere you can specify a field with collation it seems. Did you try " IF #MyData Collate {Collation} IS NOT NULL"?
I just put this as answer to help people finding it.

Temp Table collation conflict - Error : Cannot resolve the collation conflict between Latin1* and SQL_Latin1*

I can't update temp table. This is my query
CREATE TABLE #temp_po(IndentID INT, OIndentDetailID INT, OD1 VARCHAR(50), OD2 VARCHAR(50),
OD3 VARCHAR(50), ORD VARCHAR(50), NIndentDetailID INT, ND1 VARCHAR(50), ND2 VARCHAR(50),
ND3 VARCHAR(50), NRD VARCHAR(50), Quantity DECIMAL(15,3))
INSERT INTO #temp_po(IndentID, OIndentDetailID, OD1, OD2, OD3, ORD)
SELECT ID.IndentID, ID.IndentDetailID, ID.D1, ID.D2, ID.D3, ID.RandomDimension
FROM STR_IndentDetail ID WHERE ID.IndentID = #IndentID
UPDATE
t
SET
t.ND1 = CASE WHEN D.D1 = '' THEN NULL ELSE D.D1 END,
t.ND2 = CASE WHEN D.D2 = '' THEN NULL ELSE D.D2 END,
t.ND3 = CASE WHEN D.D3 = '' THEN NULL ELSE D.D3 END,
t.NRD = CASE WHEN D.RandomDim = '' THEN NULL ELSE D.RandomDim END,
t.Quantity = D.PurchaseQty
FROM
#temp_po t INNER JOIN #detail D ON D.IndentDetailID = t.OIndentDetailID
WHERE
t.IndentID = #IndentID
But it gives the error
Cannot resolve the collation conflict between "Latin1_General_CI_AI" and "SQL_Latin1_General_CP1_CI_AS" in the equal to operation.
How to resolve this problem?
My tempdb collation is Latin1_General_CI_AI and my actual database collation is SQL_Latin1_General_CP1_CI_AS.
This happens because the collations on #tempdb.temp_po.OD1 and STR_IndentDetail.D1 are different (and specifically, note that #tempdb is a different, system database, which is generally why it will have a default opinion for collation, unlike your own databases and tables where you may have provided more specific opinions).
Since you have control over the creation of the temp table, the easiest way to solve this appears to be to create *char columns in the temp table with the same collation as your STR_IndentDetail table:
CREATE TABLE #temp_po(
IndentID INT,
OIndentDetailID INT,
OD1 VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS,
.. Same for the other *char columns
In the situation where you don't have control over the table creation, when you join the columns, another way is to add explicit COLLATE statements in the DML where errors occur, either via COLLATE SQL_Latin1_General_CP1_CI_AS or easier, using COLLATE DATABASE_DEFAULT
SELECT * FROM #temp_po t INNER JOIN STR_IndentDetail s
ON t.OD1 = s.D1 COLLATE SQL_Latin1_General_CP1_CI_AS;
OR, easier
SELECT * FROM #temp_po t INNER JOIN STR_IndentDetail s
ON t.OD1 = s.D1 COLLATE DATABASE_DEFAULT;
SqlFiddle here
Changing the server collation is not a straight forward decision, there may be other databases on the server which may get impacted. Even changing the database collation is not always advisable for an existing populated database. I think using COLLATE DATABASE_DEFAULT when creating temp table is the safest and easiest option as it does not hard code any collation in your sql. For example:
CREATE TABLE #temp_table1
(
column_1 VARCHAR(2) COLLATE database_default
)
By default temp table take the collation of server. So instead updating all stored procedure with temp table change only server collation.
Check this link for Set or Change the Server Collation
This worked for me.
We ran into the same problem right now. Instead of adding the collation to the temp table creation (or to each temp table join), we just changed the temp table creation to a table variable declaration.

SQL Server check case-sensitivity?

How can I check to see if a database in SQL Server is case-sensitive? I have previously been running the query:
SELECT CASE WHEN 'A' = 'a' THEN 'NOT CASE SENSITIVE' ELSE 'CASE SENSITIVE' END
But I am looking for other ways as this has actually given me issues in the past.
Edit - A little more info:
An existing product has many pre-written stored procedures. In a stored procedure #test != #TEST depending on the sensitivity of the server itself. So what I'm looking for is the best way to check the server for its sensitivity.
Collation can be set at various levels:
Server
Database
Column
So you could have a Case Sensitive Column in a Case Insensitive database. I have not yet come across a situation where a business case could be made for case sensitivity of a single column of data, but I suppose there could be.
Check Server Collation
SELECT SERVERPROPERTY('COLLATION')
Check Database Collation
SELECT DATABASEPROPERTYEX('AdventureWorks', 'Collation') SQLCollation;
Check Column Collation
select table_name, column_name, collation_name
from INFORMATION_SCHEMA.COLUMNS
where table_name = #table_name
If you installed SQL Server with the default collation options, you might find that the following queries return the same results:
CREATE TABLE mytable
(
mycolumn VARCHAR(10)
)
GO
SET NOCOUNT ON
INSERT mytable VALUES('Case')
GO
SELECT mycolumn FROM mytable WHERE mycolumn='Case'
SELECT mycolumn FROM mytable WHERE mycolumn='caSE'
SELECT mycolumn FROM mytable WHERE mycolumn='case'
You can alter your query by forcing collation at the column level:
SELECT myColumn FROM myTable
WHERE myColumn COLLATE Latin1_General_CS_AS = 'caSE'
SELECT myColumn FROM myTable
WHERE myColumn COLLATE Latin1_General_CS_AS = 'case'
SELECT myColumn FROM myTable
WHERE myColumn COLLATE Latin1_General_CS_AS = 'Case'
-- if myColumn has an index, you will likely benefit by adding
-- AND myColumn = 'case'
SELECT DATABASEPROPERTYEX('<database name>', 'Collation')
As changing this setting can impact applications and SQL queries, I would isolate this test first. From SQL Server 2000, you can easily run an ALTER TABLE statement to change the sort order of a specific column, forcing it to be case sensitive. First, execute the following query to determine what you need to change it back to:
EXEC sp_help 'mytable'
The second recordset should contain the following information, in a default scenario:
Column_Name Collation
mycolumn SQL_Latin1_General_CP1_CI_AS
Whatever the 'Collation' column returns, you now know what you need to change it back to after you make the following change, which will force case sensitivity:
ALTER TABLE mytable
ALTER COLUMN mycolumn VARCHAR(10)
COLLATE Latin1_General_CS_AS
GO
SELECT mycolumn FROM mytable WHERE mycolumn='Case'
SELECT mycolumn FROM mytable WHERE mycolumn='caSE'
SELECT mycolumn FROM mytable WHERE mycolumn='case'
If this screws things up, you can change it back, simply by issuing a new ALTER TABLE statement (be sure to replace my COLLATE identifier with the one you found previously):
ALTER TABLE mytable
ALTER COLUMN mycolumn VARCHAR(10)
COLLATE SQL_Latin1_General_CP1_CI_AS
If you are stuck with SQL Server 7.0, you can try this workaround, which might be a little more of a performance hit (you should only get a result for the FIRST match):
SELECT mycolumn FROM mytable WHERE
mycolumn = 'case' AND
CAST(mycolumn AS VARBINARY(10)) = CAST('Case' AS VARBINARY(10))
SELECT mycolumn FROM mytable WHERE
mycolumn = 'case' AND
CAST(mycolumn AS VARBINARY(10)) = CAST('caSE' AS VARBINARY(10))
SELECT mycolumn FROM mytable WHERE
mycolumn = 'case' AND
CAST(mycolumn AS VARBINARY(10)) = CAST('case' AS VARBINARY(10))
-- if myColumn has an index, you will likely benefit by adding
-- AND myColumn = 'case'
SQL server determines case sensitivity by COLLATION.
COLLATION can be set at various levels.
Server-level
Database-level
Column-level
Expression-level
Here is the MSDN reference.
One can check the COLLATION at each level as mentioned in Raj More's answer.
Check Server Collation
SELECT SERVERPROPERTY('COLLATION')
Check Database Collation
SELECT DATABASEPROPERTYEX('AdventureWorks', 'Collation') SQLCollation;
Check Column Collation
select table_name, column_name, collation_name
from INFORMATION_SCHEMA.COLUMNS
where table_name = #table_name
Check Expression Collation
For expression level COLLATION you need to look at the expression. :)
It would be generally at the end of the expression as in below example.
SELECT name FROM customer ORDER BY name COLLATE Latin1_General_CS_AI;
Collation Description
For getting description of each COLLATION value try this.
SELECT * FROM fn_helpcollations()
And you should see something like this.
You can always put a WHERE clause to filter and see description only for your COLLATION.
You can find a list of collations here.
You're interested in the collation. You could build something based on this snippet:
SELECT DATABASEPROPERTYEX('master', 'Collation');
Update
Based on your edit — If #test and #TEST can ever refer to two different variables, it's not SQL Server. If you see problems where the same variable is not equal to itself, check if that variable is NULL, because NULL = NULL returns `false.
The best way to work with already created tables is that,
Go to Sql Server Query Editor
Type: sp_help <tablename>
This will show table's structure , see the details for the desired field under COLLATE column.
then type in the query like :
SELECT myColumn FROM myTable
WHERE myColumn COLLATE SQL_Latin1_General_CP1_CI_AS = 'Case'
It could be different character schema <SQL_Latin1_General_CP1_CI_AS>, so better to find out the exact schema that has been used against that column.
How can I check to see if a database in SQL Server is case-sensitive?
You can use below query that returns your informed database is case sensitive or not or is in binary sort(with null result):
;WITH collations AS (
SELECT
name,
CASE
WHEN description like '%case-insensitive%' THEN 0
WHEN description like '%case-sensitive%' THEN 1
END isCaseSensitive
FROM
sys.fn_helpcollations()
)
SELECT *
FROM collations
WHERE name = CONVERT(varchar, DATABASEPROPERTYEX('yourDatabaseName','collation'));
For more read this MSDN information ;).
SQL Server is not case sensitive. SELECT * FROM SomeTable is the same as SeLeCT * frOM soMetaBLe.