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

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.

Related

SQL Server COLLATION ISSUE

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.

Temporary Table and Collation Issue?

My server database default collation is Arabic_CI_AS. In my application, I am never setting collation anywhere. But when I run this simple SQL,
CREATE TABLE #TempProductInventory
(
PID int
,InvTypeValue nvarchar(MAX)
,InvTypeKey nvarchar(MAX)
);
SELECT *
FROM #TempProductInventory TP
INNER JOIN dbo.[Sources] S ON (S.Code = TP.InvTypeKey)
I am getting,
Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "Arabic_CI_AS" in the equal to operation. When I un,
When I run,
SELECT col.name, col.collation_name FROM sys.columns col WHERE object_id = OBJECT_ID('Sources')
I will get,
name collation_name
ID NULL
Code Arabic_CI_AS
Try this, it will set the collation of temporary table to the one that you specify.
Most likely reason for this happening is as stated by GarethD that temp database collition is set not to Arabic_CI_AS.
CREATE TABLE #TempProductInventory( PID int ,InvTypeValue nvarchar(MAX) ,InvTypeKey nvarchar(MAX) Collate "Arabic_CI_AS")

Passing multiple value parameter to stored procedure

I have an existing stored procedure which accepts two single valued parameter. Now i have requirement to change one of its parameters to accept multiple values . I modified the stored procedure as below.
CREATE PROCEDURE [dbo].[GetSpecificationsM1]
#EntityType NVARCHAR(100)
,#EntityId BIGINT
AS
DECLARE #EntityTypeId AS BIGINT
SET #EntityTypeId=ISNULL((SELECT ID
FROM [ObjectTypes] WHERE [Type]=#EntityType),0)
SELECT ISNULL([Specifications].[Id],0) AS [SpecificationId]
,ISNULL([Specifications].[Measure],'') AS [Measure]
,ISNULL([Specifications].[Notes],'') AS [Notes]
,ISNULL([UOM].[UOM],'') As UOM
,ISNULL(SpecificationsTemplate.Name,'') As Specification
,ISNULL(SpecificationsTemplate.Id, 0) AS SpecificationTemplateId
,ISNULL(Specifications.EntityId, 0) AS EntityId
,(CASE WHEN ISNULL([SpecificationsTemplate].FieldTypeId,0)=0
THEN 8 ELSE [SpecificationsTemplate].FieldTypeId END) AS [FieldTypeId]
,ISNULL(SpecificationsTemplate.ListId,0) AS ListId
,ISNULL([Specifications].[ListItemId],0) AS [ListItemId]
FROM [SpecificationsTemplate] LEFT OUTER JOIN [Specifications]
ON [SpecificationsTemplate].[Id]=[Specifications].[SpecificationTemplateId]
AND [Specifications].[EntityTypeId]=#EntityTypeId
LEFT OUTER JOIN [UOM] ON [SpecificationsTemplate].[UOMId]=[UOM].[Id]
WHERE [Specifications].[EntityId] IN (#EntityId)
GO
In the above code I modified #EntityId to accept multiple values in the last line of the code. But I am getting an error as cannot convert Varchar to BigINt when i try to pass multiple values into the parameter as #EntityId=9,10,11.
Kindly help me out with the solution.
Thanks !
In your stored procedure change the parameter where condition something like below
Eg:
WHERE ([CostCentre]) collate database_default IN(SELECT Value FROM dbo.FnSplit(#CostCentre,','))
Complete code:
ALTER PROCEDURE [dbo].[SomeSP]
#CostCentre NVARCHAR(255)
AS
SELECT
[ProjectCode],[ProjectName], [ProjectManager],SUM([Hours]) AS [Hours MTD]
FROM dbo.Rpt_NRMA_CATS NC
INNER JOIN PeriodID P ON NC.PeriodID = P.PeriodID
WHERE
([CostCentre]) collate database_default IN (SELECT Value FROM dbo.FnSplit(#CostCentre, ','))
Just change your where condition to
WHERE [Specifications].[EntityId] IN (select item from dbo.fnSplit(#EntityId))
The code for fnSplit function is here

SQL Server: can't collate variables in SELECT-Statement

I have 2 databases (X and Y) on my SQL Server 2008 R2. For some reason the databases and the server have different encodings (SQL_Latin1_general_CP1_CI_AS and Latin1_General_CI_AS) so I'm always facing collate problems when I use temp tables or table variables.
Selecting some info from database Y into the table variable #info
When I try to join both in this way it work really fine:
select d.data_id, i.info_id, i.info_value
from X.aaa.data d
join #info i on i.serial COLLATE DATABASE_DEFAULT =
SUBSTRING(d.serial, 17, 10) COLLATE DATABASE_DEFAULT
But the serial length can be different for different products so I want to do it with a variable:
declare #serial_length int = 10;
-- some switch case to set #serial_length to some other value
select d.data_id, i.info_id, i.info_value
from X.aaa.data d
join #info i on i.serial COLLATE DATABASE_DEFAULT =
SUBSTRING(d.serial, 17, #serial_length) COLLATE DATABASE_DEFAULT
When I try this the query will just run forever and do nothing.
Is there a workaround for this problem? Or does at least anyone know why this is happening?
UPDATE: Thanks to MitchWheat the collate isn't a problem any more Changing Database Collation and dealing with TempDB Objects
But the SELECT still doesn't work. I'm using SUBSTRING(serial, 17, #serial_length) also in another procedure but without table variables and there it works.

SQL Server Collation conflict - creating a view

i am trying to create a View in a Database A, that is filled by a select from the Database B and i am having a collation conflict, to be more exactly , its between ( Latin1_General_CI_AS" and "Latin1_General_BIN ). WHere(in the code) i need to put the collate?
Best Regards.
The code is here:
CREATE VIEW [dbo].[CML_SDG_MENSAL_ESTOQUE]
AS
select
SUM(dw_fato_faturmes.val_fatur) val_fatur,
SUM(dw_fato_faturmes.val_receita) val_receita,
SUM(dw_fato_faturmes.qtd_bonif_item) qtd_bonif_item,
SUM(dw_fato_faturmes.val_bonif_fatur) val_bonif_fatur,
SUM(dw_fato_faturmes.val_bonif_receita) val_bonif_receita,
SUM(dw_fato_faturmes.val_devol_fatur) val_devol_fatur,
SUM(dw_fato_faturmes.val_devol_receita) val_devol_receita,
DW_DIM_PRODUTO.B1_CODDB B1_CODDB,
dw_fato_faturmes.cod_produto cod_produto,
SUM(dw_fato_faturmes.qtd_estoque) qtd_estoque,
SUM(dw_fato_faturmes.qtd_devol) qtd_devol,
SUM(dw_fato_faturmes.qtd_item) qtd_item,
SUM(dw_fato_faturmes.qtd_meta) qtd_meta,
SUM(dw_fato_faturmes.qtd_pedido) qtd_pedido,
SUM(dw_fato_faturmes.qtd_item)+
SUM(dw_fato_faturmes.qtd_bonif_item)+
SUM(dw_fato_faturmes.qtd_devol) venda_liquida
(SUM(dw_fato_faturmes.qtd_item)
+SUM(dw_fato_faturmes.qtd_bonif_item)
+SUM(dw_fato_faturmes.qtd_devol))
+SUM(dw_fato_faturmes.qtd_pedido) venda___pedido
FROM
logixbi.dbo.dw_fato_faturmes dw_fato_faturmes,
logixbi.dbo.DW_DIM_CLIENTE DW_DIM_CLIENTE,
DW_DIM_EMPRESA DW_DIM_EMPRESA,
logixbi.dbo.DW_DIM_MARCA DW_DIM_MARCA,
logixbi.dbo.DW_DIM_PRODUTO DW_DIM_PRODUTO,
logixbi.dbo.DW_DIM_REPRESENTANTE DW_DIM_REPRESENTANTE
where
DW_DIM_EMPRESA.SM0_FILIAL=dw_fato_faturmes.filial and
DW_DIM_MARCA.BM_GRUPO=dw_fato_faturmes.grupo and
DW_DIM_PRODUTO.B1_COD=dw_fato_faturmes.cod_produto and
DW_DIM_REPRESENTANTE.A3_COD=dw_fato_faturmes.vendedor and
DW_DIM_CLIENTE.A1_COD=dw_fato_faturmes.cliente and
DW_DIM_CLIENTE.A1_LOJA=dw_fato_faturmes.loja
group by DW_DIM_PRODUTO.B1_CODDB,dw_fato_faturmes.cod_produto
In order to find wich column has wich collation use this snippet:
SELECT name, collation_name
FROM sys.columns
WHERE OBJECT_ID IN (SELECT OBJECT_ID
FROM sys.objects
WHERE type = 'U'
AND name = 'your_table_name'
)
AND name = 'your_column_name'
Once you find the columns try this:
column_1 COLLATE your_collation = column_2 COLLATE your_collation
It is better to stick to a single collation globally. Otherwise you will have problems. Here is a snippet that will give you all the columns on your database with a COLLATION different than the one in the database
SELECT [TABLE_NAME] = OBJECT_NAME([id]),
[COLUMN_NAME] = [name],
[COLLATION_NAME] = collation
FROM syscolumns
WHERE collation <> 'your_database_collation_type'
AND collation IS NOT NULL
AND OBJECTPROPERTY([id], N'IsUserTable')=1
Where to put it depends on where the conflict is.
I'd suggest on the joins
ie
DW_DIM_EMPRESA.SM0_FILIAL COLLATE Latin1_General_CI_AS =dw_fato_faturmes.filial COLLATE Latin1_General_CI_AS
This is happening due to operation between different collation types so try this for statement for comparison.
ColumnA = ColumnB collate database_default
Try to use this in all your character matching conditions in where clause:
colnameA COLLATE Latin1_General_CI_AS = columnnameB COLLATE Latin1_General_CI_AS