5

我最近添加了一家国际公司,名称为“BLA“BLAHBLAH”Ltd。(双引号是名称的一部分。)

每当用户尝试通过输入“Blah 或其他相关内容来搜索该公司”时,搜索都会失败,并在 SQL Server 中出现语法错误。

我怎样才能避免这种情况,这样搜索就不会失败?

示例 SQL:

SELECT c.companyID, c.companyName, c.dateAdded, count(cm.maxID) as NumDirect
    FROM RussoundGeneral.dbo.Company c  
         LEFT JOIN RussoundGeneral.dbo.CompanyMax cm
                ON (cm.companyId = c.companyId and cm.maxID is not null)  
    WHERE CONTAINS ( companyName,  '"BLAH*' )
    GROUP BY c.companyID, c.companyName, c.dateAdded  
    ORDER BY c.companyName ASC
4

8 回答 8

8

不幸的是,双引号在 FTI 中具有特殊含义,因此即使您对其进行参数化,FTI 引擎也会将其视为短语分隔符。我不确定是否有一种简单的方法可以在 FTI 搜索中包含双引号。方括号也是一个特殊字符,但可以用引号括起来以视为查询术语 - 但不是 AFAIK 双引号。

更新

一些搜索表明将引号加倍“”可能会解决它 - 值得一试。就个人而言,我会在数据库中执行此操作,因为这是一个 TSQL 实现细节。

同样,在传递给 FTI 之前,需要将 ' 加倍为 ''(与 TSQL 转义完全分开),

于 2008-12-22T20:22:58.697 回答
7

使用参数化查询,所有引用问题都将消失。

编辑:如果您不允许他们在 CONTAINS 中输入多个单词,请通过删除引号来清理参数。无论多词搜索如何,通过删除引号来清理输入无论如何都可以工作。

于 2008-12-22T20:14:19.010 回答
3

我强烈怀疑您正在动态构建 SQL - 例如

// Bad code, do not use!
string sql = "SELECT * FROM Foo WHERE X LIKE '" + input + "%'";

这是一个非常非常糟糕的主意,原因有很多——最明显的是SQL 注入攻击。请改用参数化 SQL 语句,在其中单独指定参数。

查看带有sql-injection 标记的问题的各种答案,以了解如何正确执行此操作的示例。

于 2008-12-22T20:12:50.590 回答
1

这是一个理论上的答案,但也许会有所帮助。简短的版本是“在查询中使用参数”,但它有助于理解完整的细节。

在标准 SQL 中,字符串用单引号括起来,嵌入的单引号用一行中的两个单引号表示:

SELECT * FROM SomeWhere
    WHERE SomeThing = 'He said, "Don''t do it!"';

在某些 SQL 方言中,您可以改为用双引号关闭字符串;然后,您需要将双引号加倍以嵌入双引号的单个实例:

SELECT * FROM SomeWhere
    WHERE SomeThing = "He said, ""Don't do it!""';

从问题中不清楚公司名称是否包括外部双引号以及中间双引号,或者它是否只包含中间双引号。但是,原则上,规则是相同的。假设所有三个双引号都是必需的,并在 SQL 中使用单引号 - 在这种情况下更容易:

SELECT c.companyID, c.companyName, c.dateAdded, count(cm.maxID) as NumDirect
    FROM RussoundGeneral.dbo.Company c  
         LEFT JOIN RussoundGeneral.dbo.CompanyMax cm
                ON (cm.companyId = c.companyId and cm.maxID is not null)  
    WHERE CONTAINS ( companyName,  '"BLAH "BLAHBLAH" Ltd.' )
    GROUP BY c.companyID, c.companyName, c.dateAdded  
    ORDER BY c.companyName ASC;

使用双引号:

