【问题标题】:Correct String Escaping for T-SQL string literalsT-SQL 字符串文字的正确字符串转义
【发布时间】:2010-11-19 00:10:09
【问题描述】:

我想使用如下查询,我正在寻找确切的信息/链接来转义字符串

书名是 NVARCHAR(200)

SELECT * FROM Books WHERE BookTitle IN ('Mars and Venus', 'Stack''s Overflow \r\n')

问题: 是否只需要转义“'”,甚至 \r\n 也需要转义? MySql .Net Provider 公开了一个转义字符串值的方法,Sql Server .Net Provider 中是否有这样的功能?

我可能需要对字符串值进行等效的 C# 转义。

我知道参数化命令,但是为了最小化我的服务器到客户端的通信,并且我在 IN 子句中的值是从 20 到 50 的数量,为 BookTitle 中的每个值运行 SELECT 变得太昂贵了一通电话。而是运行单个查询并级联返回所有结果有助于节省网络资源。

【问题讨论】:

  • 这是一个无关紧要的评论,但仍然很重要。如果您在管理工作室中为自己的查询执行此操作,那很好。但是,如果您是以编程方式 执行此操作 —构建您的查询字符串并在客户端程序中转义 — 你做错了。您需要一个参数化查询。
  • 您关于需要为参数的每个值运行 1 次选择的建议是不正确的。使用表值参数或 XML 或使用逗号分隔字符串并在 SQL Server 端解压。这将是一个查询。 sommarskog.se/arrays-in-sql-2008.html

标签: c# sql-server tsql


【解决方案1】:

SQL Server 无法识别 \r\n 序列,无论它是否被转义。

如果您想匹配BookTitle 中的\r\n,则需要执行类似的操作:

-- \r = CHAR(13)
-- \n = CHAR(10)
SELECT *
FROM Books
WHERE BookTitle IN ('Mars and Venus', 'Stack''s Overflow ' + CHAR(13) + CHAR(10))

【讨论】:

  • 是的,我明白了,但我需要在 C# 中为每种类型动态执行此操作,就像我需要一个转义序列,我可以将 string.replace 用于所有此类值并准备最终查询。
  • 在这种情况下,不要使用字符串转义。请改用参数化查询。
【解决方案2】:

除了引号或换行符之外,还有更多的东西需要转义。如果有二进制输入(黑客)怎么办?更好地使用 PreparedStatement(在 java 中)或目标语言中的任何其他等效项。 Java 示例:

PreparedStatement ps = con.prepareStatement("SELECT * FROM Books WHERE BookTitle IN (?, ?)");
ps.setString(1, "Mars and Venus");
ps.setString(2, "Stack's Overflow
and 
");

ResultSet rs = ps.executeQuery();
....

【讨论】:

  • 虽然这不是完整的答案,但是是的,我在 c# 中尝试了类似的事情,但解决方法很少,现在可以接受。
【解决方案3】:

我遇到了类似的问题,我需要在我的选择查询中有一个 IN,并且元素的数量在运行时会有所不同。

我使用存储过程形式的参数化查询,并传入一个分隔字符串,其中包含我要查找的内容列表。转义由系统自动处理,无需采取特别措施。最好不要用您正在搜索的文本中找到的字符(如逗号)来分隔它。在许多情况下,竖线(“|”)可能效果最好。

顺便说一句,请确保表中的 CRLF 是 CHAR(13)+CHAR(10),因为相反的方式不是 \r\n 并且如果 Environment.NewLine 是其中的一部分,您将找不到它您的搜索。

这是一个存储过程,它使用快速而肮脏的解析来解析我使用过的表:

CREATE PROCEDURE FindBooks
(
    @list varchar(500)
)
AS

CREATE TABLE #parse_table (item varchar(500))

DECLARE @temp                       VARCHAR(500)
DECLARE @result                     VARCHAR(500)
DECLARE @str                        VARCHAR(500)
DECLARE @pos                        SMALLINT

SET @temp = RTRIM(LTRIM(@list))
SET @pos = 1

WHILE @pos > 0
    BEGIN
    SET @pos = CHARINDEX('|',@temp)
    IF @pos > 0 
       BEGIN
         SET @result = SUBSTRING(@temp,1,@pos - 1)
         SET @temp = RTRIM(LTRIM(SUBSTRING(@temp,@pos+1,LEN(@temp) - @pos)))

         INSERT INTO #parse_table
     SELECT @result
       END
    ELSE
       INSERT INTO #parse_table
       SELECT @temp
END

SELECT * FROM Books WHERE Title in (select * from #parse_table)

只需将您的书名列表创建为一个简单的字符串(包含任何嵌入的撇号、CRLF 等)并使用参数化查询。当然,您的存储过程可以包含除分隔列表之外的其他内容。

【讨论】:

    【解决方案4】:

    您可以使用表值参数来传递 IN 语句的值。如果您没有使用足够新版本的 Visual Studio 和/或 sql server 来访问表值参数,则可以改为传入一个逗号分隔的列表作为字符串参数,然后将该参数解析为表。有几种方法可以将字符串拆分为临时表/表变量。您可以在“sql server 中的拆分函数”中搜索多个选项。

    【讨论】:

      【解决方案5】:

      对于这种情况,我通常会做的是将您的信息作为参数传递,但在 XML 中,因此您可以执行以下操作:

      DECLARE @iDoc INT
      EXEC sp_xml_preparedocument @iDoc OUTPUT, @MyXml
      
      SELECT
          *
      FROM
          MyTable
      WHERE
          MyColumn IN (SELECT [Id] FROM OPENXML(@iDoc,'/ss/s',2) WITH ([Id] INT '.'))
      
      EXEC sp_xml_removedocument @iDoc
      

      在这种情况下,xml 看起来像 '<ss><s>1</s><s>2</s>...etc...</ss>'

      【讨论】:

      • CRLF 无法在 xml 处理中存活,对吗?由于它被视为空格,因此您必须以某种方式对其进行转义。无论如何,您如何在 Xml 中转义 CRLF?我猜是 CDATA,但在查询中会如何发挥作用?
      • 我不相信一般的空格需要在 XML 中转义;就是这样
      猜你喜欢
      • 2016-04-25
      • 2015-07-15
      • 2011-01-05
      • 2019-07-28
      • 1970-01-01
      • 1970-01-01
      • 2016-03-07
      相关资源
      最近更新 更多