使用 CONTAINSTABLE 在 SQL Server 全文搜索查询中转义 & 号

Posted

技术标签:

【中文标题】使用 CONTAINSTABLE 在 SQL Server 全文搜索查询中转义 & 号【英文标题】:Escaping an ampersand in SQL Server Full-Text Search query using CONTAINSTABLE 【发布时间】:2018-08-16 16:30:38 【问题描述】:

我有一个非常特殊的案例。我的 ASP.NET 页面调用我们的一个存储过程,它在我们的数据库上执行全文搜索查询。一些经常搜索的字符串包含一个 & 符号,因为我们的一些产品品牌(也包括知名品牌)的名称中有 &

事实证明,在某种情况下,我没有得到任何结果除非我逃脱了与号\&),而在另一种情况下,我没有得到任何结果只有我逃脱了和号

我不知道这是否相关,但是(没有给出品牌名称)一个以&b 结尾,另一个以&c 结尾。

这些字符串(&b&c)有没有可能有它们自己的特殊含义?通过转义它们,我实际上是在将一个特殊的字符串传递给 T-SQL?

编辑

附加信息:经过进一步测试,我证明错误出在存储过程本身。用&\& 调用它会产生不同的结果。

我将尝试发布存储过程的选定部分。我不会全部发布,因为大部分内容并不相关。

vParamBuca 参数是引起问题的参数。值可以是 'word&letter'word\&letter

SET @ricercaA = '''FORMSOF(INFLECTIONAL,"' +
    REPLACE(LTRIM(RTRIM(@vParamBuca)),' ', '") AND FORMSOF(INFLECTIONAL,"') + '")'''

然后使用变量@ricercaA 创建查询字符串:

[...]
FROM Products AS FT_TBL
LEFT OUTER JOIN CONTAINSTABLE (Products, Sign1, '+ @ricercaA + ') AS ColSign1_0 ON FT_TBL.ID = ColSign1_0.[KEY]
LEFT OUTER JOIN CONTAINSTABLE (Products, ManufacturerAdditionalText, '+ @ricercaA + ') AS ColManufacturerAdditionalText_0 ON FT_TBL.ID = ColManufacturerAdditionalText_0.[KEY]
LEFT OUTER JOIN CONTAINSTABLE (Products, ManufacturerForSearch, '+ @ricercaA + ') AS ColManufacturer_0 ON FT_TBL.ID = ColManufacturer_0.[KEY]
LEFT OUTER JOIN CONTAINSTABLE (Products, TuttaLaRiga, '+ @ricercaA + ') AS ColTuttaLaRiga_0 ON FT_TBL.ID = ColTuttaLaRiga_0.[KEY]
[...]

编辑 2

非常感谢@srutzky 为我指明了正确的方向!同时,我还发现了一个数据不一致的地方,其中一个名称带有&的品牌被修改为没有&,而另一个没有被修改(归根结底,我现在的问题是由通过那个:过去某人所做的部分修复)。

无论如何,回到正轨。现在我明白CONTAINSTABLE 函数中的& 字符被视为逻辑与(非按位)。

我仍然需要一个解决方案。 This answer 给出了一个对我不起作用的解决方案(条件和我的不一样)。我如何执行CONTAINSTABLE 搜索带有与号的字符串?最好不必将 & 符号转换为另一个安全字符?

【问题讨论】:

