Npgsql实现Postgresql数据库表的批量导入及导出(Bulk Copy)_postgresql bulk copy-程序员宅基地

技术标签: postgresql  数据库  

我们知道在ADO.NET中有“System.Data.SqlClient.SqlBulkCopy类”专门针对SQL Server的批导入表数据操作(Bulk Copy),而针对Postgresql的Npgsql并无相应的类,Npgsql实现Bulk Copy是通过Copy指令实现的,详细可以参考Npgsql官网对Bulk Copy的说明https://www.npgsql.org/doc/copy.html  (如果想更多了解关于Copy指令的语法可以阅读https://www.postgresql.org/docs/current/sql-copy.html)。

以下是C#中实现批量导入表格数据的通用方法(导出方法请阅读官网相关说明,此处略过):

public void BulkCopy(string tableName, DataTable dt)
        {    
            List<string> lsColNames = new List<string>();
            for (int i = 0; i < dt.Columns.Count; i++)
            {
                lsColNames.Add($"\"{dt.Columns[i].ColumnName}\"");
            }
            string copyString = $"COPY \"{tableName}\" ( {string.Join(",", lsColNames) } ) FROM STDIN (FORMAT BINARY)";
            using (NpgsqlConnection conn = (NpgsqlConnection)_DB.CreateConnection())
            {
                if (conn.State == ConnectionState.Closed)
                    conn.Open();
                var writer = conn.BeginBinaryImport(copyString);
                foreach (DataRow row in dt.Rows)
                {
                    writer.StartRow();
                    IEnumerable<KeyValuePair<string, JToken>> JRowData = DataConvert.ToJObject(row);
                    foreach (var kvp in JRowData)
                    {
                        NpgsqlParameter colParam = GetParameter(tableName, kvp);
                        writer.Write(colParam.Value, colParam.NpgsqlDbType);
                    }                    
                }
                writer.Complete();
                conn.Close();
            }
        }

以下是上例中涉及的有关获取各字段作参数的类型与值的方法:

        public NpgsqlParameter GetParameter(string tableName, KeyValuePair<string,JToken> columnValuePair)
        {
            string columnDBypeName = _DBTableDefProvider.GetTableColumn(tableName, columnValuePair.Key).data_type.ToLower();           

            NpgsqlParameter p = new NpgsqlParameter("@" + columnValuePair.Key,
                    columnDBypeName == "timestamp" || columnDBypeName == "timestamp without time zone" ? NpgsqlDbType.Timestamp
                        : columnDBypeName == "timestamp with time zone" ? NpgsqlDbType.TimestampTz
                        : columnDBypeName == "date" ? NpgsqlDbType.Date
                        : columnDBypeName=="time" || columnDBypeName == "time without time zone" ? NpgsqlDbType.Time
                        : columnDBypeName == "time with time zone" ? NpgsqlDbType.TimeTz
                        : columnDBypeName == "smallint" ? NpgsqlDbType.Smallint
                        : columnDBypeName == "integer" || columnDBypeName == "serial" ? NpgsqlDbType.Integer
                        : columnDBypeName == "bigint" || columnDBypeName == "bigserial" ? NpgsqlDbType.Bigint
                        : columnDBypeName == "double precision" ? NpgsqlDbType.Double
                        : columnDBypeName == "real" ? NpgsqlDbType.Real
                        : columnDBypeName == "boolean" ? NpgsqlDbType.Boolean
                        : columnDBypeName == "uuid" ? NpgsqlDbType.Uuid
                        : columnDBypeName == "bit" ? NpgsqlDbType.Bit                    //eg:0|1
                        : columnDBypeName == "json" ? NpgsqlDbType.Json
                        : columnDBypeName == "money" ? NpgsqlDbType.Money
                        : columnDBypeName == "numeric" ? NpgsqlDbType.Numeric
                        : columnDBypeName == "bit varying" ? NpgsqlDbType.Varbit        //eg:01010101
                        : columnDBypeName == "text" ? NpgsqlDbType.Text
                        : columnDBypeName == "character varying" ? NpgsqlDbType.Varchar    //NpgsqlDbType.Varchar可以直接用NpgsqlDbType.Text
                        : columnDBypeName == "\"char\"" || columnDBypeName == "character" ? NpgsqlDbType.Char   //NpgsqlDbType.Char可以直接用NpgsqlDbType.Text
                        //: columnDBypeName == "array" ? NpgsqlDbType.Array|NpgsqlDbType.Json //ARRAY需要匹配各个基础类型的Array,且不能直接以string传值,不常用不做处理
                        : columnDBypeName == "interval" ? NpgsqlDbType.Interval
                        //: NpgsqlDbType.Text); 
                        : NpgsqlDbType.Unknown);
            p.Value = columnValuePair.Value.Type == JTokenType.Null ? DBNull.Value
                    : columnDBypeName.StartsWith("timestamp") || columnDBypeName == "date" || columnDBypeName.StartsWith("time") ? Convert.ToDateTime(((JValue)columnValuePair.Value).Value)
                    : columnDBypeName == "smallint" ? Convert.ToInt16(columnValuePair.Value)
                    : columnDBypeName == "integer" || columnDBypeName == "serial" ? Convert.ToInt32(((JValue)columnValuePair.Value).Value)
                    : columnDBypeName == "bigint" || columnDBypeName == "bigserial" ? Convert.ToInt64(((JValue)columnValuePair.Value).Value)
                    : columnDBypeName == "double precision" ? Convert.ToDouble(((JValue)columnValuePair.Value).Value)
                    : columnDBypeName == "real" ? Convert.ToSingle(((JValue)columnValuePair.Value).Value)
                    : columnDBypeName == "boolean" ? Convert.ToBoolean(((JValue)columnValuePair.Value).Value)
                    : columnDBypeName == "uuid" ? Guid.Parse((string)columnValuePair.Value)
                    : columnDBypeName == "bit" ? Convert.ToString(Convert.ToInt32(columnValuePair.Value), 2).Last().ToString()
                    : columnDBypeName == "json" ? JObject.Parse((string)columnValuePair.Value).ToString()
                    : columnDBypeName == "money" || columnDBypeName == "numeric" ? Convert.ToDecimal(((JValue)columnValuePair.Value).Value)
                    : columnDBypeName == "text"|| columnDBypeName == "character varying" || columnDBypeName == "character" ? (string)columnValuePair.Value
                    : columnDBypeName == "interval" ? TimeSpan.Parse(Regex.Replace((string)columnValuePair.Value, "days?",".",RegexOptions.IgnoreCase).Replace(" ",""))
                    : (object)(string)((JValue)columnValuePair.Value).Value;
            return p;
        }

 以下是查询Postgresql表格与字段信息的SQL:

