儲存過程 動態sql 將動態列名作為變數傳值

2021-09-22 12:38:19 字數 2610 閱讀 8023

背景:這兩天有個需求,每天並且每10分鐘從es取一次資料(每次大概五萬多條車輛資料),每台車有veh,vom兩欄位,vom為車輛狀態資訊(會改變),每十分鐘都要記錄一次車輛狀態,將此資訊存在資料庫的veh_state表裡面。

再將這些資料用echarts表現出來(後話)。

所以,資料庫表的列名定為:veh,date,vom1,vom2,vom3,vom4....vom144;(vom1是凌晨0:00,vom2是0:10...直到 vom144是23:50)。

方案一:

第一次從es取出資料後,直接存到veh_state裡面,有資料的列是veh,date,vom1,第二次取es的資料時(凌晨0:20),做更新操作,將vom2這列的資料update到veh_state裡面。

問題是每次五萬多條資料做更新,無論是一次性提交還是分批次(500條/次)提交,耗時都在十分鐘左右,這肯定是不行的。

方案二:

建兩個表,正式表veh_state和臨時表veh_state_temp,每次從es查的資料都往veh_state_temp插入,包括第一次。然後寫個儲存過程,每次用veh_state_temp和veh_state做比對,veh和date欄位都相同的,則更新這條資料的vom?狀態,如果veh不存在且date欄位相同(說明當天這次從es查的資料比上次查的資料多了幾條車輛資料),則插入這條資料。最後再刪除veh_state_temp臨時表的資料。

臨時表veh_state_temp的字段就沒有144個vom,只有veh,date,vom三個字段。(這裡萬分感謝公司范姓大佬)

儲存過程:

create or replace procedure p_es_vehicle_state(vomnum nvarchar2) as

cdate number;

begin

declare

cursor cur_vehicle is

select * from veh_state_temp; --宣告游標

ve_vehicle veh_state_temp%rowtype; --宣告行變數

sqlstr varchar2(500);

begin

open cur_vehicle;

loop

fetch cur_vehicle

into ve_vehicle; --提取游標 獲取記錄值

exit when cur_vehicle%notfound; --退出迴圈條件

-- 判斷臨時表是否存在相應的車輛資料

select count(0)

into cdate

from veh_state t

where t.veh = ve_vehicle.veh

and t.date = ve_vehicle.date;

if cdate = 1 then

-- 更新資料

sqlstr := ' update veh_state t set t.' || vomnum ||' =:1 where t.vin = :2 and t.date =:3';

execute immediate sqlstr using ve_vehicle.vom, ve_vehicle.veh, ve_vehicle.date; --ve_vehicle.vom這個值,如果列名vom是變數 該怎麼賦值?

commit;

elsif cdate = 0 then

--插入資料

sqlstr := 'insert into veh_state t (t.veh, t.date, t.' ||vomnum || ') values (:1, :2, :3)';

execute immediate sqlstr using ve_vehicle.veh, ve_vehicle.date, ve_vehicle.vom;

commit;

end if;

end loop;

close cur_vehicle;

--刪除臨時表

delete from veh_state_temp;

end;

end;

我寫的這個   --ve_vehicle.vom這個值,如果列名vom是變數 該怎麼賦值?  

是因為之前建臨時表的時候,完整的建了144個vom,然後將這列作為變數。網上找了很多辦法,包括使用了dbms_sql包也沒有實現這個功能,想的是以後萬一有這個需求了,改怎麼實現。如果有大佬知道,希望給點提示。因為在using後面不能傳declare 後面定義的字段。例如定義變數 vom:='vom'||vomnum (如果是第20分鐘,這裡的vom就是vom2),但是這種方式會報字字段錯誤。也不能像'||vom||'這樣拼接在sqlstr裡面,也報同樣的錯誤。

就寫在這裡吧,後續可能還會補充----

***********************************=補充分割線******************************

用儲存過程實現兩個表對比,有則更新無則增的需求,很慢,需要900秒+,所以這也是不行的。查了很多方法,改游標,用for in loop迴圈 也是很慢。最後新增索引,速度快了很多。索引新增方法網上很多,我就不再贅述了。

oralce儲存過程使用動態sql

在儲存過程中,我想根據條件拼裝sql,這個時候select xx into v xx這樣就不行了,返回不了值。要使用 execute immediate v sql into v access number create or replace procedure p access user v st...

oracle 儲存過程 呼叫動態sql

開始時間拼接 00 00 00 v sql select decode length v end 10,concat v end 00 00 00 v end from dual execute immediate v sql 編譯成功,但是儲存過程呼叫失敗。在oracl資料庫中,ddl表示資料庫定...

oracle 儲存過程 呼叫動態sql

開始時間拼接 00 00 00 v sql select decode length v end 10,concat v end 00 00 00 v end from dual execute immediate v sql 編譯成功,但是儲存過程呼叫失敗。在oracl資料庫中,ddl表示資料庫定...