【问题标题】:Converting string from MSSQL to MySQL将字符串从 MSSQL 转换为 MySQL
【发布时间】:2017-12-07 19:04:47
【问题描述】:

我有一个从 SQL DB 读取并写入 MySQL 的应用程序。此应用程序用于为客户端迁移数据。在测试时,我遇到了一条记录的问题,我很困惑。我已经测试了该站点关于使用 C#Encoding 类的各种建议,并且每次都尝试转换它,但在这条记录上没有成功。

SQL 排序规则是SQL_Latin1_General_CP1_CI_AS,MySQL 排序规则是latin1_general_ci 代码示例(在foreach 循环中)如下:

foreach(var pgObj in PgObjList)
{
    //byte[] bytes = Encoding.Default.GetBytes(pgObj.Description);
    //pgObj.Description = Encoding.ASCII.GetString(bytes);

    byte[] utf8Bytes = Encoding.UTF8.GetBytes(pgObj.Description);
    byte[] isoBytes = Encoding.Convert(Encoding.ASCII, Encoding.UTF8, utf8Bytes);
    string uf8converted = Encoding.UTF8.GetString(isoBytes);

    string insertSQL = @"INSERT INTO `mainsite`.`sf_root_items` 
                        (`ID`, 
                        `LoweredName`, 
                        `MenuName`, 
                        `Title`, 
                        `Description`, 
                        `PageType`, 
                        `ExternalUrl`
                        )
                        VALUES
                        ('" + pgObj.ID + @"', 
                        '" + pgObj.LoweredName + @"', 
                        '" + pgObj.MenuName + @"', 
                        '" + pgObj.Title + @"', 
                        '" + pgObj.Description + @"', 
                        '" + pgObj.PageType + @"', 
                        '" + pgObj.ExternalUrl + @"'
                        );";
    string outputMsg;
    // more code here to execute the MySQL statement
}

我得到的最好结果是转换为 ASCII(注释代码)并将文本存储为看起来像汉字的形式。没有例外,但是当我以任何其他方式运行它时,我得到了这条记录的异常。

例外:

MySQL Exception on record#28/r/n
MySql.Data.MySqlClient.MySqlException (0x80004005): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'il vous plaît (RSVP)', 
                                                '0', 
             ' at line 15
       at MySql.Data.MySqlClient.MySqlStream.ReadPacket()
       at MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int64& insertedId)
       at MySql.Data.MySqlClient.Driver.GetResult(Int32 statementId, Int32& affectedRows, Int64& insertedId)
       at MySql.Data.MySqlClient.Driver.NextResult(Int32 statementId, Boolean force)
       at MySql.Data.MySqlClient.MySqlDataReader.NextResult()
       at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
       at MySql.Data.MySqlClient.MySqlCommand.ExecuteNonQuery()
       at SharepointImportDL.SharepointContentImport.GetSitefinityContent.addRootItems(List`1 PgObjList, String WPConnectionString) in C:\Users\Administrator\Source\Repos\TestBinaryWriter\Test Binary Writer\SharepointImportDL\SharepointContentImport\GetSitefinityContent.cs:line 986

第 986 行是 SQL 执行:int output = cmd.ExecuteNonQuery();

还可能值得注意的是,我插入的字符串来自 nvarchar 列 (MSSQL) 和 varchar (MySQL) 列

具有讽刺意味的是,字符串是一个简单的“Répondez s'il vous plaît (RSVP)”(我想揍不得不使用法语文本的自命不凡的人)所以我不太可能'会再次遇到它,但显然我需要处理这种可能性。

【问题讨论】:

  • UTF-8 涵盖的字符范围远远超过 ASCII。也许在发送之前转换为 UTF-8,然后在存储之前转换回目标数据库想要的任何字符编码。
  • 您应该始终使用参数化查询。我知道通过简单的数据迁移,SQL 注入的风险很低,但它确实很好地处理了转义和所有这些问题。而且最好是在安全方面。它甚至可以解决您的问题。
  • @rossum 原谅我的无知,但我什么时候转换,你建议“在发送之前”,所以这会出现在我的 MSSQL 选择语句中吗?我还没有看到这样做的方法,因为这是我的第一种方法
  • 我阅读了一些资料。 C1 表示代码页 1252。根据this 页,它与 latin1_general_ci 相同。我仍然认为您可以在不进行转换的情况下进行参数化查询。
  • 您对@PalleDue 的使用parameterized 查询的建议做了什么吗?我想它会解决你的问题。

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


【解决方案1】:

在构建 SQL (string insertSQL) 之前转义字符串(例如,pgObj.Description)。否则你会从

之类的东西中得到语法错误
, 'Répondez s'il vous plaît (RSVP)', 

注意单引号中的单引号是怎么回事?还要注意错误是如何指出问题的:

... syntax to use near 'il vous plaît (RSVP)', 

【讨论】:

    【解决方案2】:

    感谢 Palle Due 提出的参数化查询建议,我决定在 MySQL 中编写一个存储过程来处理这些问题。

    我的 C# 代码,基于我原来的问题如下:

    foreach(var pgObj in PgObjList)
    {
        string SP = "sp_insert_root_items";
        string outputMsg = "";
    
        MySqlConnection myConnection = new MySqlConnection(WPConnectionString);
        MySqlCommand cmd;
        try
        {
            if (myConnection.State != ConnectionState.Open)
            {
                myConnection.Close();
                myConnection.Open();
            }
            cmd = myConnection.CreateCommand();
            cmd.CommandText = SP;
            cmd.CommandType = CommandType.StoredProcedure;
    
            cmd.Parameters.AddWithValue("@ID", pgObj.ID);
            cmd.Parameters["@ID"].Direction = ParameterDirection.Input;
    
            cmd.Parameters.AddWithValue("@LoweredName", pgObj.LoweredName);
            cmd.Parameters["@LoweredName"].Direction = ParameterDirection.Input;
    
            cmd.Parameters.AddWithValue("@MenuName", pgObj.MenuName);
            cmd.Parameters["@MenuName"].Direction = ParameterDirection.Input;
    
            cmd.Parameters.AddWithValue("@Title", pgObj.Title);
            cmd.Parameters["@Title"].Direction = ParameterDirection.Input;
    
            cmd.Parameters.AddWithValue("@Description", pgObj.Description);
            cmd.Parameters["@Description"].Direction = ParameterDirection.Input;
    
            cmd.Parameters.AddWithValue("@PageType", pgObj.PageType);
            cmd.Parameters["@PageType"].Direction = ParameterDirection.Input;
    
            cmd.Parameters.AddWithValue("@ExternalUrl", pgObj.ExternalUrl);
            cmd.Parameters["@ExternalUrl"].Direction = ParameterDirection.Input;
    
            cmd.Parameters.AddWithValue("@ParentID", "");
            cmd.Parameters["@ParentID"].Direction = ParameterDirection.Input;
    
            int output = cmd.ExecuteNonQuery();
    
            // a value greater than 0 means execution was successful
            if (output > 0)
            {
                counter++;
                //outputMsg = "Record #" + counter.ToString() + " created";
    
            }
            else
            {
                counter++;
                outputMsg = "There was an error inserting record #" + counter.ToString();
            }
    
            myConnection.Close();
        }
        catch (Exception ex)
        {
            outputMsg = "MySQL Exception on record#" + counter.ToString() + "/r/n" + ex.ToString();
        }
    
        returnMsg += outputMsg;
    
    }
    

    下面是一个存储过程的示例 - 它是从 SQLYog 导出的。

    DELIMITER $$
    
    /*!50003 CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_insert_root_items`(
            IN ID VARCHAR(255), 
            IN LoweredName VARCHAR(255), 
            IN MenuName VARCHAR(255), 
            IN Title VARCHAR(255), 
            IN Description VARCHAR(500), 
            IN PageType VARCHAR(255), 
            IN ExternalUrl VARCHAR(255), 
            IN ParentID VARCHAR(255)
        )
    BEGIN
        INSERT INTO `wp_sf_page_items`
            (`ID`, 
            `LoweredName`, 
            `MenuName`, 
            `Title`, 
            `Description`, 
            `PageType`, 
            `ExternalUrl`, 
            `ParentID`
        )
        VALUES(ID, LoweredName, MenuName, Title, Description, PageType, ExternalUrl, ParentID);  
    END */$$
    DELIMITER ;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-29
      • 1970-01-01
      • 2018-08-09
      • 1970-01-01
      • 1970-01-01
      • 2014-01-04
      • 2014-05-24
      • 1970-01-01
      相关资源
      最近更新 更多