Oracleの簡単なSQLを実行するBashのシェルスクリプトを今年になってからいろんなところで書くので自分用のテンプレート
ちょっとした確認用のSQLを実行するのにSQL Developerを立ち上げるのが重いというのもあり、よく実行するものはシェルスクリプトにしている。
今年に入ってから、いろいろな場所で同じようなSQLばかり書いているので、面倒だと感じ始めたからシェルスプリクトにする。
ただ、それぞれ別の場所で作るから毎回微妙に違うものを書いていたので、次に自分が作るとき用のメモ。
自分がよく作るのはGit for WindowsのBashでOracleに接続してSQLを投げるシェルスプリクト。
そのまま実行するとSELECTするSQLが実行され、-aをつけるとINSERTするSQLを実行する。
作るもののほとんどがマスターに登録があるかないかを確認する系のSQLで、EXISTSで確認して無かったら追加する流れなので、値は指定しない事が多い。
#!/bin/bash # # 説明 readonly ORACLE_CONNECTION=USER/PASSWORD@SERVER:PORT/SID function usage() { cat <<_EOF_ Usage: $0 [-a] Description: 説明 Option: -a ADD DATA _EOF_ exit 1 } err() { echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $@" >&2 } function select_data() { sqlplus -s $ORACLE_CONNECTION << EOF SELECT * FROM USERS A WHERE NOT EXISTS ( SELECT * FROM USERS2 B WHERE A.ID = B.ID ) ; EXIT; EOF if [ $? -ne 0 ]; then err "ERROR SELECT" return 1 fi return 0 } function insert_data() { sqlplus -s $ORACLE_CONNECTION << EOF INSERT INTO USERS( ID , NAME ) SELECT A.ID , A.NAME FROM USERS2 A WHERE NOT EXISTS ( SELECT * FROM USERS B WHERE A.ID = B.ID ) ; COMMIT; EXIT; EOF if [ $? -ne 0 ]; then err "ERROR INSERT" return 1 fi return 0 } FLAG_A="" if [ "$OPTIND" = 1 ]; then while getopts abf:h OPT do case $OPT in a) FLAG_A="on" ;; h) usage ;; \?) echo "Try to enter the h option." 1>&2 ;; esac done else echo "No installed getoptions-command." 1>&2 exit 1 fi function main() { if [ -n "$FLAG_A" ]; then insert_data else select_data fi return 0 } main
emacsでVB6のコードを見る。そのままでも見れるけど、やっぱり白黒ではあじけないのでvisual-basic-mode.elを入れてみる。
EmacsWikiからvisual-basic-mode.elをダウンロードする。
ダウンロードしたらどこでもいいけど「~/.emacs.d/elisp/visual-basic-mode.el」なんかに置く。
おもむろにinit.elに追記する。
(add-to-list 'load-path "~/.emacs.d/elisp") ;ファイルを置いたところのパスを追加 ;;; VB mode (require 'visual-basic-mode) (add-to-list 'auto-mode-alist '("\\.\\(frm\\|bas\\|cls\\|vbs\\)$" . visual-basic-mode))
これで、VB6のコードも少しは見る気になれるだろうか。
十数年前に、今、私の目の前にあるコードを書いた人は、まさか2018年になってもまだ自分の作ったプログラムが使われ続け、今もなおメンテナンスされているとは思わないだろう。
システムはいつの時も作者の予想よりも長く運用されるもの。
PL/SQLでSELECT INTOをした時にORA-01422が出る場合には、一度、引数とか変数の名前をカラム名と同じにしていないか確認しよう。
ORA-01422がでるのは、PL/SQLで変数にどこかのテーブルの値を検索してセットする時なんかに、戻ってくる値が一意にならないからエラーになる。
例えば下記のようにするとエラーになる。
CREATE OR REPLACE PROCEDURE SAMPLE ( USER_ID IN NUMBER ) AS V_USER_NAME VARCHAR2(32 CHAR) BEGIN SELECT USER_NAME INTO V_USER_NAME FROM USERS WHERE USER_ID = USER_ID; DBMS_OUTPUT.PUT_LINE('USER_NAME: ' || V_USER_NAME); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('ERROR CODE: ' || SQLCODE || ', MESSAGE: ' || SQLERRM); END; END;
この場合、引数のUSER_IDとUSERSテーブルのカラム名のUSER_IDがまったく同じなので、エラーになる。
例えば、引数のUSER_IDを「SAMPLE」にするとWHERE句が「'SAMPLE' = 'SAMPLE'」となり、まったく同じ値で比較してしまう。
これだとUSERSテーブルのすべてが返ってきてしまうので、V_USER_NAMEに何をセットしたらいいかわからなくて、ORA-01422が出てしまう。
SELECT USER_NAME INTO USER_NAME FROM USERS WHERE 'SAMPLE' = 'SAMPLE';
それを回避するには、単に引数名や変数名をカラム名と同じにしなければいい。
引数は「P_(アンダーバー)」で始め、変数は「V_(アンダーバー)」で始めれば区別もついてわかりやすいと思う。
上のコードの引数の部分を書き換えて、P_USER_IDにすれば問題なく動いてくれる。
CREATE OR REPLACE PROCEDURE SAMPLE ( P_USER_ID IN NUMBER ) AS V_USER_NAME VARCHAR2(32 CHAR) BEGIN SELECT USER_NAME INTO V_USER_NAME FROM USERS WHERE USER_ID = P_USER_ID; DBMS_OUTPUT.PUT_LINE('USER_NAME: ' || V_USER_NAME); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('ERROR CODE: ' || SQLCODE || ', MESSAGE: ' || SQLERRM); END; END;
当初はエラーを出力していなかったので、なんでこけるのかわからず、無駄な時間を過ごした。
2018年、正月三が日の深夜の思い出。
WindowsのCMDを使ってCOPYコマンドでファイルを連結する
file1とfile2を連結してfile3を作る
CMD> COPY file1 + file2 file3
ただし、出来上がったfile3の最後に空白行が入る。 なので、例えば、CSVなんかを連結して、SQLLoderに食べさせる時にこれを使うと最後の行がエラーになるので注意が必要。
空白行を入れたくなければCOPYコマンドではなくTYPEコマンドとリダイレクトでやれば最後に空白なんて入らない。
CMD> TYPE file1 file2 > file3
ちょっとした計算をコマンドライン上でやりたい時のPowerShellとBashでのやり方の違いメモ
電卓を開くのが面倒な時に覚えておくと便利かも
PowerShellはそのまま
PS> 100 - 50 50
Bashは算術式展開?で書かないといけないみたい
$ echo $((100 - 50)) 50
これだけ見るとPowerShellよりもBashの方が面倒か
ちなみに変数に入れるのは
PS> $x = 100 PS> $x 100
$ let x=100 $ echo $x 100
vimの:sort uをemacsではどうしたらいいか調べたのでメモ。
年末の大掃除のついでにシステムの監視用にログを取っているSQLiteのファイルも大きくなっていたので、こっちも掃除するかといらなくなったログデータを削除してもファイルサイズが小さくならなかったのでvacuumして小さくした。
複数のシステムを運用していると、バッチなんかで出力されるログが溜まっていく。
定期的に削除されるようにしているし、個別のファイルに吐かれているものだから検索も面倒なので使い勝手が悪い。
なので、そのログのファイル名と内容をけっこう雑にSQLiteに入れて、ログDBとしてあとでWebから検索できるようにしている。
ログ自体はテキトーに入れているが、バッチがエラーになった時なんかに、過去に同じエラーが出たことがないかを調べたり、他のバッチでも同じエラーがないか調べるのには当初考えていたよりも便利に使えている。
そのログDBも放置しているといつの間にかサーバーのディスクを圧迫する容量となっていたので、同僚たちが大掃除している中、一人、サーバー内の掃除をしていた。
最初は単純にDeleteしてしまえば、SQLiteのファイルサイズが小さくなるだろうと思っていたけど、そうはならなかった。 Oracleだと自動拡張とかを考えなければ最初から指定した容量を取ってるからそれと同じノリか。一度、伸びると縮まらないジャージのゴムを思い出した。
調べると「vacuum」ってすると小さくなるらしいので試した。
CMD> sqlite ファイル名.sqlite sqlite> vacuum;
それほど時間がかかる事もなく、容量が小さくなった。
これで、サーバーの容量が足りなくなったと、夜中に呼び出されることもないだろう。