注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

sql大数据量插入的问题之三POSTGRESQL中的COPY  

2014-04-15 11:30:55|  分类: NET(C#) |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

sql大数据量插入的问题之三POSTGRESQL中的COPY

目前的程序中需要用到PSQL中的COPY这个方法来传递大数据量。需要在底层的库里对这个进行一次封装。搞了一下午,费了许多无用功,然后完成了。

估计是人员不好,光搭开发环境就用了将近两个小时。后来想起现有的库是支持WEB的,本地库是无法使用的(调用了WEBDLL,里面也有很多WEB方面的函数,主要原因其实是一些静态变量使用了这些函数,现象是无法进行调试。)

后来把库拷走进行修改,然后才搭好环境。

PSQL的帮助里可以看到,COPY支持从文件或标准的输入输出流进行导入和导出(注意:要分清COPY命令函数和COPY这个SQL)。他的标准用法如下:

COPY table_name [ ( column_name [, ...] ) ]

    FROM { 'filename' | PROGRAM 'command' | STDIN }

    [ [ WITH ] ( option [, ...] ) ]

 

COPY { table_name [ ( column_name [, ...] ) ] | ( query ) }

    TO { 'filename' | PROGRAM 'command' | STDOUT }

    [ [ WITH ] ( option [, ...] ) ]

 

where option can be one of:

 

    FORMAT format_name

    OIDS [ boolean ]

    FREEZE [ boolean ]

    DELIMITER 'delimiter_character'

    NULL 'null_string'

    HEADER [ boolean ]

    QUOTE 'quote_character'

    ESCAPE 'escape_character'

    FORCE_QUOTE { ( column_name [, ...] ) | * }

    FORCE_NOT_NULL ( column_name [, ...] )

    ENCODING 'encoding_name'

然后写下了下面的程序:

     /// <summary>

        /// 处理COPY数据

        /// </summary>

        /// <param name="streamData">输入流</param>

        /// <returns></returns>

        public int CopyIn(string tableName,MemoryStream ms)

        {

            //byte[]转内存流前的形式"123\t123\n" 其中对应实体物理表的字段为myname(string)  mynum(int)

            using (NpgsqlTransaction ntrans = this.BeginTransaction())

            {

                try

                {

                                    

                    string commandString = "COPY " + tableName + "  from STDIN";

//下行代码在测试成功后更新到库后丢失,造成数据无法保存

this._command.CommandText = commandString;

                    this._nCopyIn = new NpgsqlCopyIn(this._command, this._connection,ms);

                    this._nCopyIn.Start();

                    ntrans.Commit();//此处在测试代码时没有

                }

                catch (NpgsqlException ne)

                {

                    string s = ne.Message.ToString();

                    this._nCopyIn.Cancel(s);

                    ntrans.Rollback();//此处在测试代码时没有

                    return -1;

                }

                finally

                {

                    this._nCopyIn.End();

                }

            }

 

            return 1;

        }

        /// <summary>

        /// 返回字节流

        /// </summary>

        /// <param name="tableName">表名称</param>

        /// <param name="ms">返回数据流</param>

        /// <returns></returns>

        public int CopyOut(string tableName,ref MemoryStream ms )

        {

            try

            {

                string cmdString = "COPY  "+tableName+"  to STDOUT";

                this._command.CommandText = cmdString;

                this._nCopyOut = new NpgsqlCopyOut(this._command, this._connection, ms);

                this._nCopyOut.Start();

            }

            catch (NpgsqlException ne)

            {

                this._nCopyOut.End();

                return -1;

            }

 

            return 1;

        }

注意到红色部分没有,特别是在开始测试时,主要考虑COPY这个用法,一直都没有注意事务的动作。所以导致下面的代码始终无法提交到数据库。甚至下来了NPGSQL的源码跟了进去,仍然啥动作都感受不到啊。人品无敌,这就是昨天下午。

using (NpgsqlTransaction ntrans = this.BeginTransaction())

{

                string strcopy = "1237\t\\N\n";

                strcopy = "2014-04-01\t187\t190\t187\t214\t214\n2014-04-02\t190\t215\t190\t215\t188\n";

                strcopy = "2014-04-01\t187\t\\N\t\\N\t\\N\t\\N\n2014-04-02\t188\t\\N\t\\N\t\\N\t\\N\n";//\\N \t

 

                byte[] tm = System.Text.Encoding.UTF8.GetBytes(strcopy);

                Stream ms = new MemoryStream(tm);

                //string commandString = @"COPY " + tableName + "  from STDIN DELIMITER '\t'";

                string commandString = "COPY xigou_leader_schedule  from STDIN ";

                this.s_npgsqlCmd.CommandText = commandString;

                //string commandString = "COPY q  from STDIN DELIMITER '\t'";

 

                this._nCopyIn = new NpgsqlCopyIn(this.s_npgsqlCmd, this.s_npgsqlCon, ms);

 

                this._nCopyIn.Start();

                ntrans.commit();----少这一行

}

开始主要是字符串组织的有一些问题,\t\n没有,然后报“mynum没有赋值”或者“myname过长”(设置了32位长度),再到后来怀疑是不是COPY的用法不对。查了帮助,也没查出个所以然来。

后来故意写一个重复的主键插入进去,然后报“违反主键约束唯一性”,说明程序已经刷到了数据库啊。就偏偏没有想到是事务没有提交的原因,一直在想是不是自己的COPY动作是不是有问题。然后又从帮助了拷了一个例程,结果更爽,这一弄,下午半天没有了,直接结果就是搞不定。对C#操作已经有大约一年不再做了,一直在搞C++,所以觉得生疏了很多,许多常用的方法都想不起来了。心中也有些感叹,怪不得老人儿们常说:拳不离手,曲不离口。诚不我欺。

后来不再想了,去问同事对PSQLCOPY动作如何用,结果试了两把不行后人家突然发现事务没有提交。这个,这个,只能是无语。

然后就是提交库,结果第二天仍然无法使用,再测试,发现了第一行红色标注那儿,命令根本没有给COMMAND赋值。这是一个令人失望的下午。

然后紧接着是空值的赋值问题,如上面的代码,需要使用\N,如何体现到字符串里要使用\\N,下面是帮助上的说明:

Backslash characters (\) can be used in the COPY data to quote data characters that might otherwise be taken as row or column delimiters. In particular, the following characters must be preceded by a backslash if they appear as part of a column value: backslash itself, newline, carriage return, and the current delimiter character.

 

The specified null string is sent by COPY TO without adding any backslashes; conversely, COPY FROM matches the input against the null string before removing backslashes. Therefore, a null string such as \N cannot be confused with the actual data value \N (which would be represented as \\N).

这里需要重点说明一下:逃逸字符没有处理,以后遇到还得重点想着,不过年岁大了,记性也不好了。呵呵。

共同努力,共同进步,共同发展,共同享受代码生活。

说明:一直到最后,也没有解决C#标准输入输出的方法来COPY执行。可能对他的写入和写出机制还是不太清楚。目前觉得主要原因就是这个。弄清楚了,估计也就解决了,这个也不是很必须,有时间以后弄一下。

  评论这张
 
阅读(710)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017