SQL Server:如何即时更改我选择的所有列的排序规则

时间:2018-12-11 11:32:29

标签: sql sql-server collation

我需要从数据库中的一个表中查询某些内容,但是某些列的排序规则与我需要的排序规则不同。

我发现了如何动态更改一列的排序规则:

SELECT 
  u.name  COLLATE Latin1_General_CI_AS AS 'User'(...)

但是问题是有超过150列需要即时更改COLLATION(不要问我为什么,因为即使我认为这是最好的选择,我们也不能更改整个表的排序规则)。

所以主要问题是: Is there a way to set the COLLATION to all columns of my query?

2 个答案:

答案 0 :(得分:1)

我不确定是否可以通过这种方式对输出的所有列强制使用默认排序规则。

但是,如果您的服务器允许您使用动态SQL,则可以构建动态查询并执行它以获取所需的结果。

此工作的示例如下所示。请将YOUR_TABLE_NAME更改为您的实际表名,以使其起作用:

DECLARE @col    VARCHAR(200)
DECLARE @sql    VARCHAR(MAX)
DECLARE @table  VARCHAR(200)
SET @table = 'YOUR_TABLE_NAME';

-- Use a cursor to read all varchar columns from table
DECLARE curColumns CURSOR FORWARD_ONLY STATIC READ_ONLY
  FOR
    SELECT  c.name
      FROM  sys.columns c
        INNER JOIN sys.types t ON c.user_type_id = t.user_type_id
      WHERE c.object_id = OBJECT_ID(@table) AND
            t.name = 'varchar'

SET @sql = 'SELECT'

-- Go through column cursor
OPEN curColumns
FETCH NEXT FROM curColumns INTO @col
WHILE (@@FETCH_STATUS = 0)
BEGIN
    -- Add column to SQL with collation
    SET @sql = @sql + ' ' + @col + ' COLLATE Latin1_General_CI_AS,'

    FETCH NEXT FROM curColumns INTO @col
END
CLOSE curColumns
DEALLOCATE curColumns

-- Add the from clause
SET @sql = SUBSTRING(@sql, 0, LEN(@sql) - 1) + ' FROM ' + @table

-- Uncomment this line to see the generated SQL
--PRINT @sql
EXEC (@sql)

请注意,上面的示例有几个限制:

  1. 您的服务器必须允许运行动态SQL。
  2. 在此示例中,仅输出VARCHAR列(您可以通过更改光标查询以包括更多类型来更改此列)。
  3. 无法使用此方法指定列别名。

答案 1 :(得分:1)

无法即时更改所有文本列的排序规则-但是可以通过操纵查询来获得相同的结果。 Martin's answer显示了一种方法,这是使用查询元数据的另一种方法。好处是,它没有游标,并且如果排序规则已经是我们想要的,它就避免了不必要地引入“新”列。它要求至少SQL Server 2012具有sys.dm_exec_describe_first_result_set,SQL Server 2017具有STRING_AGG(在以前的版本中,可以使用经典的字符串串联技巧,例如FOR XML PATH技巧)

DECLARE @query NVARCHAR(MAX) = N'SELECT * FROM MyTable';
DECLARE @tweakedQuery NVARCHAR(MAX);
DECLARE @tweakedCollation SYSNAME = N'Latin1_General_CI_AS';

SELECT @tweakedQuery = CONCAT(
    'SELECT ', 
    STRING_AGG(
        CONCAT(
            CONVERT(NVARCHAR(MAX), QUOTENAME([name])), 
            CASE 
                WHEN collation_name IS NOT NULL AND collation_name <> @tweakedCollation
                THEN ' COLLATE ' + @tweakedCollation + ' AS ' + QUOTENAME([name]) 
            END
        ), 
        ', ' + CHAR(13) + CHAR(10)
    ),
    ' FROM (' + CHAR(13) + CHAR(10),
    @query,
    CHAR(13) + CHAR(10) + ') _'
)
FROM sys.dm_exec_describe_first_result_set(@query, NULL, NULL);
PRINT @tweakedQuery;

如果自定义别名是系统生成的(基于表名或列名),则合并起来很简单。否则,您将不得不手动修补问题。

对于一次性查询(不一定需要即时执行),使自己熟悉自己喜欢的编辑器中的正则表达式仍然是一个更好的主意。如果您最喜欢的编辑器没有正则表达式,请获取一个。