select
    --col.table_schema,
    col.table_name,
    col.column_name,
    (case when col.column_default like 'nextval(%' then true else false end) as is_serial,
    --col.is_generated,
    (case when col.is_nullable='NO' then false else true end) as is_nullable,
    (case when con.contype is not null then true else false end) as is_primarykey,
    --con.contype ,
    col.data_type,
    col.character_maximum_length
from information_schema.columns col 
inner join pg_class cls on col.table_name=cls.relname
left join pg_constraint con on cls.oid=con.conrelid and con.contype='p' and array_position(con.conkey::integer[],col.ordinal_position::integer)>0
where col.table_schema = 'public'
order by col.table_name,col.ordinal_position;

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/carcarrot/article/details/106850699

智能推荐

十六进制颜色值和ARGB颜色值的转换_十六进制argb-程序员宅基地

文章浏览阅读2.9k次。#include typedef struct ARGB{int alpha;int red;int green;int blue;}color, *pcolor;//将十六进制转化为ARGBcolor hex_to_argb( int colo_十六进制argb

vs2017 Nuget无法连接到远程服务器_.net core nuget无法连接到远程服务器-程序员宅基地

文章浏览阅读1.4k次。Nuget无法连接到远程服务器解决办法:找到ie浏览器选择internet选项还原高级设置最后重启一下电脑就解决问题了_.net core nuget无法连接到远程服务器

vscode上配置Arduino遇到Select the main sketch file问题_为什么arduino保存的`.ino`文件必须位于相同名称的文件夹中才能打开?-程序员宅基地

文章浏览阅读899次。在arduino上保存一个ino文件,必须将它放在一个同名文件夹中,就算你不放,下次用arduino打开还是会生成一个这样的文件夹。在vscode中,每次upload,都让我选一个sketch,而且选项只有ino文件,也不懂是什么意思。而且,选了一个之后就不能再运行其他的ino文件了。最终,我在https://github.com/czgtest/vscode-arduino中,发现:也就是说,vscode下运行每个ino的文件都要一个在一个专有的文件夹下,带着专有的arduino.json文件运行。_为什么arduino保存的`.ino`文件必须位于相同名称的文件夹中才能打开?

开源短剧播放小程序,带完整搭建教程_短剧小程序 开源-程序员宅基地

文章浏览阅读728次。大家好啊,罗峰又老给大家分享好用的小程序了。大家都喜欢看短剧吧,相比传统网剧冗长的剧情,微短剧最大的看点,是时长短、高浓缩,顺应了当下用户娱乐时间碎片化趋势。其故事题材多为赘婿、霸道总裁、穿越、重生等看似夸张、无厘头,但却非常“上头”的虚构内容。_短剧小程序 开源

