SQL Server:资源数据库的整理

Ruu*_*ten 5 sql-server collation full-text-search sql-server-2012

我正在尝试使用停用词,以便全文索引器跳过某些单词。我可以在表sys.fulltext_stopwords 中添加这些停用词。

尝试在 SQL Server 2012 中获取列表时遇到错误。我正在执行以下(简化的)查询:

SELECT sys.fulltext_stopwords.stopword 
FROM sys.fulltext_stopwords     

UNION 

SELECT sys.fulltext_system_stopwords.stopword 
FROM sys.fulltext_system_stopwords;
Run Code Online (Sandbox Code Playgroud)

我得到的错误信息是:

“无法解决 UNION 操作中“Latin1_General_CI_AS”和“Latin1_General_BIN”之间的排序规则冲突。”

我的查询中第一个 SELECT 语句的数据库规则Latin1_General_CI_AS数据库也是如此。

在什么地方Latin1_General_BIN 从何而来?看起来 sys.fulltext_system_stopwords 表有不同的排序规则,但为什么呢?

编辑

我可以通过在查询中使用COLLATE来“解决”我的错误,如下所示:

SELECT  sys.fulltext_stopwords.stopword COLLATE DATABASE_DEFAULT
FROM sys.fulltext_stopwords 

UNION 

SELECT sys.fulltext_system_stopwords.stopword COLLATE DATABASE_DEFAULT
FROM sys.fulltext_system_stopwords 
Run Code Online (Sandbox Code Playgroud)

我看到系统停用词存储在资源数据库中,可以解释整理的差异。下一个问题是:为什么资源数据库中的排序规则与默认排序规则不同?

Sol*_*zky 6

我的查询中第一个 SELECT 语句的数据库排序规则是Latin1_General_CI_AS

嗯,不完全是。这个说法有几个问题:

  1. 当使用字符串文字、变量和来自 UDF 的返回值时,数据库的默认排序规则仅在查询中重要。并且,默认排序规则仅在没有使用列或COLLATE关键字时才重要。

  2. SELECT 语句/查询,作为一个整体,不使用排序规则。每个字符串字段都分配了排序规则,并且查询中的每个字段都可以不同。

  3. 第一个/顶部查询中的列stopword没有使用Latin1_General_CI_AS排序规则(稍后会详细介绍)。

我看到系统停用词存储在资源数据库中,可以解释整理的差异。

来自不同数据库的列(或表达式)不一定解释排序规则的差异。如上所述,排序规则是针对查询的每个字段设置的,无论该字段来自表中的列还是表达式。排序规则通常从排序规则优先级自然派生:列排序规则覆盖文字和变量,COLLATE关键字覆盖两者。如果有冲突,那么你需要COLLATE关键字。

这里的主要点,但问题在于,如果stopword在列sys.fulltext_system_stopwords来自一个列在一个表中在资源数据库(即mssqlsystemresource),或者如果它来自一种表达在一个视图中,其经由具有其归类组资源数据库COLLATE关键字,那么资源数据库的默认排序规则是无关紧要的。

我可以通过COLLATE在查询中使用来“解决”我的错误

是的,COLLATE关键字是要走的路。但是,要解决此冲突,您只需COLLATE在一个查询中指定关键字,尽管哪个查询无关紧要。

例如,如果我运行没有COLLATE关键字的查询,我会得到:

SELECT ftsw.stopword
FROM sys.fulltext_stopwords ftsw

UNION

SELECT ftssw.stopword
FROM sys.fulltext_system_stopwords ftssw;
Run Code Online (Sandbox Code Playgroud)

消息 468,级别 16,状态 9,第 4 行
无法解决 UNION 操作中“SQL_Latin1_General_CP1_CI_AS”和“Latin1_General_BIN”之间的排序规则冲突。

因此,假设冲突在第二个(即底部)SELECT 语句中,我可以通过应用当前数据库的默认排序规则来修复它:

SELECT ftsw.stopword
FROM sys.fulltext_stopwords ftsw
UNION
SELECT ftssw.stopword COLLATE SQL_Latin1_General_CP1_CI_AS
FROM sys.fulltext_system_stopwords ftssw;
Run Code Online (Sandbox Code Playgroud)

