Solving a Collation Problem between Two Tables - sql

I have the following SQL script, trying to perform a union on two tables located on the same database. One table appears to have a different collation type
select * from ns.TurnsCOS
union all
select * from ns.TurnsValue
After running, I get the following error
I've read the other posts related to fixing collation issues, but adding 'Collate Latin1_General_Bin' after the from clause doesn't seem to work
How best can I resolve this collation issue between the two tables?

You have to change the collation of each column individually e.g.
select OtherCols, Col1, Col6, Col7
from ns.TurnsCOS
union all
select OtherCols, Col1 collate SQL_Latin1_General_CP1_CI_AS, Col6 collate SQL_Latin1_General_CP1_CI_AS, Col7 collate SQL_Latin1_General_CP1_CI_AS
from ns.TurnsValue
You can permanently change the column collation as follows - but you should be very cautious doing so as it may then conflict with other existing queries:
ALTER TABLE [TableName] ALTER COLUMN [Col_Name]
[Existing Data-Type] COLLATE [New_Collation] [NULL | NOT NULL];
GO
Ref: https://learn.microsoft.com/en-us/sql/relational-databases/collations/set-or-change-the-column-collation?view=sql-server-2017

Related

How to use EXCEPT clause in multiple databases

I have a query with an except clause. Underneath the except, my 2nd query is coming from a different database than the one that the first query is using.
It looks something like this
SELECT field1 as a
FROM table 1
EXCEPT
USE differentdb
SELECT field2 as a
FROM table 2
I have also tried this
SELECT field1 as a
FROM table 1
EXCEPT
USE differentdb
SELECT field2 as a
FROM differentdb.dbo.table2
I realize that this is not allowed in SQL because I get the following error:
Msg 468, Level 16, State 9, Line 1 Cannot resolve the collation
conflict between "SQL_Latin1_General_CP1_CI_AS" and
"Latin1_General_CI_AS" in the equal to operation.
I am wondering if there is another way to write this query and accomplish a cross-db EXCEPT clause.
Change the collation of column on the fly like:
SELECT field1 COLLATE SQL_Latin1_General_CP1_CI_AS as a
FROM table 1
EXCEPT
SELECT differentdb.SchemaName.field2 as a
FROM table 2
Us can use collate clause to convert collation from other database.
SELECT field2 collate SQL_Latin1_General_CP1_CI_AS as a
FROM table 2
Here you should use correct collation - because it is not enough information what is collation of your first and second databases.
Or you can simply use
SELECT field2 collate database_default as a
FROM table 2
This will cause the collate clause to inherit the collation of the current database

Is the LIKE operator case-sensitive with SQL Server?

