背景:這兩天有個需求,每天並且每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表示資料庫定...