使用C#将大型csv
数据文件上传到SQL服务器的最佳方法是什么?该文件包含大约30,000行和25列。
答案 0 :(得分:44)
第一关,你不需要编程。您可以使用SQL管理工具将CSV文件直接上载到SQL数据库中。但是,如果您真的需要通过编程来完成,请阅读以下内容。
就个人而言,我认为这种方法是通过编程实现的最有效和最简单的方法。
通常,您可以分两步完成
第一个步骤是读取CSV文件并将记录保存为DataTable
。
第二个步骤将检索到的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 - 使用此函数将Retrieved 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);
}
}
答案 1 :(得分:3)
这是通过编程将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());
}
}
答案 2 :(得分:3)
我发现将大型CSV文件导入SQL Server的最佳方法是使用SqlBulkCopy
和IDataReader
实现。这样做的好处是,您无需将整个文件读入内存(使用DataTable方法就是这种情况),并且您可以控制发送到SQL Server的批处理的大小。不好的是,您必须实现IDataReader
,这是我见过的最长的MS接口之一。
我写了一个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使用。
作为参考,以下是将SqlBulkCopy
与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();
}
}
}
}
答案 3 :(得分:1)
使用System.Data.SqlClient.SqlBulkCopy类将数据插入Sql表。 要使用该类,您还需要将CVS数据转换为DataTable,请参阅here其中一种方法。
答案 4 :(得分:1)
这听起来像是SSIS的完美工作。它是SQL Server的免费部分,可以遍历文件夹中的所有csv文件,速度非常快,并且具有出色的错误处理和日志记录。
答案 5 :(得分:1)
此技术使用SQLBulkCopy()工具,但不会将整个文件读入内存。
诀窍是它实现了一个IDataReader类来读取.csv文件。
https://www.codeproject.com/Tips/1029831/Fast-and-Simple-IDataReader-Implementation-to-Read
答案 6 :(得分:0)
您也可以使用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中的列数必须与预定义表中的相同。
答案 7 :(得分:0)
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;
}
}