web-dev-qa-db-ja.com

CSVファイルをSQLサーバーにアップロードする

C#を使用して大きなcsvデータファイルをSQLサーバーにアップロードする最良の方法は何ですか?ファイルには、約30,000行と25列が含まれています。

24
user3083221

最初に、プログラミングの必要はありません。 SQL管理ツールを使用して、CSVファイルをSQLデータベースに直接アップロードできます。ただし、プログラミングで本当に必要な場合は、以下をお読みください。

個人的には、このアプローチはプログラミングを通じて行う最も効率的で簡単な方法だと思います。

一般に、2段階で達成できます

1stステップは、CSVファイルを読み取り、DataTableとしてレコードを保持します。
2ndステップは、取得したDataTableをバルクエントリとしてSQLデータベーステーブルに保存します。

これは、CSVファイルデータをDataTableとして返す関数です。呼び出してメモリに保存すると、あなたはそれで何でもできます。

この関数は、CSV読み取りファイルをDataTableに返します。

private static DataTable GetDataTabletFromCSVFile(string csv_file_path)
    {
        DataTable csvData = new DataTable();
        try
        {
          using(TextFieldParser csvReader = new TextFieldParser(csv_file_path))
             {
                csvReader.SetDelimiters(new string[] { "," });
                csvReader.HasFieldsEnclosedInQuotes = true;
                string[] colFields = csvReader.ReadFields();
                foreach (string column in colFields)
                {
                    DataColumn datecolumn = new DataColumn(column);
                    datecolumn.AllowDBNull = true;
                    csvData.Columns.Add(datecolumn);
                }
                while (!csvReader.EndOfData)
                {
                    string[] fieldData = csvReader.ReadFields();
                    //Making empty value as null
                    for (int i = 0; i < fieldData.Length; i++)
                    {
                        if (fieldData[i] == "")
                        {
                            fieldData[i] = null;
                        }
                    }
                    csvData.Rows.Add(fieldData);
                }
            }
        }
        catch (Exception ex)
        {
           return null;
        }
        return csvData;
    }
  }

SQLBulkCopy-この関数を使用して、取得したDataTableをSqlテーブルに挿入します

