【问题标题】:Char encoding and SQL in C#C#中的字符编码和SQL
【发布时间】:2015-06-09 11:48:11
【问题描述】:

我有这个 sql:

从 productcode = @code 的产品中选择 productid

并且@code 是一个参数,它的值是ABCÊ,但它与ABC 匹配,在Visual Studio 中调试它显示在快速观察中。数据库有Latin1_General_CI_AS 作为排序规则。数据库中的字段类型是nvarchar(50)

那么当我将它与ABCÊ 进行比较时,为什么会返回包含 productcode = 'ABC' 的数据行? 我在我的短信select 1 where 'ABC' = 'ABCÊ' 中输入了这个,它没有返回 1,这确实:选择 1 where 'ABC' = 'ABC' 那么它在我的代码中吗?带有 utf 或编码的东西?

编辑 c#代码:

SqlCommand comGetProd = new SqlCommand(@"SELECT ProductID FROM PRODUCTS WHERE (ProductCode = @name)");
comGetProd.Parameters.AddWithValue("name", "ABCÊ");

编辑 15-6-2015

按照@Oskar Sjöberg 的建议缩小了问题范围。它与数据库无关!因为这会返回true

using (StreamReader sr = new StreamReader("test.csv"))
{
    while (!sr.EndOfStream)
    {                  
        Console.WriteLine("D1103SL".Equals(sr.ReadLine()));
    }
}

test.csv 包含:D1103SLÊ

记事本++:

原来是http://www.codetable.net/hex/ca 我还是看不出它是如何相等的。

【问题讨论】:

  • 但它与在 Visual Studio 中调试它的 ABC 相匹配,显示在 quickwatch 中。 这是什么意思?
  • @code参数是nvarchar吗?对于 Unicode 文字,您需要指定 N 前缀以防止转换为 varchar:N 'ABCÊ'`
  • 请出示代码。 ? 出现在您尝试将文本从一个 ASCII 代码页转换为另一个代码页时,从不使用 Unicode 文本。最有可能的是,参数的类型是varchar。还要确保在您到达数据库命令之前没有发生修改,例如使用错误的代码页读取 ASCII 输入
  • 我使用了comGetProd.Parameters.AddWithValue("code", "ABCÊ");,所以我没有指定sql类型。 comGetProd 是一个 SqlCommand
  • 请显示插入值的代码。那是发生转换错误的时候。另请注意,'ABCÊ' 是 varchar,而不是 Unicode,必须进行转换。您需要输入 N'ABCÊ' 才能输入 nvarchar 值。您的 SELECT 1 ... 语句还比较 varchar,而不是 nvarchar 值,尽管这不会改变任何内容

标签: c# sql-server character-encoding collation


【解决方案1】:

使用

COLLATE DATABASE_DEFAULT

如下图

select productid from products where productcode COLLATE DATABASE_DEFAULT = @code

【讨论】:

  • 您能解释一下 COLLATE DATABASE_DEFAULT 如何/为什么会解决这个问题吗?
【解决方案2】:

如果您使用的是 LINQ,则可以使用文化比较。

var result = from a in collection.Products
             select a.Productid
             where string.Equals(a.ProductCode, 'ABCÊ', StringComparison.Ordinal);

【讨论】:

  • OP 在转换方面存在问题,而不是比较。无论如何,这与 LINQ 无关,它与 SQL 有关。 LINQ to EF 可能会拒绝执行此查询,而 L2S 会将整个表加载到内存中然后尝试查找匹配的行
  • 对不起,我不使用 LINQ
【解决方案3】:

我尝试使用相同的排序规则、表格和示例数据设置相同的场景并运行以下代码:

var connection = new SqlConnection("connectionstringgoeshere");
connection.Open();
var command = new SqlCommand(@"SELECT ProductID FROM PRODUCTS WHERE (ProductCode = @name)", connection);
command.Parameters.AddWithValue("name", "ABCÊ");
var dataTable = new DataTable();
dataTable.Load(command.ExecuteReader());
Console.WriteLine(dataTable.Rows);  

它按预期返回零行,将代码中的“ABCÊ”更改为“ABC”会返回包含正确数据的一行。

我认为这里还有另一个问题,但您需要包含一个更完整但仍然最少的代码示例、数据库架构和数据库数据。

【讨论】:

  • 感谢您的时间和精力,我会看看我是否可以在单独的小项目中重现它
  • 我做了一个类似的测试项目,但是当我像你一样硬编码字符串时,我没有行。当我从 csv 文件(复制粘贴)中读取完全相同的字符串时,我得到了 1 行(没有线索)
【解决方案4】:

显然,“\xCA”在 Mac 上是一个不间断的空格——与 Windows 和 ISO-Latin-1 中的“\xA0”以及 HTML 中的“ ”相同。

http://use.perl.org/use.perl.org/commentsf6b4-3.html?sid=18447&op=reply&threshold=0&commentsort=0&mode=thread

所以当使用 UTF-8 编码时,它只知道这是一个无意义的字符,可以跳过,所以字符串是相等的

using (StreamReader sr = new StreamReader("test.csv", ASCIIEncoding.UTF8))
{
    while (!sr.EndOfStream)
    {
        Console.WriteLine("D1103SL".Equals(sr.ReadLine()));
    }
}

当使用 ascii 时,它会“看到”Ê,当比较时,它会返回 false。

【讨论】:

    【解决方案5】:

    尝试使用SQL_Latin1_General_CP1_CI_AS 而不是COLLATE Latin1_General_CI_ASsource

    【讨论】:

    • 为什么这会对 Unicode (nvarchar) 字段有所帮助?您链接的文章实际上提到了he rules for nvarchar data sorting/comparisons seem to be identical though ,实际上警告不要这样做Mixing the collations ... could impact on your performance quite heavily or cause collation conflict errors ... especially if you are using the older SQL collation
    猜你喜欢
    • 2015-01-21
    • 1970-01-01
    • 2011-06-17
    • 2011-08-06
    • 2013-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多