在查询中使用 COLLATE 的规则是什么?

Mar*_*lli 5 sql-server collation permissions scripting t-sql

我正在将一个脚本放在一起,它为我提供了对数据库对象的权限。

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
Run Code Online (Sandbox Code Playgroud)

我想collate尽可能少地使用这个词,并且仍然有一个为多数据库、多排序服务器运行的脚本。

我怎样才能做到这一点?申请规则是collate什么?

在此处输入图片说明

Sol*_*zky 12

COLLATE根据上下文,按谓词按表达式操作。COLLATE主要用于控制字符串值的比较或排序方式。因此,它是最常用的JOINWHEREHAVING谓词,以及GROUP BYORDER BY条款(在这种情况下它可以每列/表达式中使用)。它需要应用于可能具有不同排序规则的字符串列。非字符串类型(包括 XML)不使用COLLATE,并且保证具有相同排序规则的列不需要它。对于JOINWHEREHAVING谓词,只需要要在运营商的一侧指定既然对方会被强制到指定的排序规则。

通常不会在SELECT列表中使用,除非有理由更改所选列/表达式的排序规则,这主要适用于VARCHAR数据,因为您可以更改代码页,但我真的没有看到太多应用这种用法。这样做的最可能原因是请求数据的客户端需要不同的代码页,但我想不出需要这样做的原因。

但是,在SELECT列表(可能还有其他地方)中使用它的一个原因是在进行涉及两个或多个可能具有混合排序规则的列的字符串连接时。这种情况适用于VARCHARNVARCHAR数据。您不必担心单列和字符串文字,因为文字将被强制转换为列的排序规则。

您可能需要COLLATESELECT列表中使用的另一个原因是使用UNION,INTERSECT或 时EXCEPT,并且至少两个查询之间相同位置的列/表达式之间的排序规则不相同。

所以,看看你的查询:

  1. 你不需要COLLATE在这些地方:
    • role_=dp.name collate Latin1_General_CI_AS,
      因为您只是选择一列,所以没有混合。
    • Obj = sys.schemas.name + '.' + so.name collate Latin1_General_CI_AS,
      因为这两列都是来自同一个数据库的数据库级元数据,保证是相同的排序规则,加上一个已经是数据库默认排序规则的字符串文字(与它连接的两列相同),但即使它已经不一样了,它会被强制到两列的 Collat​​ion 中。这里唯一的改进是在文字前加上大写,N因为表达式是NVARCHAR由于模式名称和对象名称的类型sysnameNVARCHAR(128).
    • Permission = permission_name collate Latin1_General_CI_AS,
      因为您只是选择一列,所以没有混合。
  2. 确实需要COLLATE字符串连接,因为您正在混合数据库级元数据(使用数据库的默认排序规则)和来自隐藏数据库的系统级元数据(即state_descpermission_name),mssqlsystemresource并且通常具有Latin1_General_CI_AS_KS_WS. 它应该是罚款已COLLATE每个表达式一次指定的,因为它应该具有最高的优先级和两个文字和列强行进入规定整理。

最后,关于指定哪个排序规则:DATABASE_DEFAULTCATALOG_DEFAULT,或您选择的一个(例如您在此处执行的操作):假设您正在处理NVARCHAR数据(没有机会更改代码页/字符集)并且不COLLATE用于排序或比较(没有机会改变查询在不同数据库之间的工作方式),这真的无关紧要;在这个特定的场景中都是一样的。如果您需要查询(或该特定谓词或/项)对本地数据库敏感并根据执行查询的位置更改行为,您将使用DATABASE_DEFAULT或。CATALOG_DEFAULTORDERGROUP

其他注意事项:

  1. 我建议将结果集列名括在方括号中(即[permission_order]代替permission_order[role_]代替role_等)。
  2. 你必须CHAR(13)在这应该是最终CHAR(10)像在串联这些新行的其余部分。
  3. 甚至更好的是使用NCHAR(10) 前缀的每个字符串文字片串接的与大写N因为你是串联sysname/NVARCHAR列这将迫使整个串入NVARCHAR,因此,那些CHAR()引用和字符串被隐式转换无论如何。
  4. 将模式/对象名称包装在QUOTENAME()(并删除您的显式分隔符 -[]- 在字符串文字中)也是好的,因为QUOTENAME有转义嵌入分隔符的好处。

  • @usr 你好。我相信“谓词”。但是为了澄清我使用错误的术语,请考虑这个简单的例子:`SELECT 1 FROM sys.all_objects WHERE [name] = N'objects' COLLATE Latin1_General_100_BIN2`。谓词是“x = y”的两侧,表达式只是一侧,“x”和“y”都是一个单独的表达式,对吗?如果两者都是肯定的,那么每个谓词都是肯定的,因为双方都需要具有相同的排序规则,因此`COLLATE` 将强制谓词的两边,而不仅仅是它直接附加到的表达式。否则你会得到一个排序规则不匹配错误。 (3认同)