在SQL中,我们通常会像这样对数据表进行批量插入操作:
SqlBulkCopy copy = new SqlBulkCopy(sqlCon);
copy.DestinationTableName = strDestinationTable;
copy.WriteToServer(dtFrom);
Blockquote
但在PostgreSQL中如何执行此操作
在SQL中,我们通常会像这样对数据表进行批量插入操作:
SqlBulkCopy copy = new SqlBulkCopy(sqlCon);
copy.DestinationTableName = strDestinationTable;
copy.WriteToServer(dtFrom);
Blockquote
但在PostgreSQL中如何执行此操作
您的项目将需要引用以下程序集:Npgsql
。如果此引用在Visual Studio中不可见,则:
GACInstall.exe
CREATE TABLE "OrderHistory"
(
"OrderId" bigint NOT NULL,
"TotalAmount" bigint,
CONSTRAINT "OrderIdPk" PRIMARY KEY ("OrderId")
)
WITH (
OIDS=FALSE
);
ALTER TABLE "OrderHistory"
OWNER TO postgres;
GRANT ALL ON TABLE "OrderHistory" TO postgres;
GRANT ALL ON TABLE "OrderHistory" TO public;
ALTER TABLE "OrderHistory" ALTER COLUMN "OrderId" SET (n_distinct=1);
GRANT SELECT("OrderId"), UPDATE("OrderId"), INSERT("OrderId"), REFERENCES("OrderId") ON "OrderHistory" TO public;
GRANT SELECT("TotalAmount"), UPDATE("TotalAmount"), INSERT("TotalAmount"), REFERENCES("TotalAmount") ON "OrderHistory" TO public;
请务必使用以下指令:
using Npgsql;
using NpgsqlTypes;
将以下源代码输入到您的方法中:
// Make sure that the user has the INSERT privilege for the OrderHistory table.
NpgsqlConnection connection = new NpgsqlConnection("PORT=5432;TIMEOUT=15;POOLING=True;MINPOOLSIZE=1;MAXPOOLSIZE=20;COMMANDTIMEOUT=20;COMPATIBLE=2.2.4.3;DATABASE=test;HOST=127.0.0.1;PASSWORD=test;USER ID=test");
connection.Open();
DataSet dataSet = new DataSet();
NpgsqlDataAdapter dataAdapter = new NpgsqlDataAdapter("select * from OrderHistory where OrderId=-1", connection);
dataAdapter.InsertCommand = new NpgsqlCommand("insert into OrderHistory(OrderId, TotalAmount) " +
" values (:a, :b)", connection);
dataAdapter.InsertCommand.Parameters.Add(new NpgsqlParameter("a", NpgsqlDbType.Bigint));
dataAdapter.InsertCommand.Parameters.Add(new NpgsqlParameter("b", NpgsqlDbType.Bigint));
dataAdapter.InsertCommand.Parameters[0].Direction = ParameterDirection.Input;
dataAdapter.InsertCommand.Parameters[1].Direction = ParameterDirection.Input;
dataAdapter.InsertCommand.Parameters[0].SourceColumn = "OrderId";
dataAdapter.InsertCommand.Parameters[1].SourceColumn = "TotalAmount";
dataAdapter.Fill(dataSet);
DataTable newOrders = dataSet.Tables[0];
DataRow newOrder = newOrders.NewRow();
newOrder["OrderId"] = 20;
newOrder["TotalAmount"] = 20.0;
newOrders.Rows.Add(newOrder);
DataSet ds2 = dataSet.GetChanges();
dataAdapter.Update(ds2);
dataSet.Merge(ds2);
dataSet.AcceptChanges();
connection.Close();
原始帖子没有提到性能要求。要求解决方案必须:
DataTable
进行插入如果您正在插入大量数据,则建议您查看性能选项。 Postgres文档建议您:
COPY
命令有关优化Postgres插入的更多信息,请参见:
此外,还有许多其他因素会影响系统的性能。要了解高级介绍,请参见:
Copy
命令?
Npgsql
连接器的源代码并添加自己的BulkCopy()
方法。请确保首先查看源代码的许可协议。Postgres
函数中,该函数可以直接将数据插入目标。我也发现,目前还没有“即用型”解决方案。也许你可以查看我的另一个答案,在其中我描述了一个小助手,可以轻松地利用另一个助手来解决这个问题:https://dev59.com/DW025IYBdhLWcg3wjGtO#46063313 我认为这是目前最好的解决方案。 我在帖子中发布了链接中的解决方案,以防帖子失效。
编辑: 最近我遇到了类似的问题,但我们使用的是Postgresql。我想使用有效的批量插入,结果证明这相当困难。我没有找到任何适用于此数据库的免费库。我只找到了这个助手: https://bytefish.de/blog/postgresql_bulk_insert/ 它也在Nuget上。我编写了一个小映射器,自动映射属性的方式就像Entity Framework:
public static PostgreSQLCopyHelper<T> CreateHelper<T>(string schemaName, string tableName)
{
var helper = new PostgreSQLCopyHelper<T>("dbo", "\"" + tableName + "\"");
var properties = typeof(T).GetProperties();
foreach(var prop in properties)
{
var type = prop.PropertyType;
if (Attribute.IsDefined(prop, typeof(KeyAttribute)) || Attribute.IsDefined(prop, typeof(ForeignKeyAttribute)))
continue;
switch (type)
{
case Type intType when intType == typeof(int) || intType == typeof(int?):
{
helper = helper.MapInteger("\"" + prop.Name + "\"", x => (int?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type stringType when stringType == typeof(string):
{
helper = helper.MapText("\"" + prop.Name + "\"", x => (string)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type dateType when dateType == typeof(DateTime) || dateType == typeof(DateTime?):
{
helper = helper.MapTimeStamp("\"" + prop.Name + "\"", x => (DateTime?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type decimalType when decimalType == typeof(decimal) || decimalType == typeof(decimal?):
{
helper = helper.MapMoney("\"" + prop.Name + "\"", x => (decimal?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type doubleType when doubleType == typeof(double) || doubleType == typeof(double?):
{
helper = helper.MapDouble("\"" + prop.Name + "\"", x => (double?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type floatType when floatType == typeof(float) || floatType == typeof(float?):
{
helper = helper.MapReal("\"" + prop.Name + "\"", x => (float?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type guidType when guidType == typeof(Guid):
{
helper = helper.MapUUID("\"" + prop.Name + "\"", x => (Guid)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
}
}
return helper;
}
var undertakingHelper = BulkMapper.CreateHelper<Model.Undertaking>("dbo", nameof(Model.Undertaking));
undertakingHelper.SaveAll(transaction.UnderlyingTransaction.Connection as Npgsql.NpgsqlConnection, undertakingsToAdd));
我展示了一个使用事务的例子,但也可以使用从上下文检索到的普通连接来完成。undertakingsToAdd是普通实体记录的可枚举集合,我想将其批量插入到数据库中。
这个解决方案是我在几个小时的研究和尝试后得出的,正如你所期望的那样,它更快,最终易于使用和免费!我真的建议您使用此解决方案,不仅因为上面提到的原因,而且因为这是唯一一个我在Postgresql本身方面没有问题的解决方案,许多其他解决方案例如SqlServer都可以无缝运行。
COPY
命令,将数据导入到csv
文件中(避免使用datatable),然后再从csv
文件中使用COPY
命令将它们复制到表中。 - Vivek S.CSV
格式,然后插入到所需的位置。或者不这样做? - Amirhossein Mehrvarzi