简体   繁体   English

无法使用C#将数据导入SQL Server数据库

[英]Cannot import data to SQL Server database with C#

I have exported data from SQL Server express and I try to import them into another database. 我已经从SQL Server Express导出数据,我尝试将它们导入另一个数据库。

I want to use it as "Repair Table" in which I will add more tables with data and I always get an error and I can't understand why. 我想将它用作“修复表”,在其中我将添加更多带有数据的表,我总是会收到错误,我无法理解为什么。

The error is 错误是

Message - System.Data.SqlClient.SqlException (0x80131904): Unclosed quotation mark after the character string 'ΧΥΜΟΙ ΑΧΛΑΔΙΩΝ ΤΗΣ ΠΟΙΚΙΛΙΑΣ '. 消息 - System.Data.SqlClient.SqlException(0x80131904):在字符串'ΧΥΜΟΙΑΧΛΑΔΙΩΝΤΗΣΠΟΙΚΙΛΙΑΣ'之后的未闭合的引号。 Incorrect syntax near 'ΧΥΜΟΙ ΑΧΛΑΔΙΩΝ ΤΗΣ ΠΟΙΚΙΛΙΑΣ '. 'ΧΥΜΟΙΑΧΛΑΔΙΩΝΤΗΣΠΟΙΚΙΛΙΑΣ'附近的语法不正确。

The descriptions are in Greek language, I don't know if this has something to do with the error. 描述是希腊语,我不知道这是否与错误有关。

My code so far 我的代码到目前为止

private void startBtn_Click(object sender, EventArgs e)
{
     string sqlQuery = DatabaseTables.KodikoiTaric;

     if(checkBox1.Checked) 
          InsertDefaultValues(sqlQuery);
}

void InsertDefaultValues(string tableName)
{
    RepairTable(tableName);
    // DataTable csvData = GetDataTabletFromCSVFile(DatabaseTables.taric2);
}

void RepairTable(string tableName)
{
    try
    {
        string sqlConnectionString = Parameters.Config.ConnectionString;
        string script = tableName;
        var sqlqueries = script.Split(new[] { "GO" }, StringSplitOptions.RemoveEmptyEntries);

        SqlConnection conn = new SqlConnection(sqlConnectionString);

        SqlCommand cmd = new SqlCommand("query", conn);
        Server server = new Server(new ServerConnection(conn));

        conn.Open();
        var progressBar = 10;

        foreach (var query in sqlqueries)
        {
            progressBar += 10;
            cmd.CommandText = query;
            cmd.ExecuteNonQuery();
            conn.InfoMessage += delegate (object sender, SqlInfoMessageEventArgs e)
                {
                    FileStream ostrm;
                    StreamWriter writer;
                    TextWriter oldout = Console.Out;
                    string _dbUpdateLogPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\DBUpdate" + DateTime.Now.ToString("ddMMyy") + ".txt";
                    try
                    {
                        if (!File.Exists(_dbUpdateLogPath))
                        {
                            ostrm = new FileStream(_dbUpdateLogPath, FileMode.OpenOrCreate, FileAccess.Write);
                            writer = new StreamWriter(ostrm);
                            Console.SetOut(writer);
                            Console.WriteLine(e.Message);
                            Console.SetOut(oldout);
                            writer.Close();
                            ostrm.Close();
                        }
                        else if (File.Exists(_dbUpdateLogPath))
                        {
                            ostrm = new FileStream(_dbUpdateLogPath, FileMode.Append, FileAccess.Write);
                            writer = new StreamWriter(ostrm);
                            Console.SetOut(writer);
                            Console.WriteLine(e.Message);
                            Console.SetOut(oldout);
                            writer.Close();
                            ostrm.Close();
                        }
                    }
                    catch (Exception ex)
                    {
                        NLogger.NLogger.LibraryLogClass.Error(ex.ToString());
                        return;
                    }

                };
            }

            conn.Close();
    }
    catch (Exception ex)
    {
        NLogger.NLogger.LibraryLogClass.Error(ex.ToString());
    }
}

I have the file as resource file and the form is like this 我有文件作为资源文件,表单是这样的

SET NUMERIC_ROUNDABORT OFF
GO

SET ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, ARITHABORT, QUOTED_IDENTIFIER, ANSI_NULLS, NOCOUNT ON
GO

SET DATEFORMAT YMD
GO

SET XACT_ABORT ON
GO

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
GO

BEGIN TRANSACTION
GO

DELETE FROM [dbo].[KodikosTaric]
GO

SET IDENTITY_INSERT [dbo].[KodikosTaric] ON 

INSERT INTO [dbo].[KodikosTaric] ([Id], [KodikosTaric], [KoinotikonMetron_a], [KoinotikonMetron_b], [Perigrafi], [DasmosTritonXoron], [ProtimisiakosDasmos], [SimpliromatikesMonades], [YpologismosKila], [DiasafistisId]) 
VALUES (1, N'8701100000', NULL, NULL, N'ΕΛΚΥΣΤΗΡΕΣ ΧΕΙΡΟΔΗΓΟΥΜΕΝΟΙ', NULL, NULL, NULL, NULL, NULL),
       (2, N'8701201000', NULL, NULL, N'ΚΑΙΝΟΥΡΓΙΟΙ', NULL, NULL, NULL, NULL, NULL),
       (3, N'8701209000', NULL, NULL, N'ΜΕΤΑΧΕΙΡΙΣΜΕΝΟΙ', NULL, NULL, NULL, NULL, NULL)
      .
      .
      .

The line that always give me the error is this 总是给我错误的那条线就是这个

