What are the rules for using COLLATE in a query?
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
3
down vote
favorite
I am putting a script together, that gives me the permissions on database objects.
SELECT permission_order=710
,permission_type = 'Object Level Permissions'
,db = db_name(),
login_=null,
role_=dp.name collate Latin1_General_CI_AS,
Obj = sys.schemas.name + '.' + so.name collate Latin1_General_CI_AS,
Permission = permission_name collate Latin1_General_CI_AS,
[script]=
'IF OBJECT_ID (' + '''' + '['+ sys.schemas.name + '].[' + so.name + ']' + '''' + ') IS NOT NULL ' + CHAR(10) + state_desc +
' ' + permission_name + ' on ['+ sys.schemas.name + '].[' + so.name + '] to [' + dp.name + ']' collate Latin1_General_CI_AS + CHAR(10) +
'ELSE ' + CHAR(10) +
'print ' + '''['+ sys.schemas.name + '].[' + so.name + '] - does not exist'''
+ CHAR(13)
from sys.database_permissions a
INNER JOIN sys.objects so on a.major_id = so.object_id
INNER JOIN sys.schemas on so.schema_id = sys.schemas.schema_id
INNER JOIN sys.database_principals dp on a.grantee_principal_id = dp.principal_id
WHERE dp.name NOT IN ( 'public', 'guest')
AND a.class = 1
I want to use the word collate
as few times as possible and still have a script that runs for multi-databases, multi-collations server.
How can I achieve that?
What is the rule for applying collate
?
sql-server t-sql permissions scripting collation
add a comment |Â
up vote
3
down vote
favorite
I am putting a script together, that gives me the permissions on database objects.
SELECT permission_order=710
,permission_type = 'Object Level Permissions'
,db = db_name(),
login_=null,
role_=dp.name collate Latin1_General_CI_AS,
Obj = sys.schemas.name + '.' + so.name collate Latin1_General_CI_AS,
Permission = permission_name collate Latin1_General_CI_AS,
[script]=
'IF OBJECT_ID (' + '''' + '['+ sys.schemas.name + '].[' + so.name + ']' + '''' + ') IS NOT NULL ' + CHAR(10) + state_desc +
' ' + permission_name + ' on ['+ sys.schemas.name + '].[' + so.name + '] to [' + dp.name + ']' collate Latin1_General_CI_AS + CHAR(10) +
'ELSE ' + CHAR(10) +
'print ' + '''['+ sys.schemas.name + '].[' + so.name + '] - does not exist'''
+ CHAR(13)
from sys.database_permissions a
INNER JOIN sys.objects so on a.major_id = so.object_id
INNER JOIN sys.schemas on so.schema_id = sys.schemas.schema_id
INNER JOIN sys.database_principals dp on a.grantee_principal_id = dp.principal_id
WHERE dp.name NOT IN ( 'public', 'guest')
AND a.class = 1
I want to use the word collate
as few times as possible and still have a script that runs for multi-databases, multi-collations server.
How can I achieve that?
What is the rule for applying collate
?
sql-server t-sql permissions scripting collation
Aside: there'sCOLLATE DATABASE_DEFAULT
to, well, use the default of the current database, which can save on some inappropriate hard-coding. (It probably wouldn't do any good in this particular case, but then, I don't seeCOLLATE Latin1_General_CI_AS
doing that either.)
â Jeroen Mostert
2 hours ago
add a comment |Â
up vote
3
down vote
favorite
up vote
3
down vote
favorite
I am putting a script together, that gives me the permissions on database objects.
SELECT permission_order=710
,permission_type = 'Object Level Permissions'
,db = db_name(),
login_=null,
role_=dp.name collate Latin1_General_CI_AS,
Obj = sys.schemas.name + '.' + so.name collate Latin1_General_CI_AS,
Permission = permission_name collate Latin1_General_CI_AS,
[script]=
'IF OBJECT_ID (' + '''' + '['+ sys.schemas.name + '].[' + so.name + ']' + '''' + ') IS NOT NULL ' + CHAR(10) + state_desc +
' ' + permission_name + ' on ['+ sys.schemas.name + '].[' + so.name + '] to [' + dp.name + ']' collate Latin1_General_CI_AS + CHAR(10) +
'ELSE ' + CHAR(10) +
'print ' + '''['+ sys.schemas.name + '].[' + so.name + '] - does not exist'''
+ CHAR(13)
from sys.database_permissions a
INNER JOIN sys.objects so on a.major_id = so.object_id
INNER JOIN sys.schemas on so.schema_id = sys.schemas.schema_id
INNER JOIN sys.database_principals dp on a.grantee_principal_id = dp.principal_id
WHERE dp.name NOT IN ( 'public', 'guest')
AND a.class = 1
I want to use the word collate
as few times as possible and still have a script that runs for multi-databases, multi-collations server.
How can I achieve that?
What is the rule for applying collate
?
sql-server t-sql permissions scripting collation
I am putting a script together, that gives me the permissions on database objects.
SELECT permission_order=710
,permission_type = 'Object Level Permissions'
,db = db_name(),
login_=null,
role_=dp.name collate Latin1_General_CI_AS,
Obj = sys.schemas.name + '.' + so.name collate Latin1_General_CI_AS,
Permission = permission_name collate Latin1_General_CI_AS,
[script]=
'IF OBJECT_ID (' + '''' + '['+ sys.schemas.name + '].[' + so.name + ']' + '''' + ') IS NOT NULL ' + CHAR(10) + state_desc +
' ' + permission_name + ' on ['+ sys.schemas.name + '].[' + so.name + '] to [' + dp.name + ']' collate Latin1_General_CI_AS + CHAR(10) +
'ELSE ' + CHAR(10) +
'print ' + '''['+ sys.schemas.name + '].[' + so.name + '] - does not exist'''
+ CHAR(13)
from sys.database_permissions a
INNER JOIN sys.objects so on a.major_id = so.object_id
INNER JOIN sys.schemas on so.schema_id = sys.schemas.schema_id
INNER JOIN sys.database_principals dp on a.grantee_principal_id = dp.principal_id
WHERE dp.name NOT IN ( 'public', 'guest')
AND a.class = 1
I want to use the word collate
as few times as possible and still have a script that runs for multi-databases, multi-collations server.
How can I achieve that?
What is the rule for applying collate
?
sql-server t-sql permissions scripting collation
sql-server t-sql permissions scripting collation
edited 13 mins ago
Solomon Rutzky
46k476162
46k476162
asked 3 hours ago
marcello miorelli
5,2081659123
5,2081659123
Aside: there'sCOLLATE DATABASE_DEFAULT
to, well, use the default of the current database, which can save on some inappropriate hard-coding. (It probably wouldn't do any good in this particular case, but then, I don't seeCOLLATE Latin1_General_CI_AS
doing that either.)
â Jeroen Mostert
2 hours ago
add a comment |Â
Aside: there'sCOLLATE DATABASE_DEFAULT
to, well, use the default of the current database, which can save on some inappropriate hard-coding. (It probably wouldn't do any good in this particular case, but then, I don't seeCOLLATE Latin1_General_CI_AS
doing that either.)
â Jeroen Mostert
2 hours ago
Aside: there's
COLLATE DATABASE_DEFAULT
to, well, use the default of the current database, which can save on some inappropriate hard-coding. (It probably wouldn't do any good in this particular case, but then, I don't see COLLATE Latin1_General_CI_AS
doing that either.)â Jeroen Mostert
2 hours ago
Aside: there's
COLLATE DATABASE_DEFAULT
to, well, use the default of the current database, which can save on some inappropriate hard-coding. (It probably wouldn't do any good in this particular case, but then, I don't see COLLATE Latin1_General_CI_AS
doing that either.)â Jeroen Mostert
2 hours ago
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
6
down vote
accepted
COLLATE
operates per predicate. So, it needs to be applied to string columns that could possibly have differing Collations. Non-string types (including XML) do not use COLLATE
, and columns that are guaranteed to have the same Collation do not need it.
COLLATE
is mainly used to control how the string values are being compared or sorted. Hence it is most commonly used in JOIN
, WHERE
, and HAVING
predicates as well as GROUP BY
and ORDER BY
clauses (in which case it can be used per column / expression).
It generally wouldn't be used in a SELECT
list unless there was a reason to change the Collation of the selected column / expression, which would mainly apply to VARCHAR
data as you can change the Code Page, but I really don't see much application for this usage. The most likely reason to do this would be if the client requesting the data needs a different Code Page, but I can't think of a reason that this would ever be needed.
However, one reason to use it in the SELECT
list (and possibly other places) is when doing string concatenation involving two more columns that can potentially have mixed Collations. You shouldn't need to worry about single columns and string literals as the literals will be coerced into the Collation of the column.
So, looking at your query:
- You don't need
COLLATE
in these places:role_=dp.name collate Latin1_General_CI_AS,
because you are just selecting a single column, nothing is being mixed.Obj = sys.schemas.name + '.' + so.name collate Latin1_General_CI_AS,
because both columns are database-level meta-data from the same database which is guaranteed to be the same Collation, plus a string literal that is already the database's default Collation (same as the two column's it is being concatenated with), but even if it wasn't already the same, it would be coerced into the Collation of the two columns. Only improvement here would be to prefix the literal with an upper-caseN
since the expression isNVARCHAR
due to the schema names and object names being of typesysname
which is an alias forNVARCHAR(128)
.Permission = permission_name collate Latin1_General_CI_AS,
because you are just selecting a single column, nothing is being mixed.
- You do need
COLLATE
in the string concatenation because you are mixing database-level meta-data (which uses the database's default Collation) and system-level meta-data (i.e.state_desc
andpermission_name
) which comes from the hiddenmssqlsystemresource
database and usually has a Collation ofLatin1_General_CI_AS_KS_WS
. It should be fine to haveCOLLATE
specified only once per expression since it should have the highest precedence and force both literals and columns into the stated Collation.
Finally, regarding which Collation to specify: DATABASE_DEFAULT
, CATALOG_DEFAULT
, or one of your choosing (such as you are doing here): given that you are working on NVARCHAR
data (no chance of changing the Code Page / character set) and not using COLLATE
for sorting or comparison (no chance of changing how the query works between different databases), it really doesn't matter; it's all the same in this particular scenario. You would use DATABASE_DEFAULT
or CATALOG_DEFAULT
if you needed the query (or that particular predicate or ORDER
/ GROUP
item) to be sensitive to local database and change behavior depending on where the query is being executed.
Other notes:
- I would suggested enclosing the result set column names in square brackets (i.e.
[permission_order]
instead ofpermission_order
,[role_]
instead ofrole_
, etc). - You have
CHAR(13)
at the end which should beCHAR(10)
like the rest of those newlines in that concatenation. - Even better would be to use
NCHAR(10)
and prefix each string literal piece of the concatenation with an upper-caseN
since you are concatenatingsysname
/NVARCHAR
columns which will force the entire string intoNVARCHAR
, hence thoseCHAR()
references and string literals are being implicitly converted anyway. - Also good would be to wrap the schema / object names in
QUOTENAME()
(and remove your explicit delimiters â[
and]
â in the string literals) asQUOTENAME
has the benefit of escaping embedded delimiters.
When you say "per predicate" do you not mean "per expression"?
â usr
25 mins ago
1
@usr Hi there. I believe "predicate". But to clarify in case I'm using terminology incorrectly, consider this simple example:SELECT 1 FROM sys.all_objects WHERE [name] = N'objects' COLLATE Latin1_General_100_BIN2
. The predicate is both sides of the "x = y", and an expression is just one side, both "x" and "y", each being a separate expression, correct? If yes to both, then yes, per predicate since both sides need to be of the same Collation, soCOLLATE
will force both sides of the predicate, not just the expression it is directly attached to. Else you would get a Collation mismatch error.
â Solomon Rutzky
17 mins ago
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
6
down vote
accepted
COLLATE
operates per predicate. So, it needs to be applied to string columns that could possibly have differing Collations. Non-string types (including XML) do not use COLLATE
, and columns that are guaranteed to have the same Collation do not need it.
COLLATE
is mainly used to control how the string values are being compared or sorted. Hence it is most commonly used in JOIN
, WHERE
, and HAVING
predicates as well as GROUP BY
and ORDER BY
clauses (in which case it can be used per column / expression).
It generally wouldn't be used in a SELECT
list unless there was a reason to change the Collation of the selected column / expression, which would mainly apply to VARCHAR
data as you can change the Code Page, but I really don't see much application for this usage. The most likely reason to do this would be if the client requesting the data needs a different Code Page, but I can't think of a reason that this would ever be needed.
However, one reason to use it in the SELECT
list (and possibly other places) is when doing string concatenation involving two more columns that can potentially have mixed Collations. You shouldn't need to worry about single columns and string literals as the literals will be coerced into the Collation of the column.
So, looking at your query:
- You don't need
COLLATE
in these places:role_=dp.name collate Latin1_General_CI_AS,
because you are just selecting a single column, nothing is being mixed.Obj = sys.schemas.name + '.' + so.name collate Latin1_General_CI_AS,
because both columns are database-level meta-data from the same database which is guaranteed to be the same Collation, plus a string literal that is already the database's default Collation (same as the two column's it is being concatenated with), but even if it wasn't already the same, it would be coerced into the Collation of the two columns. Only improvement here would be to prefix the literal with an upper-caseN
since the expression isNVARCHAR
due to the schema names and object names being of typesysname
which is an alias forNVARCHAR(128)
.Permission = permission_name collate Latin1_General_CI_AS,
because you are just selecting a single column, nothing is being mixed.
- You do need
COLLATE
in the string concatenation because you are mixing database-level meta-data (which uses the database's default Collation) and system-level meta-data (i.e.state_desc
andpermission_name
) which comes from the hiddenmssqlsystemresource
database and usually has a Collation ofLatin1_General_CI_AS_KS_WS
. It should be fine to haveCOLLATE
specified only once per expression since it should have the highest precedence and force both literals and columns into the stated Collation.
Finally, regarding which Collation to specify: DATABASE_DEFAULT
, CATALOG_DEFAULT
, or one of your choosing (such as you are doing here): given that you are working on NVARCHAR
data (no chance of changing the Code Page / character set) and not using COLLATE
for sorting or comparison (no chance of changing how the query works between different databases), it really doesn't matter; it's all the same in this particular scenario. You would use DATABASE_DEFAULT
or CATALOG_DEFAULT
if you needed the query (or that particular predicate or ORDER
/ GROUP
item) to be sensitive to local database and change behavior depending on where the query is being executed.
Other notes:
- I would suggested enclosing the result set column names in square brackets (i.e.
[permission_order]
instead ofpermission_order
,[role_]
instead ofrole_
, etc). - You have
CHAR(13)
at the end which should beCHAR(10)
like the rest of those newlines in that concatenation. - Even better would be to use
NCHAR(10)
and prefix each string literal piece of the concatenation with an upper-caseN
since you are concatenatingsysname
/NVARCHAR
columns which will force the entire string intoNVARCHAR
, hence thoseCHAR()
references and string literals are being implicitly converted anyway. - Also good would be to wrap the schema / object names in
QUOTENAME()
(and remove your explicit delimiters â[
and]
â in the string literals) asQUOTENAME
has the benefit of escaping embedded delimiters.
When you say "per predicate" do you not mean "per expression"?
â usr
25 mins ago
1
@usr Hi there. I believe "predicate". But to clarify in case I'm using terminology incorrectly, consider this simple example:SELECT 1 FROM sys.all_objects WHERE [name] = N'objects' COLLATE Latin1_General_100_BIN2
. The predicate is both sides of the "x = y", and an expression is just one side, both "x" and "y", each being a separate expression, correct? If yes to both, then yes, per predicate since both sides need to be of the same Collation, soCOLLATE
will force both sides of the predicate, not just the expression it is directly attached to. Else you would get a Collation mismatch error.
â Solomon Rutzky
17 mins ago
add a comment |Â
up vote
6
down vote
accepted
COLLATE
operates per predicate. So, it needs to be applied to string columns that could possibly have differing Collations. Non-string types (including XML) do not use COLLATE
, and columns that are guaranteed to have the same Collation do not need it.
COLLATE
is mainly used to control how the string values are being compared or sorted. Hence it is most commonly used in JOIN
, WHERE
, and HAVING
predicates as well as GROUP BY
and ORDER BY
clauses (in which case it can be used per column / expression).
It generally wouldn't be used in a SELECT
list unless there was a reason to change the Collation of the selected column / expression, which would mainly apply to VARCHAR
data as you can change the Code Page, but I really don't see much application for this usage. The most likely reason to do this would be if the client requesting the data needs a different Code Page, but I can't think of a reason that this would ever be needed.
However, one reason to use it in the SELECT
list (and possibly other places) is when doing string concatenation involving two more columns that can potentially have mixed Collations. You shouldn't need to worry about single columns and string literals as the literals will be coerced into the Collation of the column.
So, looking at your query:
- You don't need
COLLATE
in these places:role_=dp.name collate Latin1_General_CI_AS,
because you are just selecting a single column, nothing is being mixed.Obj = sys.schemas.name + '.' + so.name collate Latin1_General_CI_AS,
because both columns are database-level meta-data from the same database which is guaranteed to be the same Collation, plus a string literal that is already the database's default Collation (same as the two column's it is being concatenated with), but even if it wasn't already the same, it would be coerced into the Collation of the two columns. Only improvement here would be to prefix the literal with an upper-caseN
since the expression isNVARCHAR
due to the schema names and object names being of typesysname
which is an alias forNVARCHAR(128)
.Permission = permission_name collate Latin1_General_CI_AS,
because you are just selecting a single column, nothing is being mixed.
- You do need
COLLATE
in the string concatenation because you are mixing database-level meta-data (which uses the database's default Collation) and system-level meta-data (i.e.state_desc
andpermission_name
) which comes from the hiddenmssqlsystemresource
database and usually has a Collation ofLatin1_General_CI_AS_KS_WS
. It should be fine to haveCOLLATE
specified only once per expression since it should have the highest precedence and force both literals and columns into the stated Collation.
Finally, regarding which Collation to specify: DATABASE_DEFAULT
, CATALOG_DEFAULT
, or one of your choosing (such as you are doing here): given that you are working on NVARCHAR
data (no chance of changing the Code Page / character set) and not using COLLATE
for sorting or comparison (no chance of changing how the query works between different databases), it really doesn't matter; it's all the same in this particular scenario. You would use DATABASE_DEFAULT
or CATALOG_DEFAULT
if you needed the query (or that particular predicate or ORDER
/ GROUP
item) to be sensitive to local database and change behavior depending on where the query is being executed.
Other notes:
- I would suggested enclosing the result set column names in square brackets (i.e.
[permission_order]
instead ofpermission_order
,[role_]
instead ofrole_
, etc). - You have
CHAR(13)
at the end which should beCHAR(10)
like the rest of those newlines in that concatenation. - Even better would be to use
NCHAR(10)
and prefix each string literal piece of the concatenation with an upper-caseN
since you are concatenatingsysname
/NVARCHAR
columns which will force the entire string intoNVARCHAR
, hence thoseCHAR()
references and string literals are being implicitly converted anyway. - Also good would be to wrap the schema / object names in
QUOTENAME()
(and remove your explicit delimiters â[
and]
â in the string literals) asQUOTENAME
has the benefit of escaping embedded delimiters.
When you say "per predicate" do you not mean "per expression"?
â usr
25 mins ago
1
@usr Hi there. I believe "predicate". But to clarify in case I'm using terminology incorrectly, consider this simple example:SELECT 1 FROM sys.all_objects WHERE [name] = N'objects' COLLATE Latin1_General_100_BIN2
. The predicate is both sides of the "x = y", and an expression is just one side, both "x" and "y", each being a separate expression, correct? If yes to both, then yes, per predicate since both sides need to be of the same Collation, soCOLLATE
will force both sides of the predicate, not just the expression it is directly attached to. Else you would get a Collation mismatch error.
â Solomon Rutzky
17 mins ago
add a comment |Â
up vote
6
down vote
accepted
up vote
6
down vote
accepted
COLLATE
operates per predicate. So, it needs to be applied to string columns that could possibly have differing Collations. Non-string types (including XML) do not use COLLATE
, and columns that are guaranteed to have the same Collation do not need it.
COLLATE
is mainly used to control how the string values are being compared or sorted. Hence it is most commonly used in JOIN
, WHERE
, and HAVING
predicates as well as GROUP BY
and ORDER BY
clauses (in which case it can be used per column / expression).
It generally wouldn't be used in a SELECT
list unless there was a reason to change the Collation of the selected column / expression, which would mainly apply to VARCHAR
data as you can change the Code Page, but I really don't see much application for this usage. The most likely reason to do this would be if the client requesting the data needs a different Code Page, but I can't think of a reason that this would ever be needed.
However, one reason to use it in the SELECT
list (and possibly other places) is when doing string concatenation involving two more columns that can potentially have mixed Collations. You shouldn't need to worry about single columns and string literals as the literals will be coerced into the Collation of the column.
So, looking at your query:
- You don't need
COLLATE
in these places:role_=dp.name collate Latin1_General_CI_AS,
because you are just selecting a single column, nothing is being mixed.Obj = sys.schemas.name + '.' + so.name collate Latin1_General_CI_AS,
because both columns are database-level meta-data from the same database which is guaranteed to be the same Collation, plus a string literal that is already the database's default Collation (same as the two column's it is being concatenated with), but even if it wasn't already the same, it would be coerced into the Collation of the two columns. Only improvement here would be to prefix the literal with an upper-caseN
since the expression isNVARCHAR
due to the schema names and object names being of typesysname
which is an alias forNVARCHAR(128)
.Permission = permission_name collate Latin1_General_CI_AS,
because you are just selecting a single column, nothing is being mixed.
- You do need
COLLATE
in the string concatenation because you are mixing database-level meta-data (which uses the database's default Collation) and system-level meta-data (i.e.state_desc
andpermission_name
) which comes from the hiddenmssqlsystemresource
database and usually has a Collation ofLatin1_General_CI_AS_KS_WS
. It should be fine to haveCOLLATE
specified only once per expression since it should have the highest precedence and force both literals and columns into the stated Collation.
Finally, regarding which Collation to specify: DATABASE_DEFAULT
, CATALOG_DEFAULT
, or one of your choosing (such as you are doing here): given that you are working on NVARCHAR
data (no chance of changing the Code Page / character set) and not using COLLATE
for sorting or comparison (no chance of changing how the query works between different databases), it really doesn't matter; it's all the same in this particular scenario. You would use DATABASE_DEFAULT
or CATALOG_DEFAULT
if you needed the query (or that particular predicate or ORDER
/ GROUP
item) to be sensitive to local database and change behavior depending on where the query is being executed.
Other notes:
- I would suggested enclosing the result set column names in square brackets (i.e.
[permission_order]
instead ofpermission_order
,[role_]
instead ofrole_
, etc). - You have
CHAR(13)
at the end which should beCHAR(10)
like the rest of those newlines in that concatenation. - Even better would be to use
NCHAR(10)
and prefix each string literal piece of the concatenation with an upper-caseN
since you are concatenatingsysname
/NVARCHAR
columns which will force the entire string intoNVARCHAR
, hence thoseCHAR()
references and string literals are being implicitly converted anyway. - Also good would be to wrap the schema / object names in
QUOTENAME()
(and remove your explicit delimiters â[
and]
â in the string literals) asQUOTENAME
has the benefit of escaping embedded delimiters.
COLLATE
operates per predicate. So, it needs to be applied to string columns that could possibly have differing Collations. Non-string types (including XML) do not use COLLATE
, and columns that are guaranteed to have the same Collation do not need it.
COLLATE
is mainly used to control how the string values are being compared or sorted. Hence it is most commonly used in JOIN
, WHERE
, and HAVING
predicates as well as GROUP BY
and ORDER BY
clauses (in which case it can be used per column / expression).
It generally wouldn't be used in a SELECT
list unless there was a reason to change the Collation of the selected column / expression, which would mainly apply to VARCHAR
data as you can change the Code Page, but I really don't see much application for this usage. The most likely reason to do this would be if the client requesting the data needs a different Code Page, but I can't think of a reason that this would ever be needed.
However, one reason to use it in the SELECT
list (and possibly other places) is when doing string concatenation involving two more columns that can potentially have mixed Collations. You shouldn't need to worry about single columns and string literals as the literals will be coerced into the Collation of the column.
So, looking at your query:
- You don't need
COLLATE
in these places:role_=dp.name collate Latin1_General_CI_AS,
because you are just selecting a single column, nothing is being mixed.Obj = sys.schemas.name + '.' + so.name collate Latin1_General_CI_AS,
because both columns are database-level meta-data from the same database which is guaranteed to be the same Collation, plus a string literal that is already the database's default Collation (same as the two column's it is being concatenated with), but even if it wasn't already the same, it would be coerced into the Collation of the two columns. Only improvement here would be to prefix the literal with an upper-caseN
since the expression isNVARCHAR
due to the schema names and object names being of typesysname
which is an alias forNVARCHAR(128)
.Permission = permission_name collate Latin1_General_CI_AS,
because you are just selecting a single column, nothing is being mixed.
- You do need
COLLATE
in the string concatenation because you are mixing database-level meta-data (which uses the database's default Collation) and system-level meta-data (i.e.state_desc
andpermission_name
) which comes from the hiddenmssqlsystemresource
database and usually has a Collation ofLatin1_General_CI_AS_KS_WS
. It should be fine to haveCOLLATE
specified only once per expression since it should have the highest precedence and force both literals and columns into the stated Collation.
Finally, regarding which Collation to specify: DATABASE_DEFAULT
, CATALOG_DEFAULT
, or one of your choosing (such as you are doing here): given that you are working on NVARCHAR
data (no chance of changing the Code Page / character set) and not using COLLATE
for sorting or comparison (no chance of changing how the query works between different databases), it really doesn't matter; it's all the same in this particular scenario. You would use DATABASE_DEFAULT
or CATALOG_DEFAULT
if you needed the query (or that particular predicate or ORDER
/ GROUP
item) to be sensitive to local database and change behavior depending on where the query is being executed.
Other notes:
- I would suggested enclosing the result set column names in square brackets (i.e.
[permission_order]
instead ofpermission_order
,[role_]
instead ofrole_
, etc). - You have
CHAR(13)
at the end which should beCHAR(10)
like the rest of those newlines in that concatenation. - Even better would be to use
NCHAR(10)
and prefix each string literal piece of the concatenation with an upper-caseN
since you are concatenatingsysname
/NVARCHAR
columns which will force the entire string intoNVARCHAR
, hence thoseCHAR()
references and string literals are being implicitly converted anyway. - Also good would be to wrap the schema / object names in
QUOTENAME()
(and remove your explicit delimiters â[
and]
â in the string literals) asQUOTENAME
has the benefit of escaping embedded delimiters.
edited 2 hours ago
answered 3 hours ago
Solomon Rutzky
46k476162
46k476162
When you say "per predicate" do you not mean "per expression"?
â usr
25 mins ago
1
@usr Hi there. I believe "predicate". But to clarify in case I'm using terminology incorrectly, consider this simple example:SELECT 1 FROM sys.all_objects WHERE [name] = N'objects' COLLATE Latin1_General_100_BIN2
. The predicate is both sides of the "x = y", and an expression is just one side, both "x" and "y", each being a separate expression, correct? If yes to both, then yes, per predicate since both sides need to be of the same Collation, soCOLLATE
will force both sides of the predicate, not just the expression it is directly attached to. Else you would get a Collation mismatch error.
â Solomon Rutzky
17 mins ago
add a comment |Â
When you say "per predicate" do you not mean "per expression"?
â usr
25 mins ago
1
@usr Hi there. I believe "predicate". But to clarify in case I'm using terminology incorrectly, consider this simple example:SELECT 1 FROM sys.all_objects WHERE [name] = N'objects' COLLATE Latin1_General_100_BIN2
. The predicate is both sides of the "x = y", and an expression is just one side, both "x" and "y", each being a separate expression, correct? If yes to both, then yes, per predicate since both sides need to be of the same Collation, soCOLLATE
will force both sides of the predicate, not just the expression it is directly attached to. Else you would get a Collation mismatch error.
â Solomon Rutzky
17 mins ago
When you say "per predicate" do you not mean "per expression"?
â usr
25 mins ago
When you say "per predicate" do you not mean "per expression"?
â usr
25 mins ago
1
1
@usr Hi there. I believe "predicate". But to clarify in case I'm using terminology incorrectly, consider this simple example:
SELECT 1 FROM sys.all_objects WHERE [name] = N'objects' COLLATE Latin1_General_100_BIN2
. The predicate is both sides of the "x = y", and an expression is just one side, both "x" and "y", each being a separate expression, correct? If yes to both, then yes, per predicate since both sides need to be of the same Collation, so COLLATE
will force both sides of the predicate, not just the expression it is directly attached to. Else you would get a Collation mismatch error.â Solomon Rutzky
17 mins ago
@usr Hi there. I believe "predicate". But to clarify in case I'm using terminology incorrectly, consider this simple example:
SELECT 1 FROM sys.all_objects WHERE [name] = N'objects' COLLATE Latin1_General_100_BIN2
. The predicate is both sides of the "x = y", and an expression is just one side, both "x" and "y", each being a separate expression, correct? If yes to both, then yes, per predicate since both sides need to be of the same Collation, so COLLATE
will force both sides of the predicate, not just the expression it is directly attached to. Else you would get a Collation mismatch error.â Solomon Rutzky
17 mins ago
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f218824%2fwhat-are-the-rules-for-using-collate-in-a-query%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Aside: there's
COLLATE DATABASE_DEFAULT
to, well, use the default of the current database, which can save on some inappropriate hard-coding. (It probably wouldn't do any good in this particular case, but then, I don't seeCOLLATE Latin1_General_CI_AS
doing that either.)â Jeroen Mostert
2 hours ago