SELECT c.companyID, c.companyName, c.dateAdded, count(cm.maxID) as NumDirect
    FROM RussoundGeneral.dbo.Company c  
         LEFT JOIN RussoundGeneral.dbo.CompanyMax cm
                ON (cm.companyId = c.companyId and cm.maxID is not null)  
    WHERE CONTAINS ( companyName,  """BLAH ""BLAHBLAH"" Ltd." )
    GROUP BY c.companyID, c.companyName, c.dateAdded  
    ORDER BY c.companyName ASC;

如果您正在使用编程语言构建字符串,那么您必须担心这些引号会超出您的编程语言中对字符串进行评估的任何内容。例如,如果您在 C 中构建字符串文字,则必须使用反斜杠转义双引号:

static const char sql_stmt[] =
"SELECT c.companyID, c.companyName, c.dateAdded,\n"
"       COUNT(cm.maxID) AS NumDirect\n"
"    FROM RussoundGeneral.dbo.Company c\n"
"         LEFT JOIN RussoundGeneral.dbo.CompanyMax cm\n"
"                ON (cm.companyId = c.companyId AND cm.maxID IS NOT NULL)\n"  
"    WHERE CONTAINS(companyName,  \"\"\"BLAH \"\"BLAHBLAH\"\" Ltd.\")\n"
"    GROUP BY c.companyID, c.companyName, c.dateAdded\n"
"    ORDER BY c.companyName ASC";

另一方面,如果您从用户那里读取数据 - 例如公司名称,那么您只需确保正确引用读取的内容。

那些说“使用参数”的人是对的——它更容易、更可靠并且更不容易受到 SQL 注入攻击(如果你还没有看到,请参阅XKCD )。但是,如果您了解基本原理,则可以适应系统的实际要求。

最后说明:在标准 SQL 中,双引号包含“分隔标识符”。也就是说,双引号包含一个名称,该名称必须被视为数据库中某物的名称,而不是字符串文字。在 MS SQL Server 中,[方括号] 具有相同的用途;括号之间是列的名称或数据库中的任何内容。许多系统比这更灵活。并非所有系统在偏离标准的方式上都是相同的。

于 2008-12-22T21:34:50.923 回答
0

你试过用它的ASCII码代替这个字符吗?

于 2008-12-22T20:33:21.907 回答
0

尝试使用转义关键字:

SELECT c.companyID, c.companyName, c.dateAdded, count(cm.maxID) as NumDirect 
FROM RussoundGeneral.dbo.Company c          
LEFT JOIN RussoundGeneral.dbo.CompanyMax cm 
ON (cm.companyId = c.companyId and cm.maxID is not null )  
WHERE CONTAINS ( companyName,  '\"BLAH*' ) escape '\'
group by c.companyID, c.companyName, c.dateAdded  ORDER BY c.companyName ASC
于 2008-12-22T20:38:06.280 回答
0

应该是这样的

string sqlCommand = "SELECT c.companyID, c.companyName, c.dateAdded, count(cm.maxID) as NumDirect FROM RussoundGeneral.dbo.Company c LEFT JOIN RussoundGeneral.dbo.CompanyMax cm ON (cm.companyId = c.companyId and cm.maxID is not null ) WHERE CONTAINS ( companyName,  '@strVal' ) group by c.companyID, c.companyName, c.dateAdded ORDER BY c.companyName ASC"
SqlCommand command = new SqlCommand(strSQLCommand, conn); 
SqlCommand.Parameters.AddWithValue("@strval", SearchTextBox.Text); 
于 2008-12-22T21:15:38.980 回答
0

您最终必须从数据库中提取数据并将其显示在屏幕上或打印在报告上。操作双引号或任何额外的字符会变得非常混乱。

通过在插入或更新之前将字符串转换为 HTML,您可以避免与引号管理相关的所有混淆。在 SELECT 时,很容易从 HTML 转换回来。在报告时(因为报告工具(例如 Crystal Reports)提出了 HTML 格式选项),您甚至不需要做任何事情来以正确的方式显示数据。

顺便说一句,别忘了把发明这个公司名字的人挂起来。

于 2008-12-23T07:22:40.643 回答