如何让健康成为生活的重要组成部分?这份指南教你享受健康生活!_健康应用程序如何成为现代人生活的重要组成部分-程序员宅基地

文章浏览阅读177次。如何有效果地保持终生健康:全网最全面实用易懂的健康指南,内含具体贴心细节不容错过_健康应用程序如何成为现代人生活的重要组成部分

LA 2038 Strategic game 树形DP ._la 2038战略游戏-程序员宅基地

文章浏览阅读243次。题目地址:http://vjudge.net/problem/UVALive-2038 以前做过类似的题 就是,无根转有根 然后普通的DP d[u][i] 表示u节点的父亲有没有被选中,i==1表示被选中,反之没有 为什么弄u的父节点呢,因为 如果弄u的节点信息,那么当u没被选中,子结点至少有一个要被选中,那么只能枚举被选中的那个,无法递推,有后效性#include

随便推点

大型转码连续剧之——辣条自学Python勇闯数据科学(一)前期准备与理解编程-程序员宅基地

文章浏览阅读747次,点赞23次,收藏12次。各位大佬好,欢迎收看大型转码连续剧之——的第一集。首先做个自我介绍,辣条是一个刚从经济学转码来的菜鸟,也刚开始在CSDN平台上发帖。这不今年9月准备去读个硕,去年刚本科毕业的辣条得提前学点儿数据科学相关的知识。和ChatGPT聊了聊,这哥们儿建议辣条学个以提升专业技能,那咱就好好学一下。这Gap Year也算是给自己找了个事儿干,学点干货,笔记记在这儿。

慕课哈工大C语言程序设计精髓(第5周练兵区)_判断一个整型数据有几位v2.0 从键盘输入一个整型数据(int型),用switch语句和循环-程序员宅基地

文章浏览阅读2.3k次,点赞2次,收藏8次。1判断一个整型数据有几位v2.0(4分)从键盘输入一个整型数据(int型),编写程序判断该整数共有几位,并输出包含各个数字的个数。例如,从键盘输入整数16644,该整数共有5位,其中有1个1,2个6,2个4。程序运行结果示例1:Please enter the number:1222612226: 5 bits1: 12: 36: 1程序运行结果示例2:Please ent..._判断一个整型数据有几位v2.0 从键盘输入一个整型数据(int型),用switch语句和循环

Scrapy 安装介绍以及基本操作_怎么安装scrapy无pip-程序员宅基地

文章浏览阅读6.2w次,点赞38次,收藏179次。在写之前我们先来了解一下什么是Scrapy?Scrapy是用纯Python实现一个为了爬取网站数据、提取结构性数据而编写的应用框架,用途非常广泛框架的力量,用户只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页内容以及各种图片,非常之方便Scrapy 使用了 Twisted['twɪstɪd](其主要对手是Tornado)异步网络框架来处理网络通讯,可以加快我们的下载速度,不..._怎么安装scrapy无pip

Linux下九个实用脚本_linux脚本-程序员宅基地

文章浏览阅读1.9k次,点赞3次,收藏6次。root@ansible ~]# watch -n 1 sh sd.sh 加上watch -n 1 来判断网卡实时流量。if [ "$RT" -gt 250 ] 限定次数250 超过就屏蔽。echo "网站$URL坏掉,请及时处理"echo "网站高危$URL"echo "磁盘已经沾满不能存储数据!echo "$name 创建成功"echo "$name 创建成功"echo "等待磁盘IO响应使用率: $LL"不过要退出 watch 才会使IP屏蔽。_linux脚本

【Bug解决】ImportError: C extension: No module named ‘pandas._libs.tslibs.base‘ not built._importerror: c extension: none not built. if you w-程序员宅基地

文章浏览阅读4.3k次,点赞6次,收藏11次。问题描述笔者用Pyinstaller打包成exe文件,在其他电脑端运行时出现如下问题ImportError: C extension: No module named 'pandas._libs.tslibs.base' not built. If you want to import pandas from the source directory, you may need to run 'python setup.py build_ext --force' to build the C exten_importerror: c extension: none not built. if you want to import pandas from

tf.tile,tf.gather,t f.concat,t f .expand_dims,tf.add_n, tf.stack,tf.sparse_to_dense_tf add_n concat-程序员宅基地

文章浏览阅读345次。temp = tf.range(0,10)*10 + tf.constant(1,shape=[10])temp2 = tf.gather(temp,[1,5,9])with tf.Session() as sess: print (sess.run(temp)) print (sess.run(temp2))输出结果[ 1 11 21 31 41 51 61 ..._tf add_n concat