使用 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&sally
和 bob\&sally
的结果是相同的,并且在这两种情况下,bob
和 sally
是分开的,不会组合成一个完全匹配的字符串。
但是,r&f
和 r\&f
之间的结果并不相同。 r&f
仅被视为单个完全匹配的字符串,因为 r
和 f
单独不是已知词。另一方面,添加反斜杠将两个字母分开,因为\
是一个分词器,在这种情况下,您会得到r
和f
。
鉴于您在更新中声明您有“数据不一致,其中名称中带有“&”的品牌之一被修改为不带有“&”,而另一个则没有”,我怀疑当您 not 添加 \
字符时,您会得到 not 修改的品牌(因为它与整个任期)。但是当你做添加\
字符时,你会得到被修改为删除&
的品牌,因为你现在正在搜索这两个部分,每一个都匹配该品牌名称的部分。
我会修复数据以保持一致:更新已删除 &
的品牌名称以将 & 符号放回原处。然后当人们使用 &
搜索时,没有额外的 @987654347 @添加,这将是完全匹配的。这种行为将包含在数据中,并且不需要您添加代码来规避 FTS 的自然操作,这似乎是一种容易出错的方法。
【讨论】:
非常感谢!我尝试了几个实验,现在我明白了 AND 运算符的作用。但是,我仍然需要一个解决方案:是否有可能以某种方式“逃脱”&符号?如果我不把它转换成一些安全的角色会更好。 您的回答很棒而且很有帮助!我还有一个问题:为什么'r\&f'
不返回由'r&f'
返回的r&f
记录?
@Simone 不知道为什么会这样,这可能取决于sys.dm_fts_parser
TVF 中参数 3 和 4 中反映的设置。我怀疑由于r\&f
会同时进入r
和f
,它们都不匹配r&f
,后者被认为是一个单一的实体。以上是关于使用 CONTAINSTABLE 在 SQL Server 全文搜索查询中转义 & 号的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server 2008 FTS CONTAINSTABLE 不返回超过五行
CONTAINSTABLE 和 CONTAINS,传递哪个字符串来匹配所有记录?
如何在实体框架中映射 CONTAINSTABLE 函数(代码优先)?