使用CONTAINSTABLE

时间:2016-09-22 15:33:22

标签: sql-server tsql escaping full-text-search

我有一个非常奇怪的案例。我的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字符被视为逻辑AND(非按位)。

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

1 个答案:

答案 0 :(得分:2)

您看到的奇怪行为很可能是由于CONTAINSCONTAINSTABLE函数(均与SQL Server的全文搜索功能一起使用)使用&符号{{1} })字符等同于&运算符。以下声明摘自AND的文档:

  

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

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

<强>更新

根据&#34;编辑2&#34;中提供的信息问题和其他研究,我会说你需要逃避任何事情。似乎将搜索短语放在双引号中(作为使用CONTAINS的结果)将FORMSOF视为字面值或断字符,具体取决于{两边的值} {1}}。请尝试以下示例:

&

&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都是分开的,并且永远不会合并为一个完全匹配的字符串。< / p>

然而,bobsally之间的结果并不相同。 r&f仅被视为单个完全匹配字符串,因为仅r\&fr&f不是已知单词。另一方面,添加反斜杠会分隔两个字母,因为r是一个断字符,在这种情况下,您同时获得f\

鉴于您在更新中声明您有&#34; 数据不一致,其中一个品牌带有&#34;&amp;&#34;在其名称中被修改为不具有&#34;&amp;&#34;,而另一个不是&#34;,我怀疑当你做添加r字符,即可获得修改的品牌(因为它与完整字词完全匹配)。但是,当您 添加f字符时,您就会获得 修改后的品牌,以删除\,因为您现在已经搜索两个部分,每个部分匹配该品牌名称的一部分。

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