How can i set the collation SQL Server will use for the duration of that connection?
Not until i connect to SQL Server do i know what collation i want to use.
e.g. a browser with language fr-IT has connected to the web-site. Any queries i run on that connection i want to follow the French language, Italy variant collation.
i envision a hypothetical connection level property, simlar to SET ANSI_NULLS OFF, but for collation1:
SET COLLATION_ORDER 'French_CI_AS'
SELECT TOP 100 FROM Orders
ORDER BY ProjectName
and later
SELECT * FROM Orders
WHERE CustomerID = 3277
AND ProjectName LIKE '%l''ecole%'
and later
UPDATE Quotes
SET IsCompleted = 1
WHERE QuoteName = 'Cour de l''école'
At the same time, when a chinese customer connects:
SET COLLATION_ORDER Chinese_PRC_CI_AI_KS_WS
SELECT TOP 100 FROM Orders
ORDER BY ProjectName
or
SELECT * FROM Orders
WHERE CustomerID = 3277
AND ProjectName LIKE '學校'
or
UPDATE Quotes
SET IsCompleted = 1
WHERE QuoteName = '學校的操場'
Now i could alter every SELECT statement in the system to allow me to pass in a collation:
SELECT TOP 100 FROM Orders
WHERE CustomerID = 3278
ORDER BY ProjectName COLLATE French_CI_AS
But you cannot pass a collation order as a parameter to a stored procedure:
CREATE PROCEDURE dbo.GetCommonOrders
#CustomerID int, #CollationOrder varchar(50)
AS
SELECT TOP 100 FROM Orders
WHERE CustomerID = #CustomerID
ORDER BY ProjectName COLLATE #CollationOrder
And the COLLATE clause can't help me when performing an UPDATE or a SELECT.
Note: All string columns in the database all are already nchar, nvarchar or ntext. i am not talking about the default collation applied to a server, database, table, or column for non-unicode columns (i.e. char, varchar, text). i am talking about the collation used by SQL Server when comparing and sorting strings.
How can i specify per-connection collation?
See also
Similar question, but for ADO.net and connection strings
Similar question, but for ASP.net MVC2 and MySQL
1 hypothetical sql that exhibits locale issues
As marc_s commented, the collation is a property of a database or a column, and not of a connection.
However, you can override the collation on statement level using the COLLATE keyword.
Using your examples:
SELECT * FROM Orders
WHERE CustomerID = 3277
AND ProjectName COLLATE Chinese_PRC_CI_AI_KS_WS LIKE N'學校'
UPDATE Quotes
SET IsCompleted = 1
WHERE QuoteName COLLATE Chinese_PRC_CI_AI_KS_WS = N'學校的操場'
Still, I cannot find a statement on using COLLATE with a dynamic collation name, leaving as only possible solution dynamic SQL and EXEC. See this social.MSDN entry for an example.
Related
We are trying to execute a remote procedure on an Azure database :
INSERT INTO #temp (
ConsultantId
,UserId
,Name
,Email
,Phone
,DefaultContact
)
EXEC #RemoteResult = sp_execute_remote #RemoteSource
,#SQLString
,#ParmDefinition
,#userid = #userid;
Where #temp is a table with the same 6 columns as shown in the insert above.
However, we always get the $ShardName column returned even if we specify only the columns we need and as a result we also get the following error:
Column name or number of supplied values does not match table
definition.
Any ideas would be appreciated.
If I understand correctly, the solution to this problem is to simply add another column to the table to accept the [$Shard] column. It need to be in the right position and needs to have the correct data type. It doens't need the same name.
For clarity, it's worth creating it with the same name though.
Assuming $Shard was the final column from the proc, this should work:
INSERT INTO #temp (
ConsultantId
,UserId
,Name
,Email
,Phone
,DefaultContact
,[$Shard]
)
EXEC #RemoteResult = sp_execute_remote #RemoteSource
,#SQLString
,#ParmDefinition
,#userid = #userid;
Adding relevant documentation
sp_execute_remote (Azure SQL Database)
sp_execute_remote adds an additional column to the result set named '$ShardName' that contains the name of the remote database that produced the row.
I'm working with Spanish database so when I'm looking for and "aeiou" I can also get "áéíóú" or "AEIOU" or "ÁÉÍÓÚ", in a where clause like this:
SELECT * FROM myTable WHERE stringData like '%perez%'
I'm expencting:
* perez
* PEREZ
* Pérez
* PÉREZ
So I changed my database to collation: Modern_Spanish_CI_AI
And I get only:
* perez
* PEREZ
But if I do:
SELECT * FROM myTable WHERE stringData like '%perez%' COLLATE Modern_Spanish_CI_AI
I get all results OK, so my question is, why if my database is COLLATE Modern_Spanish_CI_AI I have to set the same collation to my query???
I'm using SQL-Server 2008
You can use COLLATE, eg.
SELECT *
FROM TableName
WHERE strData COLLATE Latin1_general_CI_AI = 'perez' COLLATE Latin1_general_CI_AI
both sides must have the same collation.
SQLFiddle Demo
SQLFiddle Demo (using LIKE)
Others:
Selecting a SQL Server Collation
You need to change the collation of the table COLUMN itself.
select collation_name, *
from sys.columns
where object_id = object_id('tblname')
and name = 'stringdata';
If you're lucky it is as easy as (example)
alter table tblname alter column stringdata varchar(20) collate Modern_Spanish_CI_AS
But if you have constraints and/or schema bound references, it can get complicated.
It can be very difficult to work with a database with mixed collations, so you may want to re-collate all the table columns.
How can i determine the name of the ROWGUIDCOL column in an SQL Server 2000 table?
i tried looking through syscolumns, e.g.:
SELECT *
FROM syscolumns
WHERE id = OBJECT_ID('Currencies')
But there is nothing there, or on the MSDN page that looks like rowguidcol.
Easy in SQL Server 2005
In SQL Server 2005 you just have to query sys.columns, e.g.:
SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID('Currencies')
AND is_rowguidcol = 1
Easy peasey.
You use COLUMNPROPERTY:
SELECT COLUMNPROPERTY(id, name, 'IsRowGuidCol'), * FROM syscolumns ... ;
In the format of the original question:
SELECT *
FROM syscolumns
WHERE id = OBJECT_ID('dbo.Currencies')
AND COLUMNPROPERTY(id, name, 'IsRowGuidCol') = 1;
For starters, if you don't know the rowguid column and you want to select it (but don't need to know its name for any other reason than to select it) you can do this:
SELECT $rowguid FROM YourTable;
If the table doesn't have a rowguid column:
In SQL 2000 you will get a column with name rowguid full of the value 0.00.
In SQL 2005 and up you will get an error, Invalid column name '$rowguid'.
For completeness note that in SQL 2005 and up you can also use $identity to get a table's identity column without knowing its name. In SQL 2000 you get Incorrect syntax near the keyword 'identity'.
i'm trying to do the following select:
select * from urlpath where substring(urlpathpath, 3, len(urlpathpath))
not in (select accessuserpassword from accessuser where accessuserparentid = 257)
I get the error:
Cannot resolve the collation conflict between
"SQL_Latin1_General_CP1_CI_AI" and
"SQL_Latin1_General_CP1_CI_AS" in the equal to operation.
Does anyone know how i can cast as a collation, or something that permits me to match this condition?
Thanx
You can add COLLATE CollationName after the column name for the column you want to "re-collate". (Note: the collation name is literal, not quoted)
You can even do the collate on the query to create a new table with that query, for example:
SELECT
*
INTO
#TempTable
FROM
View_total
WHERE
YEAR(ValidFrom) <= 2007
AND YEAR(ValidTo)>= 2007
AND Id_Product = '001'
AND ProductLine COLLATE DATABASE_DEFAULT IN (SELECT Product FROM #TempAUX)
COLLATE DATABASE_DEFAULT causes the COLLATE clause inherits the collation of the current database, eliminating the difference between the two
I have a table that originates in an old legacy system that was case senstive, in particular a status column where 's' = 'Schedule import' and 'S' = 'Schedule management'. This table eventually makes its way into a SQL Server 2000 database which I can query against. My query is relatively simple just going for counts...
Select trans_type, count(1) from mytable group by trans_type
This is grouping the counts for 'S' along with the 's' counts. Is there any way to force a query to be cap sensitive? I have access to both SQL Server 2000 and 2005 environments to run this, however have limited admin capability on the server (so I can't set server attributes)... I guess I could move the data to my local and setup something on my local where I have full access to server options, but would prefer a tsql solution.
select trans_type collate SQL_Latin1_General_CP1_CS_AS, count(*)
from mytable
group by trans_type collate SQL_Latin1_General_CP1_CS_AS
You can do this with =, like, and other operators as well. Note that you must modify the select list because you are no longer grouping by trans_type, you are now grouping by trans_type collate SQL_Latin1_General_CP1_CS_AS. Kind of a gotcha.
Can you introduce a trans_type_ascii column with the ascii value of the trans_type and group on that instead? Or any other column you can use (isUpperCase) to distinguish them.