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;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM