目前,我正在将所有Delphi 2007代码库更新为Delphi XE2。最重要的考虑因素是ANSI到Unicode的转换,我们通过将所有基类型(char / string)重新定义为ANSI类型(ansichar / ansistring)来处理。这在我们的许多程序中都有效,直到我开始使用数据库。
当我将存储从文件读取的信息的程序转换为SQL Server 2008数据库时,问题就开始了。突然使用字符串查找数据的简单查询将失败,例如:
SELECT id FROM table WHERE name = 'something'
name
字段为varchar
。我发现通过在字符串名称前面添加N
,我能够成功完成查询。我的印象是varchar
只能 存储ANSI字符,但它似乎存储了Unicode? p>
更多信息:Delphi中的名称字段为string[13]
,但我尝试删除[13]
。数据库排序规则为SQL_Latin1_General_CP1_CI_AS
。我们使用ADO与数据库连接。连接信息存储在ODBC管理器中。
注意:由于Panagiotis的一些指示,我已经解决了我的实际问题。我们从地图文件中读取的名称是array[1..24] of AnsiChar
。此值被隐式转换为string[13]
,其中包含空字符。因此,5个字符的名称实际上被存储为数据库中的5个字符+8个空字符。
答案 0 :(得分:2)
varchar 字段不存储Unicode字符。它们将ASCII值存储在字段排序规则指定的代码页中。当您尝试存储来自不同代码页的Unicode或数据时,SQL Server将try to convert characters到正确的代码页。您可以禁用此功能,但最好的选择是在应用程序中使用 nvarchar 字段和UnicodeString来避免整个混乱。
您提到您将所有字符类型更改为ANSI,而不是应用程序中的UNICODE类型。如果要使用UNICODE,则应使用UNICODE类型,如UnicodeString。否则,在将值发送到服务器时,您的值将转换为ANSI。当您创建发送到服务器的AnsiString时,您的代码将完成此转换。
BTW,您的select语句在字段中存储ASCII值。如果要将值存储为unicode值,则必须在N前面添加值,例如g.g
SELECT id FROM table WHERE name = N'something'
即使这样也不能保证您的数据会以Unicode格式到达服务器。如果将语句存储在AnsiString中,则整个语句在发送到服务器之前将转换为ANSI。如果您的应用程序进行了错误的转换,您最终会在服务器上出现错误的数据。
解决方案非常简单,只需使用参数化语句将unicode值作为unicode参数传递,并将它们存储在NVarchar字段中。它速度更快,可以避免所有转换错误并防止SQL注入攻击。