SQL*Plus、@ 和相對路徑
不知何故,似乎 SQL*Plus(至少在 Windows 上)在使用相對路徑呼叫
@@
以及路徑以單點或雙點開頭時無法找到具有相對路徑的腳本。例如,在
x:\some\where
我有以下目錄結構:script.sql main-dir\main-sub-dir call-script.sql script.sql
即:兩個
script.sql
但在不同的位置。
script.sql
剛剛下的內容x:\some\where
簡直了prompt SCRIPT root
而對方
script.sql
的內容是prompt SCRIPT main-dir/main-subdir
call-script.sql
讀@@script.sql @ script.sql
預期產出
如果我從啟動 SQL*Plus
x:\some\where
然後執行@main-dir/main-sub-dir/call-scripts
輸出將是
SCRIPT main-dir/main-subdir SCRIPT root
這是意料之中的,因為單曲
@
應該搜尋 SQL*Plus 啟動@@
的路徑,並且應該搜尋包含腳本目錄的路徑。意外輸出
現在,如果我
call-scripts.sql
這樣改變:@@./script.sql @ ./script.sql
double
@@
似乎改變了它的行為,因為它搜尋 SQL*Plus 啟動的路徑,現在輸出將是SCRIPT root SCRIPT root
這不是我所期望的。
這種行為是否記錄在某處,更重要的是,我必須如何更改
call-scripts.sql
才能正確呼叫相對路徑(@@../../other-dir/other-sub-dir/script
)?
是的,這是已經存在很長時間的錯誤 2391334,並且可能在不久的將來不會修復。
解決此問題的一種方法是“知道”腳本的路徑,而無需實際對該路徑進行硬編碼。在 SQLPlus 中執行此操作需要一個技巧 - 如果您嘗試執行一個不存在的文件,那麼您將收到一條包含路徑名的錯誤消息。
所以這裡有一個實際的展示。為了模仿你的場景,我有:
c:\temp\demo script.sql maindir subdir call_script.sql script.sql
我們可以做的是在 call_script.sql 的前面添加一些命令來獲取路徑。它看起來有點奇怪,但您不需要更改它 - 它只是您粘貼的固定內容
set termout off spool _path_finder.sql @@_nonexistent_script.sql spool off; var path varchar2(100); set serverout on declare output varchar2(1000) := regexp_replace(replace(q'{ @_path_finder.sql }',chr(10)),'.*"(.*)".*','\1'); begin :path:=substr(output,1,length(output)-24); end; / col path new_val path select :path path from dual; set termout on
這裡發生了什麼,我們正在執行一個不存在的腳本,它返回:
“SP2-0310: 無法打開文件 “path_nonexistent_script.sql”
因此,使用一點正則表達式,我們可以提取路徑,將其儲存在 SQLPlus 變數中,然後從那時起使用。
所以你的 call_script.sql 的最終版本看起來像這樣
set termout off spool _path_finder.sql @@_nonexistent_script.sql spool off; var path varchar2(100); set serverout on declare output varchar2(1000) := regexp_replace(replace(q'{ @_path_finder.sql }',chr(10)),'.*"(.*)".*','\1'); begin :path:=substr(output,1,length(output)-24); end; / col path new_val path select :path path from dual; set termout on prompt path was &path @@&path\script.sql @&path\script.sql
當我們執行它時,我們得到以下資訊
SQL> @maindir\mainsubdir\call_script path was maindir\mainsubdir script in subdir script in subdir
你去吧:-)