这有效。但是,如果我们尝试放置COLLATE第一个 / 顶部 SELECT 会怎样:

SELECT ftsw.stopword COLLATE SQL_Latin1_General_CP1_CI_AS
FROM sys.fulltext_stopwords ftsw
UNION
SELECT ftssw.stopword
FROM sys.fulltext_system_stopwords ftssw;
Run Code Online (Sandbox Code Playgroud)

这也有效。事实上,以下两种方法也都有效:

SELECT ftsw.stopword COLLATE Hebrew_100_CI_AS
FROM sys.fulltext_stopwords ftsw
UNION
SELECT ftssw.stopword
FROM sys.fulltext_system_stopwords ftssw;

-- and:

SELECT ftsw.stopword
FROM sys.fulltext_stopwords ftsw
UNION
SELECT ftssw.stopword COLLATE Hebrew_100_CI_AS
FROM sys.fulltext_system_stopwords ftssw;
Run Code Online (Sandbox Code Playgroud)

此外,在这种特殊情况下,我不会使用DATABASE_DEFAULT这里等同于Latin1_General_CI_AS的选项,而是使用Latin1_General_BIN(或者更好的是:Latin1_General_100_BIN2,它更新更好)因为它将确保可以将不同的字符串规范化为相同的字符串通过UNION(没有ALL)的“不同”行为和Latin1_General_CI_AS排序规则的大小写不敏感显示为不同的行。

Latin1_General_BIN 归类从何而来?看起来 sys.fulltext_system_stopwords 表有不同的排序规则,但为什么呢?

该整理来自一个不太可能的来源。让我们看看查询中的系统目录视图:

EXEC sys.sp_help N'sys.fulltext_stopwords';
Run Code Online (Sandbox Code Playgroud)

结果表明这是一个视图(如预期的那样)并且该stopword列的排序规则为Latin1_General_BIN(非预期)。但是等等,如果Latin1_General_BIN Collat​​ion 来自sys.fulltext_stopwords,那么sys.fulltext_system_stopwords另一个 Collat​​ion 又是从哪里来的呢?我们看看吧:

EXEC sys.sp_help N'sys.fulltext_system_stopwords';
Run Code Online (Sandbox Code Playgroud)

结果表明这是一个视图(如预期)并且该stopword列具有SQL_Latin1_General_CP1_CI_AS的排序规则(非预期)。

我们现在可以更深入地了解每个系统目录视图的定义:

EXEC sys.sp_helptext N'sys.fulltext_stopwords';
Run Code Online (Sandbox Code Playgroud)

返回(简化):

SELECT 
    fts.stopword,
FROM sys.sysftstops fts
Run Code Online (Sandbox Code Playgroud)

进而:

EXEC sys.sp_help N'sys.sysftstops';
Run Code Online (Sandbox Code Playgroud)

结果表明这是一个系统表,并且该stopword列确实具有Latin1_General_BIN的排序规则

接下来我们可以转到另一个系统目录视图:

EXEC sys.sp_helptext N'sys.fulltext_system_stopwords';
Run Code Online (Sandbox Code Playgroud)

返回(简化):

SELECT convert(nvarchar(64), stopword) as stopword, language_id
FROM OpenRowset(TABLE FTSYSSTPWD) 
Run Code Online (Sandbox Code Playgroud)

并且FTSYSSTPWD来自资源数据库,因此此时我们无能为力。

尽管如此,我们还可以做最后一件事来清楚来自资源数据库的数据的整理 - sys.fulltext_system_stopwords.stopword

CREATE DATABASE [FullTextCollationTest] COLLATE SQL_EBCDIC277_CP1_CS_AS;
GO
USE [FullTextCollationTest];

EXEC sys.sp_help N'sys.fulltext_stopwords';
-- Collation for [stopword] column: Latin1_General_BIN      (same as before)

EXEC sys.sp_help N'sys.fulltext_system_stopwords';
-- Collation for [stopword] column: SQL_EBCDIC277_CP1_CS_AS (same as DB's default Collation)

GO
USE [master];
DROP DATABASE [FullTextCollationTest];
Run Code Online (Sandbox Code Playgroud)