Oracle

如何在 shell 腳本中保留 sqlplus 會話

  • May 15, 2017

我正在嘗試使用 sqlplus 在 shell 腳本中插入來自 sql 文件的查詢。現在,由於架構不正確,某些查詢可能會失敗。所以我只想在所有查詢都成功的情況下送出所有事務。主要問題是,我想執行所有查詢而不考慮任何錯誤,如果至少有一個錯誤,則回滾所有查詢。

執行所有查詢背後的想法是找到會出錯的查詢並為其創建模式修復。

我正在使用這個命令:

cat "temp.sql" | sqlplus -s sys/oracle@xe as sysdba  

但是一旦 sqlplus 退出,這將自動送出。set exitcommit off因為我使用的是 11.1,所以我 無法使用。

有沒有辦法在shell腳本中做到這一點?

初步說明

你發出聲明

cat "temp.sql" | sqlplus -s sys/oracle@xe as sysdba  
  1. 您應該避免使用管道進入 sqlplus。更好地執行

sqlplus -s sys/oracle@xe as sysdba @temp.sql

一個優點是不會在輸出文件中生成提示。您可以更好地控制輸出的外觀。某些輸入將產生在互動工作時有意義但在執行批處理作業時沒有意義的結果。我看不到將命令傳遞給 sqlplus 的任何優勢。

  1. 您不應該使用 SYS 來處理應用程序對象和應用程序數據。有很多安全原因。除此之外,你應該知道

SYS 的查詢將返回事務期間所做的更改,即使 SYS 已將事務設置為只讀

如果您發出 DML 語句,則不會出現這種情況。這會使您的數據不一致。

  1. 手冊

您可以使用 SQL 數據庫操作語言 (DML) 命令 UPDATE、INSERT 和 DELETE 指定您希望對儲存在數據庫中的資訊進行的更改,這些命令可以單獨使用,也可以在 PL/SQL 塊中使用。在您輸入 SQL COMMIT 命令或 SQL 數據庫控制語言 (DCL) 或數據庫定義語言 (DDL) 命令(例如 CREATE TABLE)或使用自動送出功能之前,這些更改不會永久生效。SQL*Plus 自動送出功能導致在指定數量的成功 SQL DML 事務之後送出掛起的更改。(SQL DML 事務可以是 UPDATE、INSERT 或 DELETE 命令,也可以是 PL/SQL 塊。)

因此,您的腳本必須包含正確的語句,以便可以回滾所有語句。


SET EXITCOMMAND在 11.2 中被引入到 SQLPlus。我不認為它為 SQLPlus 添加了一些真正的新東西。您可以使用 WHENEVER 命令來控制 SQL*Plus 行為。

只有當所有查詢都成功時,我才想送出所有事務

所以我假設如果發生第一個錯誤,你想回滾並退出。

因此,您應該使用WHENEVER SQLERROR語句開始您的腳本

WHENEVER SQLERROR EXIT FAILURE ROLLBACK

如果發生 SQL 錯誤,事務將回滾並退出 SQLPlus。SQLPlus 是 OS 系統相關值的錯誤程式碼,表示錯誤

也許也應該執行WHENEVER OSERROR命令

WHENEVER OSERROR EXIT FAILURE ROLLBACK

當然AUTOCOMMIT不應該啟用,但是

SET AUTOCOMMIT OFF

是預設的,所以你不能執行這個命令。

您可以將這些語句添加到站點配置文件或使用者配置文件腳本(glogin.sql 或 login.sql) ,以便在您連接到數據庫時自動執行它們,如果這有意義的話。

在這裡草擬如何執行您的腳本。

sqlplus 腳本 run01.sql

SPOOL run01.log
REM file: run01.sql
WHENEVER SQLERROR EXIT FAILURE ROLLBACK
WHENEVER OSERROR EXIT FAILURE ROLLBACK
@temp.sql
SPOOL OFF
EXIT COMMIT
REM COMMIT is the default of EXIT

外殼腳本 main1.sh

#!/bin/bash
sqlplus $USER/$PASSWORD @run01.sql
if [[ $? = 0 ]]; then
   echo "sql script executed successfully" >&
else
   # alert  
   echo "error when executing sql script, check run01.log" >&2
   fi

您添加了一個新要求:

我想執行所有查詢而不考慮任何錯誤,如果至少有一個錯誤,我想回滾所有查詢。

如果發生第一個錯誤,您可以再次執行腳本回滾結束退出。如果發生這種情況,您可以再次執行腳本,但現在您不會退出以防出錯,而是繼續執行腳本。[在腳本結束時,您使用 {EXIT COMMAND] 8](https://docs.oracle.com/database/122/SQPUG/EXIT.htm#SQPUG044)回滾所有事務。

sqlplus 腳本 run02.sql

SPOOL run02.log
REM file: run02.sql
WHENEVER SQLERROR CONTINUE NONE
WHENEVER OSERROR EXIT FAILURE ROLLBACK
@temp.sql
SPOOL OFF
EXIT ROLLBACK

外殼腳本 main2.sh

#!/bin/bash
sqlplus $USER/$PASSWORD @run01.sql
if [[ $? = 0 ]]; then
   echo "sql script executed successfully" >&
else
   sqlplus $USER/$PASSWORD @run02.sql
   # alert  
   echo "error when executing sql script, check run02.log" >&2
   fi

這是我的首選解決方案。我能看到的唯一缺點是 temp.sql 腳本在第一個錯誤發生之前執行的語句被執行了兩次:在腳本 run01.sql 和腳本 run02.sql 中。在 Linux 環境中,您可以嘗試通過執行整個腳本並使用grep語句分析日誌文件來避免這種情況,然後根據分析結果退出會話並送出或回滾。

sqlplus 腳本 run03.sql

SPOOL run03.log
REM file: run03.sql
WHENEVER SQLERROR CONTINUE NONE
WHENEVER OSERROR EXIT FAILURE ROLLBACK
@temp.sql
SPOOL OFF
HOST ./analyze_logfile.sh
@exit.sql

外殼腳本 main3.sh

#!/bin/bash
sqlplus $USER/$PASSWORD @run03.sql
if [[ $? = 0 ]]; then
   echo "sql script executed successfully" >&
else
   # alert  
   echo "error when executing sql script, check run03.log" >&2
   fi

外殼腳本analyze_logfile.sh

#/bin/bash
# file: analyze_logfile.sh
if grep "^ORA-" run03.log; then
   echo "EXIT ROLLBACK"
else
   echo "EXIT COMMIT"

引用自:https://dba.stackexchange.com/questions/173507