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;
  • 相关阅读:
    Mayan游戏 (codevs 1136)题解
    虫食算 (codevs 1064)题解
    靶形数独 (codevs 1174)题解
    黑白棋游戏 (codevs 2743)题解
    神经网络 (codevs 1088) 题解
    The Rotation Game (POJ 2286) 题解
    倒水问题 (codevs 1226) 题解
    银河英雄传说 (codevs 1540) 题解
    生日蛋糕 (codevs 1710) 题解
    第一章 1.11 高阶函数
  • 原文地址:https://www.cnblogs.com/ssqhan/p/7399900.html
Copyright © 2011-2022 走看看