【问题标题】:Unable to return query Thai data无法返回查询泰语数据
【发布时间】:2014-12-08 16:46:36
【问题描述】:

我有一个包含泰文和英文文本数据列的表格。 NVARCHAR(255)。 在 SSMS 中,我可以很容易地查询表并返回所有行。但是,如果我随后专门查询其中一个泰语结果,它不会返回任何行。

SELECT TOP 1000 [Province]
,[District]
,[SubDistrict]
,[Branch ]
FROM [THDocuworldRego].[dbo].[allDistricsBranches]

返回

Province    District    SubDistrict Branch 
อุตรดิตถ์   ลับแล   ศรีพนมมาศ   Northern
Bangkok  Khlong Toei    Khlong Tan  SSS1

但是这个查询:

SELECT [Province]
      ,[District]
      ,[SubDistrict]
      ,[Branch ]
  FROM [THDocuworldRego].[dbo].[allDistricsBranches]
  where [Province] LIKE 'อุตรดิตถ์'

不返回任何行。 我需要做什么才能获得预期的结果。 排序规则集是 Latin1_General_CI_AS。 数据显示并插入没有错误只是无法搜索。

【问题讨论】:

  • 不,仍然没有返回任何内容。 N 前缀是必需的,如下所示
  • @g2server :不需要 RTRIM()。它只是使该字段上的任何索引都无法用于帮助此查询。当然,对于以“%”开头的 LIKE 子句,它无论如何都不会在该字段上使用索引,但是,在这里使用 RTRIM 没有任何好处。
  • 您好。我意识到它已经接近 4 年了,但在那段时间里我学到了很多东西,所以我只是更新了我的答案,以便更准确和详细,如果你有兴趣:-)。

标签: sql-server unicode thai


【解决方案1】:

两个问题:

  1. 传递到LIKE 子句的字符串是VARCHAR,因为它没有以大写字母“N”为前缀。例如:

    SELECT 'อุตรดิตถ์' AS [VARCHAR], N'อุตรดิตถ์' AS [NVARCHAR]
    -- ?????????        อุตรดิตถ
    

    这里发生的是,当 SQL Server 解析查询批处理时,它需要确定所有文字/常量的确切类型和值。所以它知道12是一个INT12.0是一个NUMERIC等等。它知道N'ดิ'NVARCHAR,这是一个全包字符集,所以它取值照原样。但是,如前所述,'ดิ'VARCHAR,这是一种 8 位编码,这意味着字符集由代码页控制。对于字符串文字和变量/参数,用于VARCHAR 数据的代码页是数据库的默认排序规则。如果字符串中有字符在数据库的默认排序规则使用的代码页上不可用,则它们要么被转换为“最适合”的映射,如果存在这样的映射,否则它们成为默认的替换字符:@987654335 @。

    从技术上讲,由于数据库的默认排序规则控制字符串文字(和变量),并且由于“泰语”有一个代码页(在 Windows 排序规则中可用),所以有可能有一个 VARCHAR 字符串包含泰语字符(意思是:'ดิ',没有“N”前缀,可以工作)。但这需要更改数据库的默认排序规则,这比简单地在字符串文字前加上“N”要多得多。

    要深入了解此行为,请参阅我的两部分系列:

  2. 需要在两端加上通配符:
    N'%อุตรดิตถ์%'

最终结果将如下所示:

WHERE [Province] LIKE N'%อุตรดิตถ์%'

编辑:
我刚刚编辑了问题以将“结果”格式化为更具可读性。现在看来,以下方法也可能有效(因为问题中的 LIKE 谓词中没有使用通配符):

WHERE [Province] = N'อุตรดิตถ์'

编辑 2:
一个字符串(即单引号内的东西) VARCHAR,如果字符串文字没有前缀“N”。目标数据类型是什么并不重要(例如,NVARCHAR(255) 列)。这里的问题是 source 数据的数据类型,而该源是字符串文字。与 .NET 中的 string 不同,SQL Server 将 'string' 处理为 8 位编码(VARCHAR;ASCII 值 0 - 127 在所有代码页中相同,扩展 ASCII 值 128 - 255 由代码页确定,并且可能是双字节字符集的 2 字节序列)和 N'string' 作为 UTF-16 Little Endian(NVARCHAR;Unicode 字符集,BMP 字符 0 - 65535 的 2 字节序列,代码的两个 2 字节序列高于 65535 点)。使用'string' 与传入VARCHAR 变量相同。例如:

DECLARE @ASCII VARCHAR(20);
SET @ASCII = N'อุตรดิตถ์';
SELECT @ASCII AS [ImplicitlyConverted]
-- ?????????

【讨论】:

  • 在查询中使用了 N 前缀,但是当列已经定义为 nvarcahr(255) 时为什么需要它。为什么需要重新验证请求?
  • @Hammertime :您没有重新验证请求。我将在我的答案中添加一个更新来解释这一点。
  • 感谢您的解释。我现在理解得更彻底了。
  • @Hammertime:不客气。如果这对你有用,你能接受这个答案吗?
【解决方案2】:

可能有很多东西!

首先打印出列的值和十六进制的查询字符串。

SELECT     convert(varbinary(20)Province) as stored convert(varbinary(20),'อุตรดิตถ์') as query from allDistricsBranches;

这应该可以让您对问题有所了解。我认为最可能的原因是 ั、ิ 字符的输入顺序错误。它们显示为主要字母的一部分,但在内部存储为单独的字符。

【讨论】:

  • 'hex' 不是可识别的内置函数名。
  • @Hammertime :正确,HEX 不是 T-SQL 函数。 CONVERT 函数用于在 SQL Server 中完成此类操作。
  • 使用了正确的函数 -- convert() 而不是 hex()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多