static void InsertDataIntoSQLServerUsingSQLBulkCopy(DataTable csvFileData)
{
    using(SqlConnection dbConnection = new SqlConnection("Data Source=ProductHost;Initial Catalog=yourDB;Integrated Security=SSPI;"))
    {
         dbConnection.Open();
         using (SqlBulkCopy s = new SqlBulkCopy(dbConnection))
         {
             s.DestinationTableName = "Your table name";
             foreach (var column in csvFileData.Columns)
             s.ColumnMappings.Add(column.ToString(), column.ToString());
             s.WriteToServer(csvFileData);
         }
     }

ソース

49
Kirk

プログラミングを介してデータベースにCSVをアップロードする別の方法を次に示します。 Cinchoo ETL 、オープンソースライブラリは、DataReaderを使用してデータベースにCSVファイルをアップロードするジョブを実行できます。これは、ほとんどまたはまったくメモリオーバーヘッドのないストリーミングアプローチです。

サンプルの方法を次に示します

string connectionstring = @"#YOUR DB ConnectionString#";
using (SqlBulkCopy bcp = new SqlBulkCopy(connectionstring))
{
    using (var p = new ChoCSVReader("#YOUR CSV FILE#").WithFirstLineHeader())
    {
        bcp.DestinationTableName = "#TABLENAME#";
        bcp.EnableStreaming = true;
        bcp.BatchSize = 10000;
        bcp.BulkCopyTimeout = 0;
        bcp.NotifyAfter = 100;
        bcp.SqlRowsCopied += delegate (object sender, SqlRowsCopiedEventArgs e)
        {
            Console.WriteLine(e.RowsCopied.ToString("#,##0") + " rows copied.");
        };
        bcp.WriteToServer(p.AsDataReader());
    }
}
4
RajN

大きなCSVファイルをSQL Serverにインポートするための最良の方法は、SqlBulkCopyIDataReader実装とともに使用することです。これの良い点は、ファイル全体をメモリに読み込まないことです(DataTableアプローチを使用する場合)。SQLServerに送信されるバッチのサイズを制御できます。悪い点は、IDataReaderを実装しなければならないことです。これは、私が見た中で最も長いMSインターフェイスの1つです。

私はあなたのためのトリックを行うnugetパッケージを書きました。素晴らしい CsvHelper パッケージを使用しているため、設定はほとんど必要ありません。最も単純なシナリオは次のようになります。

//Instantiate the reader, providing the list of columns which matches 1 to 1 the data table structure.
var dataReader = new CsvDataReader(filePath,
    new List<TypeCode>(5)
    {
        TypeCode.String,
        TypeCode.Decimal,
        TypeCode.String,
        TypeCode.Boolean,
        TypeCode.DateTime
    });

bulkCopyUtility.BulkCopy("TableName", dataReader);

さらに複雑なシナリオ用の追加の構成オプションもあります(柔軟な列マッピング、csvファイルには存在しない追加の静的列値、値変換)。興味があるなら、プロジェクトは Github にあり、 nuget package として利用可能です。

参考のために、SqlBulkCopyIDataReaderとともに使用する方法を次に示します。

public void BulkCopy(string tableName, IDataReader dataReader, Action<SqlBulkCopy>  configureSqlBulkCopy)
{
    using (SqlConnection dbConnection = new SqlConnection(connectionString))
    {
        dbConnection.Open();

        using (SqlBulkCopy bulkCopy = new SqlBulkCopy(dbConnection))
        {
            bulkCopy.BatchSize = 3000; //Data will be sent to SQL Server in batches of this size
            bulkCopy.EnableStreaming = true;
            bulkCopy.DestinationTableName = tableName;

            //This will ensure mapping based on names rather than column position
            foreach (DataColumn column in dataReader.GetSchemaTable().Columns)
            {
                bulkCopy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
            }

            //If additional, custom configuration is required, invoke the action
            configureSqlBulkCopy?.Invoke(bulkCopy);

            try
            {
                // Write from the source to the destination.
                bulkCopy.WriteToServer(dataReader);
            }
            finally
            {
                dataReader.Close();
            }
        }
    }
}
4

これは、SSISにとって完璧な仕事のように思えます。 SQL Serverの無料の部分であり、フォルダー内のすべてのcsvファイルをループでき、非常に高速で、優れたエラー処理とログ記録を備えています。

1

この手法ではSQLBulkCopy()機能を使用しますが、ファイル全体をメモリに読み込むわけではありません。

秘Theは、.csvファイルを読み取るIDataReaderクラスを実装することです。

https://www.codeproject.com/Tips/1029831/Fast-and-Simple-IDataReader-Implementation-to-Read

1
Michael Potter

System.Data.SqlClient.SqlBulkCopy クラスを使用して、SQLテーブルにデータを挿入します。このクラスを使用するには、CVSデータをDataTableに変換する必要もあります。 here のいずれかの方法を参照してください。

1
pakeha_by

Bulk Insertを使用することもできます

Public Shared Function bulkQuery()

        Dim query As StringBuilder = New StringBuilder

        query.Append("USE Import_DB BULK INSERT dbo.[Insert_Table] FROM")
        query.Append(" 'C:\Insert_Table.csv' ")
        query.Append("With (FIELDTERMINATOR = ',', ROWTERMINATOR = '\n')")

        Return query.ToString

    End Function

ただし、テーブル名とcsv名は同一である必要があり、csvの列数は事前定義されたテーブルと同じである必要があるため、ここでは注意してください。

0
ruedi
    private void GetDataTabletFromCSVFile(string fileName)
    {
        DataTable dt = new DataTable();
        //dt.TableName = fileName;

        try
        {
            using (TextFieldParser csvReader = new TextFieldParser(fileName))
            {
                csvReader.SetDelimiters(new string[] { "," });
                csvReader.HasFieldsEnclosedInQuotes = true;
                string[] colFields = csvReader.ReadFields();
                //foreach (string column in colFields)
                //{
                //    DataColumn datecolumn = new DataColumn(column);
                //    datecolumn.AllowDBNull = true;
                //    dt.Columns.Add(datecolumn);
                //}
                dt.Columns.AddRange(new DataColumn[8] {
                    new DataColumn("Symbol", typeof(string)),
                new DataColumn("ISIN", typeof(string)),
                new DataColumn("Company", typeof(string)),
                new DataColumn("FirstListingDate", typeof(string)),
                new DataColumn("FaceValue", typeof(string)),
                new DataColumn("PaidUpValue", typeof(string)),
                new DataColumn("MarketLot",typeof(string)),
                new DataColumn("industry",typeof(string))
                });
                while (!csvReader.EndOfData)
                {
                    string[] fieldData = csvReader.ReadFields();
                    //Making empty value as null
                    for (int i = 0; i < fieldData.Length; i++)
                    {
                        if (fieldData[i] == "")
                        {
                            fieldData[i] = null;
                        }
                    }
                    dt.Rows.Add(fieldData);
                }
                var builder = new ConfigurationBuilder()
                    .SetBasePath(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location))
                    .AddJsonFile("appsettings.json");

                var configuration = builder.Build();
                string DBconnection = configuration.GetSection("ConnectionString").Value;
                using (SqlConnection dbConnection = new SqlConnection(DBconnection))
                {
                    dbConnection.Open();
                    using (SqlBulkCopy s = new SqlBulkCopy(dbConnection))
                    {
                        s.DestinationTableName = "Static.dbo.Securitiesinfo";
                        foreach (var column in dt.Columns)
                            s.ColumnMappings.Add(column.ToString(), column.ToString());
                        s.WriteToServer(dt);
                    }
                }

            }
        }
        catch (Exception ex)
        {
            var x = ex;
        }

    }
0
vijay