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

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.

Related

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
)

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")

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 Collation mismatching issue

Have some collation(?) troubles when getting data from ADODB.RecordSet.
When selecting with SQL Management studio everything looks fine like
PriceMonitoring Справочник конкурентов2_Temp Table 6142061 dbo
Buuut, when i get data from powerdesigner's vbscript i got table names mismatching like
Table
Not in Model dbo.Ni?aai?iee eiieo?aioia2_Temp
Not in DB dbo.Справочник конкурентов2_Temp
For this moment i've already tried to specify different collations (COLLATE SQL_Latin1_General_CP1_CI_AS, Cyrillic_General_CI_AS, Ukrainian_CI_AS) in my sql script. I even changed DB collation, that doesn't help and had no effect to result. Any ideas, community?
That is a part of sql script.
SET NOCOUNT ON
USE DB_Control
SELECT ds.*, isnull(upo.Object_Name,'') as Object_Name_Updated, isnull(tuo.Object_Name,'') as Object_Name_Uncontrol
FROM
--
dbo.Design_Checksum AS ds
--
LEFT JOIN dbo.Uncontrolled_Object AS uo
ON uo.DB_Name = ds.DB_Name
AND uo.Object_Type_ID = ds.Object_Type_ID
AND uo.Schema_Name = ds.Schema_Name
AND uo.Object_Name COLLATE SQL_Latin1_General_CP1_CI_AS = ds.Object_Name COLLATE SQL_Latin1_General_CP1_CI_AS
--
LEFT JOIN dbo.Updated_Object AS upo
ON upo.DB_Name = ds.DB_Name
AND upo.Object_Type_ID = ds.Object_Type_ID
AND upo.Schema_Name = ds.Schema_Name
AND upo.Object_Name COLLATE SQL_Latin1_General_CP1_CI_AS = ds.Object_Name COLLATE SQL_Latin1_General_CP1_CI_AS
--
LEFT JOIN PD.Test_Uncontrolled_Object AS tuo
ON tuo.DB_Name = ds.DB_Name
AND tuo.Object_Type_ID = ds.Object_Type_ID
AND tuo.Schema_Name = ds.Schema_Name
AND tuo.Object_Name COLLATE SQL_Latin1_General_CP1_CI_AS = ds.Object_Name COLLATE SQL_Latin1_General_CP1_CI_AS
AND (tuo.Date_End IS NULL
OR tuo.Date_End > GETDATE())
WHERE
ds.DB_Name = 'PriceMonitoring'
AND uo.Object_Name IS NULL
ORDER BY
UPPER(REPLACE(ds.Object_Type_ID, '_', '!')),
UPPER(REPLACE(ds.Schema_Name, '_', '!')),
UPPER(REPLACE(ds.Object_Name, '_', '!'))

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