zoukankan      html  css  js  c++  java
  • postgresql 存储过程动态插入数据 2

    最近学习postgresql,正一个小活要用上,所以就开始学习了!
    然而,学习的过程极其艰辛,但却也充满了乐趣.

    一般来说数据库的操作不外如何增,删,改,查,
    而首要的就是要添加数据到数据库中,因为以前的经验,
    存储过程要比不用存储过程效率要高不少,至少我的程序环境是这样的结果!

    所以就想要做写些存储过程,如果一个表一个存储过程,那仅存储过程就得写好几百个
    这个实是有点夸张了!(这还仅是插入.加上删除/修改/查询那得近上千)

    那么能不能有个方法,可以减少工作量呢?自动根据表名,字段名及字段值与插入?
    POSTGRESQL 真的很强大!虽然我还没有入门!

    这个问题我通过测试看函数花了三整天,总算有点眉目:
    干货直接拉到最后看最后一个插入存储过程.
    下面是我的学习过程,本不想加上,可这是我一步步的做过来的.

    --
    目标:动态插入表中数据 -- 老规矩上代码 -- 插入函数如下 ---------------------------------------- CREATE OR REPLACE FUNCTION f_insert_module_string( modulename text, feildname text[], feildvalue text[], out returnValue text ) AS $$ DECLARE myid integer; ex_result integer default 0; ex_sql text; BEGIN myid:=f_getNewID(modulename,'id'); ex_sql:='insert into ' ||quote_ident(moduleName) ||'(id,' ||array_to_string(feildname,',') ||') values('||myid||',''' ||array_to_string(feildvalue,''',''') ||''')'; execute ex_sql; GET DIAGNOSTICS ex_result:= ROW_COUNT; if ex_result<>0 then returnValue:='{"SUCCESS":"插入操作'||ex_sql||'成功!"}'; else returnValue:='{"ERROR":"插入操作'||ex_sql||'失败!"}'; end if; END; $$ language plpgsql; -- 实际操作 select f_insert_module_string('test','{name,code,gen_time}','{whq,111000,2018-08-20}'); -- 得到如下结果:

    --同样,在插入时,直接用单引号把日期给引起来,INSERT 也不会报错,

    --那么如果用C#调用存储过程会不会报错呢?

    --我们拭目以待!

    ------------------------------

    --经测试没有问题!

    
    
    --下面是测试过程及改进代码
    --===================================================
    --插入数据除了 id ,其余字段全部以TEXT 格式传递
    --modulename 即为表名
    --feildname  即为字段名
    --feildvalue 即为对应的字段值(插入时全部为text)
    --这里的字段名和字段值是一一对应的关系,否则出错
    --===================================================
    CREATE OR REPLACE FUNCTION f_insert_module_string(
    modulename text,
    feildname  text[],
    feildvalue text[],
    out returnValue text ) AS $$
    DECLARE 
        myid         integer;
        ex_result    integer default 0;
        ex_sql       text;
    BEGIN
        myid:=f_getNewID(modulename,'id');
        ex_sql:='insert into '
            ||quote_ident(moduleName)
            ||'(id,'
            ||array_to_string(feildname,',')
            ||') values('||myid||','''
            ||array_to_string(feildvalue,''',''')
            ||''')';
        execute ex_sql; 
        GET DIAGNOSTICS ex_result:= ROW_COUNT; 
        if ex_result<>0 then  returnValue:='{"SUCCESS":"插入操作'||ex_sql||'成功!"}';
        else                  returnValue:='{"ERROR":"插入操作'||ex_sql||'失败!"}';
        end if;
    END;
    $$ language plpgsql;
    
    
    --===================================================
    --插入数据除了 id ,其余字段全部以 text格式传递
    --modulename 即为表名
    --feildname  即为字段名
    --feildvalue 即为对应的字段值(插入时全部以int格式)
    --这里的字段名和字段值是一一对应的关系,否则出错
    --===================================================
    CREATE OR REPLACE FUNCTION f_insert_module_string(
    modulename text,
    feildname  text[],
    feildvalue text[],
    out returnValue text ) AS $$
    DECLARE 
        myid         integer;
        ex_result    integer default 0;
        ex_sql       text;
    BEGIN
        myid:=f_getNewID(modulename,'id');
        ex_sql:='insert into '
            ||quote_ident(moduleName)
            ||'(id,'
            ||array_to_string(feildname,',')
            ||') values('||myid||','
            ||array_to_string(feildvalue,',')
            ||')';
        execute ex_sql; 
        GET DIAGNOSTICS ex_result:= ROW_COUNT; 
        if ex_result<>0 then  returnValue:='{"SUCCESS":"插入操作'||ex_sql||'成功!"}';
        else                  returnValue:='{"ERROR":"插入操作'||ex_sql||'失败!"}';
        end if;
    END;
    $$ language plpgsql;
    
    
    --===================================================
    --以下是合并以上两个过程的代码,但增加了一个类型参数
    --主要是为了区分除ID字段外,其他字段的类型
    --0: 认为其他字段以text类型插入,即加单引号
    --others: 认为其他字段以int类型插入,即没有单引号
    --那么问题来了:如果里面有int numeric text交叉怎么办?
    --可不可以这样:
    -- feildname 顺序打乱(不按表中顺序)
    -- 把不用带单引号的字段放前面
    -- 需要带引号的放后面
    --
    当然feildvalue要分成两个ARRAY了
    -- feildname1 text[]不用带单引号的字段值,
    -- feildname2 text[]需要带引号的字段值

    --我也不知道,我们将继续学习!
    --===================================================
    --插入数据除了 id ,其余字段全部以 text格式传递 --modulename 即为表名 --feildname 即为字段名 --feildvalue 即为对应的字段值 --inserttype 插入类型 如为0 则插入 text,否则直接插入 --这里的字段名和字段值是一一对应的关系,否则出错--=================================================== CREATE OR REPLACE FUNCTION f_insert_module_string( modulename text, feildname text[], feildvalue text[], inserttype integer, out returnValue text ) AS $$ DECLARE myid integer; ex_result integer default 0; ex_sql text; BEGIN myid:=f_getNewID(modulename,'id'); ex_sql:='insert into ' ||quote_ident(moduleName) ||'(id,' ||array_to_string(feildname,','); if inserttyp<>0 then ex_sql:=ex_sql||') values('||myid||',' ||array_to_string(feildvalue,',') ||')'; else ex_sql:=ex_sql||') values('||myid||',''' ||array_to_string(feildvalue,''',''') ||''')'; execute ex_sql; GET DIAGNOSTICS ex_result:= ROW_COUNT; if ex_result<>0 then returnValue:='{"SUCCESS":"插入操作'||ex_sql||'成功!"}'; else returnValue:='{"ERROR":"插入操作'||ex_sql||'失败!"}'; end if; END; $$ language plpgsql;



    --============================================
    --坑永远也填不完,上面完成的挺好的,可是当我用NPGSQL
    --parameters.add时发现根本不能传递数组!!
    --是的,我用的npgsql 是2.* for .net 4.0
    --===========================================
    --其实绕了个大弯:
    --在f_insert_test中不是用 ARRAY_TO_STRING了吗
    --为什么不直接传递一个text类型的字符串过来??
    -------------------------------------------
    --再来
    --===========================================
    --C#数据库访问部分:
     public static string ExecuteInsertProcedure(string proName, string tableName, string paramName,  string values, Int32 returnType)
        {
            string returnValue = string.Empty;
            NpgsqlConnection connection = new NpgsqlConnection(getConnectionString());
            NpgsqlCommand command = new NpgsqlCommand(proName, connection);
            command.CommandType = System.Data.CommandType.StoredProcedure;
            SP_SetParam(command, "tablename", NpgsqlDbType.Text, System.Data.ParameterDirection.Input, tableName);
            SP_SetParam(command, "feidname",NpgsqlDbType.Text, System.Data.ParameterDirection.Input, paramName);
            SP_SetParam(command, "feidvalue", NpgsqlDbType.Text, System.Data.ParameterDirection.Input, values);
            SP_SetParam(command, "inserttype", NpgsqlDbType.Integer, System.Data.ParameterDirection.Input, returnType);
            SP_SetParam(command, "returnvalue", NpgsqlDbType.Text, System.Data.ParameterDirection.Output, "");
            try
            {
                connection.Open();
                command.ExecuteNonQuery();
                returnValue = command.Parameters["returnValue"].Value.ToString();
            }
            catch (NpgsqlException exception)
            {
                throw new Exception(string.Format("执行SQL【{0}】出错,详细信息为:{1}", proName, exception.Message));
            }
            finally
            {
                connection.Close();
            }
            return returnValue;
        }
    
    
    --C#程序处理部分:
    public string insertModule(string tableName, string keys, string values, int returnType)
    {
    string jsonResult = string.Empty;
    if(string.IsNullOrEmpty(tableName)){ jsonResult = "{"ERROR":"请给出需要插入的表名!"}"; return jsonResult; }
    jsonResult = sqlHelper.ExecuteInsertProcedure("f_insert", tableName, keys,values, returnType);
    return jsonResult;
    }
    
    
    
    
    --plpgsql插入函数再改造如下
    --
    CREATE OR REPLACE FUNCTION f_insert(
    modulename text,
    feildname  text,
    feildvalue text,
    inserttype integer,
    out returnValue text ) AS $$
    DECLARE 
        myid          integer;
        ex_result     integer default 0;
        ex_sql        text;
        my_feildvalue text[];
    BEGIN
        myid:=f_getNewID(modulename,'id');
        my_feildvalue:=string_to_array(feildvalue,',');
        ex_sql:='insert into '
            ||quote_ident(moduleName)
            ||'(id,'
            ||feildname;
        if inserttype<>0  then
            ex_sql:=ex_sql||') values('||myid||','
                          ||array_to_string(my_feildvalue,',')
                          ||')';
        else 
            ex_sql:=ex_sql||') values('||myid||','''
                          ||array_to_string(my_feildvalue,''',''')
                          ||''')';
        end if;
        execute ex_sql; 
        GET DIAGNOSTICS ex_result:= ROW_COUNT; 
        if ex_result<>0 then  returnValue:='{"SUCCESS":"插入操作'||ex_sql||'成功!"}';
        else                  returnValue:='{"ERROR":"插入操作'||ex_sql||'失败!"}';
        end if;
    END;
    $$ language plpgsql;
    
    
    
    
    

    这样可以了吗? 
    是的,可以了!测试通过!
     

     干货在这里

    --============================================
    --既含有需要单引号: date,text,varchar等类型,
    --又含不需要单引号的:int,nemeric等类型
    --feildname 也要按顺序放
    --不需要单引号字段名放前面, feildValue
    --需要的放后面              feildsingle
    --inserttype=0 :表示所有插入字段不需单引号
    --           1 :表示所有插入字段需要单引号
    --           2 :表示一部分不需单引号,
    --                  一部分需要单引号
    --===========================================
    CREATE OR REPLACE FUNCTION f_insert_all(
    modulename  text,
    feildname   text,
    feildvalue  text,
    feildsingle text,
    inserttype  int,
    out returnValue text ) AS $$
    DECLARE 
        myid          integer;
        ex_result     integer default 0;
        ex_sql        text;
        my_feildvalue text[];
    BEGIN
        myid:=f_getNewID(modulename,'id');
        my_feildvalue:=string_to_array(feildvalue,',');
        ex_sql:='insert into '
            ||quote_ident(moduleName)
            ||'(id,'
            ||feildname;
        if inserttype=0  then
            ex_sql:=ex_sql||') values('||myid||','
                          ||array_to_string(my_feildvalue,',')
                          ||')';
        else if inserttype=1 then
            ex_sql:=ex_sql||') values('||myid||','''
                          ||array_to_string(my_feildvalue,''',''')
                          ||''')';
        else
            ex_sql:=ex_sql||') values('||myid||','
                          ||array_to_string(my_feildvalue,',');
            my_feildvalue:=string_to_array(feildsingle,',');
            ex_sql:=ex_sql||','''
                          ||array_to_string(my_feildvalue,''',''')
                          ||''')';
        end if;
        end if;
        execute ex_sql; 
        GET DIAGNOSTICS ex_result:= ROW_COUNT; 
        if ex_result<>0 then  returnValue:='{"SUCCESS":"插入操作'||ex_sql||'成功!"}';
        else                  returnValue:='{"ERROR":"插入操作'||ex_sql||'失败!"}';
        end if;
    END;
    $$ language plpgsql;

     怎么样。感觉这个不够好??

    最好的永远是下一个:

    drop function f_insert_all(text,text);
    create or replace function f_insert_all(
        table_name         text,       --表名
        insert_feilds      text,       --需要插入的字段和字段 [{"feild_name":"pt_name","feild_value":"我是中国人"},{"feild_name":"pt_description","feild_value":"我骄傲"}]
        out return_value   text        --返回值
    ) as $$
    declare
        ex_sql             text;
        recs               record;
        _key               text ;
        _value               text;
        ex_result           integer;
        _maxid               integer;
    begin
        --检查是否插入重复数据,如果重复,返回重复提示
        ex_result:=f_insert_check(table_name,insert_feilds);
        if ex_result<>0 then
            return_value:='{"ERROR":"插入操作失败!请检查是该记录是否已存在!"}';
        else
            _maxid:=f_getnewid(table_name,'id');
            ex_sql:='insert into '||quote_ident(table_name)||'(id';
            _value:='('||_maxid;
    
            for recs in select * from json_array_elements(insert_feilds::json)   loop
                ex_sql   := ex_sql|| ',' || (recs.value ->> 'feild_name');            --insert feilds
                if json_typeof(recs.value -> 'feild_value') ='number' then 
                    _value:=_value||','  ||(recs.value ->> 'feild_value') ;            --insert values numeric
                else 
                    _value:=_value||','''||(recs.value ->> 'feild_value')||'''' ;    --insert values not numeric
                end if;
            end loop;
            ex_sql:=ex_sql||') values'||_value||')';
            execute ex_sql; 
            GET DIAGNOSTICS ex_result:= ROW_COUNT; 
            if ex_result<>0 then  return_value:='{"SUCCESS":"插入操作'||ex_sql||'成功!","id":'||_maxid||'}';
            else                  return_value:='{"ERROR":"插入操作'||ex_sql||'失败!"}';
            end if;
            --return_value:='{"ERROR":"插入操作'||ex_result||'失败!"}';
        end if;
    end;
    $$ language plpgsql;
  • 相关阅读:
    计算机组成原理:“性能”是什么?
    试题 基础练习 Huffuman树
    最小堆的插入删除函数
    特殊函数
    进程控制
    进程的描述
    进程管理
    生成和配置Linux操作系统
    系统调用
    Shell脚本编程
  • 原文地址:https://www.cnblogs.com/ssqhan/p/7399900.html
Copyright © 2011-2022 走看看