In the documentation about the LIKE operator, nothing is told about the case-sensitivity of it. Is it? How to enable/disable it?
I am querying varchar(n) columns, on an Microsoft SQL Server 2005 installation, if that matters.
It is not the operator that is case sensitive, it is the column itself.
When a SQL Server installation is performed a default collation is chosen to the instance. Unless explicitly mentioned otherwise (check the collate clause bellow) when a new database is created it inherits the collation from the instance and when a new column is created it inherits the collation from the database it belongs.
A collation like sql_latin1_general_cp1_ci_as dictates how the content of the column should be treated. CI stands for case insensitive and AS stands for accent sensitive.
A complete list of collations is available at https://msdn.microsoft.com/en-us/library/ms144250(v=sql.105).aspx
(a) To check a instance collation
select serverproperty('collation')
(b) To check a database collation
select databasepropertyex('databasename', 'collation') sqlcollation
(c) To create a database using a different collation
create database exampledatabase
collate sql_latin1_general_cp1_cs_as
(d) To create a column using a different collation
create table exampletable (
examplecolumn varchar(10) collate sql_latin1_general_cp1_ci_as null
)
(e) To modify a column collation
alter table exampletable
alter column examplecolumn varchar(10) collate sql_latin1_general_cp1_ci_as null
It is possible to change a instance and database collations but it does not affect previously created objects.
It is also possible to change a column collation on the fly for string comparison, but this is highly unrecommended in a production environment because it is extremely costly.
select
column1 collate sql_latin1_general_cp1_ci_as as column1
from table1
All this talk about collation seem a bit over-complicated. Why not just use something like:
IF UPPER(##VERSION) NOT LIKE '%AZURE%'
Then your check is case insensitive whatever the collation
If you want to achieve a case sensitive search without changing the collation of the column / database / server, you can always use the COLLATE clause, e.g.
USE tempdb;
GO
CREATE TABLE dbo.foo(bar VARCHAR(32) COLLATE Latin1_General_CS_AS);
GO
INSERT dbo.foo VALUES('John'),('john');
GO
SELECT bar FROM dbo.foo
WHERE bar LIKE 'j%';
-- 1 row
SELECT bar FROM dbo.foo
WHERE bar COLLATE Latin1_General_CI_AS LIKE 'j%';
-- 2 rows
GO
DROP TABLE dbo.foo;
Works the other way, too, if your column / database / server is case sensitive and you don't want a case sensitive search, e.g.
USE tempdb;
GO
CREATE TABLE dbo.foo(bar VARCHAR(32) COLLATE Latin1_General_CI_AS);
GO
INSERT dbo.foo VALUES('John'),('john');
GO
SELECT bar FROM dbo.foo
WHERE bar LIKE 'j%';
-- 2 rows
SELECT bar FROM dbo.foo
WHERE bar COLLATE Latin1_General_CS_AS LIKE 'j%';
-- 1 row
GO
DROP TABLE dbo.foo;
You have an option to define collation order at the time of defining your table. If you define a case-sensitive order, your LIKE operator will behave in a case-sensitive way; if you define a case-insensitive collation order, the LIKE operator will ignore character case as well:
CREATE TABLE Test (
CI_Str VARCHAR(15) COLLATE Latin1_General_CI_AS -- Case-insensitive
, CS_Str VARCHAR(15) COLLATE Latin1_General_CS_AS -- Case-sensitive
);
Here is a quick demo on sqlfiddle showing the results of collation order on searches with LIKE.
The like operator takes two strings. These strings have to have compatible collations, which is explained here.
In my opinion, things then get complicated. The following query returns an error saying that the collations are incompatible:
select *
from INFORMATION_SCHEMA.TABLES
where 'abc' COLLATE SQL_Latin1_General_CP1_CI_AS like 'ABC' COLLATE SQL_Latin1_General_CP1_CS_AS
On a random machine here, the default collation is SQL_Latin1_General_CP1_CI_AS. The following query is successful, but returns no rows:
select *
from INFORMATION_SCHEMA.TABLES
where 'abc' like 'ABC' COLLATE SQL_Latin1_General_CP1_CS_AS
The values "abc" and "ABC" do not match in a case-sensitve world.
In other words, there is a difference between having no collation and using the default collation. When one side has no collation, then it is "assigned" an explicit collation from the other side.
(The results are the same when the explicit collation is on the left.)
Try running,
SELECT SERVERPROPERTY('COLLATION')
Then find out if your collation is case sensitive or not.
You can change from the property of every item.
You can easy change collation in Microsoft SQL Server Management studio.
right click table -> design.
choose your column, scroll down i column properties to Collation.
Set your sort preference by check "Case Sensitive"

collation conflict sql server

When i issue a SQL query, sometimes I get the following error message:
Cannot resolve the collation conflict between "Latin1_General_CI_AS" and "SQL_Latin1_General_CP1_CI_AS" in the equal to operation.
I often solve this problem just make both table collation same. so i need to know is there any quick way to fix this issue.
I'd like to put something special in my SQL query as a result if collation is not same for both table in sql query then also query will work perfectly without any error. is there any solution?
You can force which collation by using the COLLATE clause.
i.e.
SELECT *
FROM Table1 T1
INNER JOIN Server2.dbo.Table2 T2
ON T1.Name = T2.Name COLLATE database_default
Collation conflicts are common when joining tables between two databases or servers, especially if the version of the DB is different.
You can specify a collation in a query using the collate clause:
where col1 = col2 collate Latin1_General_CI_AS
There could be a possibility that both the servers use different Collations. If yes then you would get an error similar to then one I mentioned at the top of this topic. What you should do in this case?
You can alter the default Collation of either of the table columns/fields, but this could have a ripple effect for other tables currently in use with the altered table.
Use COLLATE DATABASE_DEFAULT keyword while matching the columns/fields
like:
SELECT T1.EmployeeName, T2.DeptName
FROM ServerA.dbo.EmpTab T1
JOIN ServerB.dbo.DeptTab T2
ON T1.DeptCode COLLATE DATABASE_DEFAULT
= T2.DeptCode COLLATE DATABASE_DEFAULT

How to find rows that have a value that contains a lowercase letter

I'm looking for an SQL query that gives me all rows where ColumnX contains any lowercase letter (e.g. "1234aaaa5789"). Same for uppercase.
SELECT * FROM my_table
WHERE UPPER(some_field) != some_field
This should work with funny characters like åäöøüæï. You might need to use a language-specific utf-8 collation for the table.
SELECT * FROM my_table WHERE my_column = 'my string'
COLLATE Latin1_General_CS_AS
This would make a case sensitive search.
EDIT
As stated in kouton's comment here and tormuto's comment here whosoever faces problem with the below collation
COLLATE Latin1_General_CS_AS
should first check the default collation for their SQL server, their respective database and the column in question; and pass in the default collation with the query expression. List of collations can be found here.
SELECT * FROM Yourtable
WHERE UPPER([column_NAME]) COLLATE Latin1_General_CS_AS !=[Column_NAME]
This is how I did it for utf8 encoded table and utf8_unicode_ci column, which doesn't seem to have been posted exactly:
SELECT *
FROM table
WHERE UPPER(column) != BINARY(column)
for search all rows in lowercase
SELECT *
FROM Test
WHERE col1
LIKE '%[abcdefghijklmnopqrstuvwxyz]%'
collate Latin1_General_CS_AS
Thanks Manesh Joseph
IN MS SQL server use the COLLATE clause.
SELECT Column1
FROM Table1
WHERE Column1 COLLATE Latin1_General_CS_AS = 'casesearch'
Adding COLLATE Latin1_General_CS_AS makes the search case sensitive.
Default Collation of the SQL Server installation SQL_Latin1_General_CP1_CI_AS is not case sensitive.
To change the collation of the any column for any table permanently run following query.
ALTER TABLE Table1
ALTER COLUMN Column1 VARCHAR(20)
COLLATE Latin1_General_CS_AS
To know the collation of the column for any table run following Stored Procedure.
EXEC sp_help DatabaseName
Source : SQL SERVER – Collate – Case Sensitive SQL Query Search
I've done something like this to find out the lower cases.
SELECT *
FROM YourTable
where BINARY_CHECKSUM(lower(ColumnName)) = BINARY_CHECKSUM(ColumnName)
mysql> SELECT '1234aaaa578' REGEXP '^[a-z]';
I have to add BINARY to the ColumnX, to get result as case sensitive
SELECT * FROM MyTable WHERE BINARY(ColumnX) REGEXP '^[a-z]';
I'm not an expert on MySQL I would suggest you look at REGEXP.
SELECT * FROM MyTable WHERE ColumnX REGEXP '^[a-z]';
In Posgresql you could use ~
For example you could search for all rows that have col_a with any letter in lowercase
select * from your_table where col_a '[a-z]';
You could modify the Regex expression according your needs.
Regards,
--For Sql
SELECT *
FROM tablename
WHERE tablecolumnname LIKE '%[a-z]%';
Logically speaking Rohit's solution should have worked, but it didn't. I think SQL Management Studio messed up when trying to optimize this.
But by modifying the string before comparing them I was able to get the right results. This worked for me:
SELECT [ExternalId]
FROM [EquipmentSerialsMaster] where LOWER('0'+[ExternalId]) COLLATE Latin1_General_CS_AS != '0'+[ExternalId]
This works in Firebird SQL, it should work in any SQL queries I believe, unless the underlying connection is not case sensitive.
To find records with any lower case letters:
select * from tablename where upper(fieldname) <> fieldname
To find records with any upper case letters:
select * from tablename where lower(fieldname) <> fieldname

SQL Server 2005 date comparison - collation issues

In my DB, I have a table that was created from an Excel sheet, via a Linked Server option.
I am now trying to compare its contents versus one of my main tables.
The tables I am comparing are in the same database.
There is a date column in both tables, both types are datetime and have Collation of SQL_Latin1_General_CP1_CI_AS, the same as the DB.
The server collation is Latin1_General_CI_AS
However when I try to run a query comparing the dates between the tables, I get the error:
Cannot resolve the collation conflict between
"Latin1_General_CI_AS" and
"SQL_Latin1_General_CP1_CI_AS" in the
equal to operation.
I have tried with and without the COLLATE option, using both collation settings.
My query is:
select * , hxl.holiday_dt,
datediff(d, h.holiday_dt collate SQL_Latin1_General_CP1_CI_AS,
hxl.holiday_dt collate SQL_Latin1_General_CP1_CI_AS)
from holiday h, Holiday_XL hxl
where h.currency_cd=hxl.currency_cd
In fact any query involving both tables gives exactly the same collation error, eg this one:
select count(*)
from Holiday_XL c
where c.currency_cd in (select distinct h.currency_cd from holiday h)
Thanks in advance for any thoughts.
Regards,
Chris
The error is being reported on the currency comparison h.currency_cd=hxl.currency_cd, not on datediff, so try force collation on the currencies.
Collation is only relevant for character (char, varchar, nvarchar) and text types.
Under the Collation and give the collation table level there are lot of tips and code available in net search with topic of collation.
Still if you have problem. Insert the content of the excel in to #table or permenant table and provide Collation to that table while selecting for comparison