【问题标题】:How to insert the special character in DB?如何在数据库中插入特殊字符?
【发布时间】:2017-02-23 11:32:37
【问题描述】:

我正在使用 Ubuntu 并使用 DBeaver 进行数据库访问。我正在尝试将拉丁字符插入数据库(MSSQL)并引发错误。但是如果我用DBeaver 插入相同的特殊字符,它不会抛出任何错误并且它正在工作。我已经看到this 的问题。但我没有任何想法。

它抛出以下错误:

DBD::ODBC::st execute failed: [unixODBC][FreeTDS][SQL Server]Error converting characters into server's character set. Some character(s) could not be converted (SQL-HY000) at expert.fi_review.pl line 243.

db 中的数据是J�rjest�myyr�。但实际数据是Järjestömyyrä。

示例代码:

my ($dsn,$dbh);
&DB_Connect;

$insert_query = "INSERT INTO table_name (name) values(N'$name')";
my $sth = $dbh->prepare($insert_query);
$sth->execute() or $DB_Error=$DBI::errstr;

sub DB_Connect
{
    $dsn = "dbi:ODBC:driver={SQL Server};Server=$Server_name,$port;database=$Database_name;driver=FreeTDS;tds_version=8.0;";
    reconnect: $dbh = DBI->connect($dsn, $db_user_id, $db_pwd ,{AutoCommit => 1}) or goto reconnect;
    $dbh-> {'LongTruncOk'} = 1;
    $dbh-> {'LongReadLen'} = 90000;
}

【问题讨论】:

  • 你的sql表字段是nvarchar吗?如果没有,请尝试。
  • 你能展示你的代码吗?
  • @SeanB 是的。我的sql表只有nvarchar类型。
  • 表和/或数据库有什么字符编码?
  • 变量$name的内容编码是什么?

标签: sql-server database perl odbc special-characters


【解决方案1】:

嗯。我向 FreeTDS 添加了iconv 支持,从某种意义上说,我对那个错误消息负责。我有三个问题和一个建议。

  1. 目标列table_name.name的编码是什么?该编码是否支持您尝试插入的字符?我打赌不会。

  2. freetds.conf 中的客户端字符集是否与 locale(1) 中反映的字符集匹配?

  3. 您确定您没有使用旧的 TDS 协议 4.1 版吗?

FreeTDS 将 SQL 文本转换为 UTF-16。当您将数据插入到 SQL insert 语句中时,FreeTDS 会转换整个语句、数据和所有内容。如果客户端编码描述不正确,则无法转换数据。如果服务器编码不能代表字符,则无法转换数据。如果该协议是古老的,则看不到对 Unicode 的支持。

很难从您的错误消息中看出,但在我看来,客户端成功而服务器端失败。也就是说,FreeTDS 正确地将数据转换为 UTF-16,但服务器无法将数据插入到name 列,因为它是varchar,而不是nvarchar,以及数据库的“代码页”(或列,如果指定)不是可以表示这些字符的列。

我的建议是使用 TDS_DUMP 并加入 FreeTDS 邮件列表。 TDS_DUMP 日志将回答我提出的所有问题。而且您会在邮件列表上获得更好的支持,因为它是专门的。

您可能会问为什么 DBeaver 似乎可以工作。我不知道;直到现在我才听说过。我可以告诉您,有一些方法可以插入数据(例如,使用 ODBC 中的参数化查询),服务器只需逐字插入数据。奇怪的是,它并没有验证它们对于声明的编码是否有效。

我帮助过很多人解决类似的问题。数据库是为 CP-1252 设置的,但数据未正确编码。该应用程序可以插入错误编码的数据,然后检索它们并正确渲染它们,就像它在雷达下一样。但是让 DBA 尝试使用普通的管理工具查询数据或检查它们,它们看起来有趣。服务器假定其数据库中的数据是根据数据库定义进行编码的。如果不是这种情况,就会发生欢闹!

如果您遇到这种情况,您可以轻松地进行测试。使用 DBeaver 插入数据。使用 SQL Server 管理应用程序或旧的 isql 在 Windows 上检索它。很可能你不会被逗乐。

【讨论】:

    【解决方案2】:

    将 utf-8 转换为 utf-16,然后再将其插入到 nvarchar 列中。

    阅读时返回 utf-8。

    或者使用 varbinary 列并在其中存储纯 utf-8 字节。在 nvarchar 列中存储 utf-8 编码的数据是错误的。

    【讨论】:

      【解决方案3】:

      您可以尝试像这样更改您的代码吗?

      $insert_query = "INSERT INTO table_name (name) values(?)";
      my $sth = $dbh->prepare($insert_query);
      $sth->bind_param(1, $name, DBI::SQL_WVARCHAR);
      $sth->execute() or $DB_Error=$DBI::errstr;
      

      【讨论】:

        【解决方案4】:

        将字段转换为utf8_unicode_ci

        示例:ALTER TABLE t CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

        或者如果是查询:

        SELECT * FROM `INFORMATION_SCHEMA.COLUMNS`
        WHERE TABLE_SCHEMA = 'dbname' AND CHARACTER_SET_NAME = 'latin1'
        

        【讨论】:

          【解决方案5】:

          从您的问题来看,问题何时出现尚不清楚。

          如果它来自 perl,您可以简单地使用 url escape function 对其进行编码

          use URI::Escape; 
          my $string = "Järjestömyyrä";
          my $encode = uri_escape($string); 
          my $decode = uri_unescape($encode);
          

          这里有一个可供预览的 JavaScript 替代方案

          var a="Järjestömyyrä";
          var b=encodeURIComponent(a);
          console.log("Encode  : "+b);
          console.log("Decode : "+decodeURIComponent(b));

          如果您尝试直接插入数据库时​​出现问题,

          然后你必须改变表结构并设置CHARSET to latin1

          ALTER TABLE table_name ALTER COLUMN name  varchar(20) COLLATE Latin1_General_CI_AS NOT NULL;
          

          这些链接将帮助您:

          1:http://kunststube.net/frontback/
          2:https://msdn.microsoft.com/en-us/library/ms190920.aspx

          【讨论】:

            猜你喜欢
            • 2016-02-18
            • 2021-03-27
            • 2011-02-04
            • 1970-01-01
            • 2012-03-24
            • 2020-08-30
            • 2018-02-26
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多