Was ist der beste Weg, um eine große csv
-Datendatei mit C # in den SQL-Server zu laden? Die Datei enthält etwa 30.000 Zeilen und 25 Spalten.
Zunächst einmal, Sie brauchen kein Programmierzeug. Sie können CSV-Dateien mit SQL-Verwaltungstools direkt in die SQL-Datenbank hochladen. Wenn Sie es jedoch wirklich durch Programmierung tun müssen, lesen Sie unten.
Ich persönlich denke, dass dieser Ansatz der effizienteste und einfachste Weg ist, durch Programmierung zu erreichen.
Im Allgemeinen können Sie es in zwei Schritten erreichen
1st ist das Lesen der CSV-Datei und das Speichern der Datensätze als DataTable
.
2nd ist das Speichern der abgerufenen DataTable
in der SQL-Datenbanktabelle als Masseneintrag
Dies ist eine Funktion, die CSV-Dateidaten als DataTable
zurückgibt. Rufen Sie an und behalten Sie es in Erinnerung und Sie können damit machen, was Sie wollen.
Diese Funktion gibt die CSV-Lesedatei in DataTable zurück.
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 - Verwenden Sie diese Funktion, um die abgerufene Datentabelle in die SQL-Tabelle einzufügen.
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);
}
}
Es gibt eine andere Möglichkeit, CSV per Programmierung in die Datenbank zu laden. Cinchoo ETL , eine Open Source-Bibliothek kann die Aufgabe übernehmen, CSV-Dateien mithilfe von DataReader in die Datenbank zu laden. Dabei handelt es sich um einen Streaming-Ansatz mit wenig bis gar keinem Speicheraufwand.
Hier ist ein Beispiel, wie es geht
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());
}
}
Der beste Weg, große CSV-Dateien in SQL Server zu importieren, ist die Verwendung von SqlBulkCopy
zusammen mit der Implementierung von IDataReader
. Das Gute daran ist, dass Sie nicht die gesamte Datei in den Arbeitsspeicher lesen (was beim DataTable-Ansatz der Fall ist) und Sie können die Größe des Stapels steuern, der an SQL Server gesendet wird. Das Schlechte daran ist, dass Sie IDataReader
implementieren müssen, eine der längsten MS-Schnittstellen, die ich je gesehen habe.
Ich habe ein Nuget-Paket geschrieben, das den Trick für Sie erledigt. Es verwendet das awesome CsvHelper - Paket, so dass sehr wenige Konfigurationsschritte erforderlich sind. Das einfachste Szenario würde folgendermaßen aussehen:
//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);
Es gibt auch zusätzliche Konfigurationsoptionen für komplexere Szenarien (flexible Spaltenzuordnung, zusätzliche statische Spaltenwerte, die nicht in der CSV-Datei enthalten sind, Werttransformation.) Wenn Sie daran interessiert sind, ist das Projekt auf Github und als nuget-Paket verfügbar .
Als Referenz verwenden Sie SqlBulkCopy
mit IDataReader
:
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();
}
}
}
}
Das klingt nach einem perfekten Job für SSIS. Es ist ein kostenloser Teil von SQL Server, kann alle CSV-Dateien in einem Ordner durchlaufen, ist sehr schnell und verfügt über eine hervorragende Fehlerbehandlung und Protokollierung.
Diese Technik verwendet die SQLBulkCopy () - Funktion, liest jedoch nicht die gesamte Datei in den Arbeitsspeicher.
Der Trick besteht darin, dass eine IDataReader-Klasse zum Lesen der CSV-Datei implementiert wird.
https://www.codeproject.com/Tips/1029831/Fast-and-Simple-IDataReader-Implementation-to-Read
Verwenden Sie System.Data.SqlClient.SqlBulkCopy class, um Daten in SQL-Tabellen einzufügen. Um diese Klasse verwenden zu können, müssen Sie auch CVS-Daten in DataTable konvertieren. Siehe hier eine der Möglichkeiten.
Sie können auch Bulk Insert
verwenden.
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
Seien Sie hier jedoch vorsichtig, da Tabellenname und CSV-Name identisch sein müssen und die Spaltenanzahl in der CSV mit der in der vordefinierten Tabelle übereinstimmen muss.
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;
}
}