不确定它是否与您的问题有关,但是 & 是 T-SQL 中的按位和运算符。 ...和您的 .NET 代码。如果您将字符串作为强类型参数传递,则&符号不会在任何地方造成任何问题。 转义与否,& 曾经是一个特殊字符,您看到的变化可能与它被“转义”无关,而是与 SQL 之后看到/搜索的其他内容有关服务器接受& 的含义。谷歌一下。 当您说“对我们的数据库执行全文搜索”时,您的意思是您使用的是实际的全文搜索功能,还是LIKE '%' + @variable + '%' 运算符? ` isn't a T-SQL escape, so if you aren't using Full Text Search (where &` 也应该在使用 CONTAINS 函数时作为逻辑 AND 工作),那么您的应用程序代码可能正在转换 &,而不是使用 ``. 谢谢大家,我已经发布了T-SQL过程的相关部分。恐怕它与按位有关,虽然:( 【参考方案1】:

您看到的奇怪行为很可能是由于 CONTAINS 和 CONTAINSTABLE 函数(都与 SQL Server 的全文搜索功能一起使用)使用与符号 (&) 字符等效于 AND操作员。以下语句摘自CONTAINS 的文档:

可以使用和号 (&) 代替 AND 关键字来表示 AND 运算符。

没有提到它有任何转义字符(反斜杠通常不是 SQL 中的转义字符)。


更新

根据现在在问题的“编辑 2”中提供的信息以及其他研究,我会说您确实不需要需要逃避任何事情。似乎将搜索短语放在双引号中(由于使用FORMSOF)将& 视为文字或断字,具体取决于& 两侧的值。试试下面的例子:

DECLARE @Term NVARCHAR(100);

SET @Term = N'bob&sally'; -- 48 rows
--SET @Term = N'bob\&sally'; -- 48 rows
--SET @Term = N'r&f'; -- 4 rows
--SET @Term = N'r\&f'; -- 24 rows

SET @Term = N'FORMSOF(INFLECTIONAL,"' + @Term + '")';

SELECT * FROM sys.dm_fts_parser(@Term, 1033, 0, 0);
SELECT * FROM sys.dm_fts_parser(@Term, 1033, 0, 1);
SELECT * FROM sys.dm_fts_parser(@Term, 1033, NULL, 0);
SELECT * FROM sys.dm_fts_parser(@Term, 1033, NULL, 1);

bob&sallybob\&sally 的结果是相同的,并且在这两种情况下,bobsally 是分开的,不会组合成一个完全匹配的字符串。

但是,r&fr\&f 之间的结果并不相同。 r&f 仅被视为单个完全匹配的字符串,因为 rf 单独不是已知词。另一方面,添加反斜杠将两个字母分开,因为\ 是一个分词器,在这种情况下,您会得到rf

鉴于您在更新中声明您有“数据不一致,其中名称中带有“&”的品牌之一被修改为不带有“&”,而另一个则没有”,我怀疑当您 not 添加 \ 字符时,您会得到 not 修改的品牌(因为它与整个任期)。但是当你添加\字符时,你会得到修改为删除&的品牌,因为你现在正在搜索这两个部分,每一个都匹配该品牌名称的部分。

我会修复数据以保持一致:更新已删除 & 的品牌名称以将 & 符号放回原处。然后当人们使用 & 搜索时,没有额外的 @987654347 @添加,这将是完全匹配的。这种行为将包含在数据中,并且不需要您添加代码来规避 FTS 的自然操作,这似乎是一种容易出错的方法。

【讨论】:

非常感谢!我尝试了几个实验,现在我明白了 AND 运算符的作用。但是,我仍然需要一个解决方案:是否有可能以某种方式“逃脱”&符号?如果我不把它转换成一些安全的角色会更好。 您的回答很棒而且很有帮助!我还有一个问题:为什么'r\&f' 不返回由'r&f' 返回的r&f 记录? @Simone 不知道为什么会这样,这可能取决于sys.dm_fts_parser TVF 中参数 3 和 4 中反映的设置。我怀疑由于r\&f 会同时进入rf,它们都不匹配r&f,后者被认为是一个单一的实体。

以上是关于使用 CONTAINSTABLE 在 SQL Server 全文搜索查询中转义 & 号的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 2008 FTS CONTAINSTABLE 不返回超过五行

CONTAINSTABLE 和 CONTAINS,传递哪个字符串来匹配所有记录?

如何在实体框架中映射 CONTAINSTABLE 函数(代码优先)?

如何实现 NOT LIKE 作为 containstable(Full-Text Query) 的搜索条件?

SQL 2008 全文搜索词邻近度

7645 Null 或空全文谓词