最近學習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;