INSERT INTO [dbo].[KodikosTaric] ([Id], [KodikosTaric], [KoinotikonMetron_a], [KoinotikonMetron_b], [Perigrafi], [DasmosTritonXoron], [ProtimisiakosDasmos], [SimpliromatikesMonades], [YpologismosKila], [DiasafistisId]) 
VALUES (782, N'2009809711', NULL, NULL, N'ΧΥΜΟΙ ΑΧΛΑΔΙΩΝ ΤΗΣ ΠΟΙΚΙΛΙΑΣ GOYAVES', NULL, NULL, NULL, NULL, NULL)

It doesn't matter in which line it is. 它在哪条线上无关紧要。 I try putting it on first line of the file and it throw the same error. 我尝试将它放在文件的第一行,它会抛出相同的错误。

The funny is that if I import that file from SQL Server Express as query it works great. 有趣的是,如果我从SQL Server Express导入该文件作为查询它很有用。

EDIT: Thanks to @Chris JI start understanding the problem. 编辑:感谢@Chris JI开始了解问题。 So the problem is that in the file there is the word 所以问题是在文件中有这个词

GOYAVES GOYAVES

which when I split the text it sees it as GO and not as GOYAVES. 当我分割文本时,它将其视为GO而不是GOYAVES。 I tried to change the split command 我试图改变split命令

var sqlqueries = script.Split(new[] { "\nGO", "\ngo" }, StringSplitOptions.RemoveEmptyEntries);

and I don't have the exception any more but the problem is even though it seems to working and splits correct the sql file it doesn't write anything to the table. 我不再有例外,但问题是即使它似乎工作和拆分更正sql文件它不会写任何东西到表。

EDIT 2: I removed those lines from the sql script 编辑2:我从sql脚本中删除了这些行

SET NUMERIC_ROUNDABORT OFF
GO

    SET ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, ARITHABORT, QUOTED_IDENTIFIER, ANSI_NULLS, NOCOUNT ON
    GO

    SET DATEFORMAT YMD
    GO

    SET XACT_ABORT ON
    GO

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
    GO

    BEGIN TRANSACTION
    GO

and everything worked fine. 一切都很好。 Thanks everyone for your help 谢谢大家的帮助

The problem is most likely here: 问题最有可能在这里:

N'ΧΥΜΟΙ ΑΧΛΑΔΙΩΝ ΤΗΣ ΠΟΙΚΙΛΙΑΣ GOYAVES'
                               ^^

Earlier in your C# code you're doing: 在您的C#代码中,您正在做的事情是:

var sqlqueries = script.Split(new[] { "GO" }, StringSplitOptions.RemoveEmptyEntries);

So it's likely splitting your SQL query on that 'GO' that's in the substring. 因此,它可能会将您的SQL查询拆分为子字符串中的“GO”。 One other clue to this is the error itself: 另一个线索是错误本身:

Unclosed quotation mark after the character string 'ΧΥΜΟΙ ΑΧΛΑΔΙΩΝ ΤΗΣ ΠΟΙΚΙΛΙΑΣ '.

This string is a substring of that full string up to and including the space. 此字符串是该完整字符串的子字符串,包括空格。

You probably need to change your C# to look only for GO at the start of a line. 您可能需要更改C#以在行的开头仅查找GO

As for the best way of doing that, it looks like your code reads the file in to memory whole as a string and then you split on that string. 至于这样做的最佳方式,看起来你的代码将文件作为一个字符串读入整个内存,然后拆分该字符串。 For large files, this could be slow and memory inefficient: it's something I generally try and avoid doing myself. 对于大文件,这可能会很慢并且内存效率低下:这是我通常会尝试避免自己做的事情。

A more efficient method would be to split as you read the file - this saves having to read and process a large string in memory. 一种更有效的方法是在读取文件时进行拆分 - 这样可以节省读取和处理内存中的大字符串的麻烦。 Something like this would do the job: 像这样的东西可以完成这项工作:

private IEnumerable<string> GetStatement(string sqlFile)
{
    using (var sr = new StreamReader(sqlFile))
    {
        string s;
        var sb = new StringBuilder();
        while ((s = sr.ReadLine()) != null)
        {
            if (s.Trim().Equals("GO", StringComparison.InvariantCultureIgnoreCase))
            {
                yield return sb.ToString();
                sb.Clear();
                continue;
            }

            sb.AppendLine(s);
        }

        yield return sb.ToString();
    }
}

This method reads the file line by line, and when it encounters "GO" on a line by itself it returns that batch. 此方法逐行读取文件,当它在一行上遇到“GO”时,它将返回该批次。 It can be called in a simple for each: 每个都可以简单地调用它:

foreach (var batch in GetStatement("Batch.sql"))
{
    Console.WriteLine(batch);
}

If you'd prefer to still read the file in full, and process a string, then you can swap the StreamReader out for a StringReader and apply the same method. 如果您仍然希望仍然完整地读取文件并处理字符串,则可以将StreamReader交换为StringReader并应用相同的方法。 But unless you really need to load the entire file into memory, it's simpler (and potentially faster for large files) to avoid doing that in the first instance and just process as you go. 但除非你真的需要将整个文件加载到内存中,否则它更简单(并且对于大文件来说可能更快),以避免在第一个实例中执行此操作并且只是随时处理。

How about this: 这个怎么样:

  var sqlqueries = script.Split(new[] { "\rGO", "\r\nGO" }, 
             StringSplitOptions.RemoveEmptyEntries);

The two strings will match the likely forms of line breaks. 这两个字符串将匹配可能的换行符形式。

See How to split strings on carriage return with C#? 请参见如何使用C#在回车符上拆分字符串?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM