SQL Scripting
awk4j
(AWK for Java Platform)
SQL スクリプティング
awk4j SQL スクリプティングは、データベースの操作や定義を
AWKスクリプトから実行するための拡張機能で、
ファイル名に データベース URL を指定することにより、
一般ファイルと同じインターフェイスで SQL文による RDBMS へのアクセスが可能。
特殊ファイル名
"jdbc:SUBPROTOCOL:SUBNAME
[ ドライバパラメータ ... ]
[ ;; SQL文 ]"
- jdbc
- この URL が データベース URL であることを表すスキーム名 (固定値)
- SUBPROTOCOL
- サブプロトコル (JDBCドライバを識別する文字列)
- SUBNAME
- 接続先のホスト名、データベース名称 など ドライバ固有のパラメータ
- ;; SQL文
- DB接続時に実行する SQL文 (オプション)
入出力命令
- print expression ... |&
URL
- SQL文 を URL で指定した RDBMS で実行する ( |&
は双方向パイプ指定)
エラー発生時は戻り値に、 0 (FALSE) および 組み込み変数 ERRNO を返す
- printf format [ , expression ... ] |&
URL
- フォーマット変換機能以外は print文と同じ
- getline [ var ] |&
URL
- SQLの実行結果を var (省略時は $0) に読み込む
読み込みデータは、欄 $1 から $NF に格納され、 $0に は 欄を FS(入力フィールドセパレータ)
で結合した値を設定する
FSが ' '(空白)の場合は、 FSに '\t' を設定して TAB区切りとする
組込み変数 RS (入力レコードセパレータ) および RT (RS にマッチし入力文字列) は (無意味なため) 使用しない
- close( URL )
- RDBMS との接続を閉じる
Note: URL に双方向パイプ '|&'
でアクセスすること以外、文法的に目新しい機能はない。
SQL文を、 print[f] で データベース URL
にリダイレクトすることにより SQL文を実行する。 実行結果は print[f] の復帰コ-ドおよび getline
により取得する。
表の削除
make jdbc0
${AWK4J} -e ' \
BEGIN { url = "jdbc:hsqldb:hsql://localhost/sampledb";
\
if
(!print "DROP TABLE COUNTRIES" |&
url) \
print ERRNO; \
close(url); \
}'
表の作成
make jdbc1
${AWK4J} -f JdbcCapitals.awk capitals
# JdbcCapitals.awk
BEGIN { FS = "\t"
url = "jdbc:hsqldb:hsql://localhost/sampledb"
print "CREATE TABLE COUNTRIES(" \
"COUNTRY
VARCHAR(30) NOT NULL, AREA INTEGER, POPULATION INTEGER, CONTINENT
VARCHAR(30), " \
"PRIMARY
KEY ( COUNTRY ) )" |&
url #
表を作成
}
{
sql = "INSERT INTO COUNTRIES VALUES('"
$1 "'," $2 "," $3 ",'" $4 "')"
if (print sql |&
url) #
標準入力から読み込んだデータを表に追加
print
FNR, sql
}
表の問い合わせ
make
jdbc2
${AWK4J} -e ' \
BEGIN { url = "jdbc:hsqldb:hsql://localhost/sampledb";
\
print
"SELECT * FROM COUNTRIES ORDER BY
COUNTRY" |&
url; \
while (0 < (url |&
getline)) \
print; \
}'
URL に SQL文を埋め込む
ファイル名を "URL;;SQL文"
とすること
により、指定した SQLの実行結果を標準入力ストリームから読み込むことが可能になる。
Note: 下記. -e
”1”
の意味は、"世界最短 1文字スクリプトでホームページにアクセス" さ
あ始めよう
を参照。
make jdbc3
${AWK4J} -e '1' 'jdbc:hsqldb:hsql://localhost/sampledb;;SELECT
* FROM COUNTRIES ORDER BY COUNTRY'
Note: SQLの実行結果より、
"Canada"
から "Japan"
にマッチするデータを抽出する。
${AWK4J}
-e '/Canada/,/Japan/' 'jdbc:hsqldb:hsql://localhost/sampledb;;SELECT
* FROM COUNTRIES ORDER BY COUNTRY'
"プログラミング言語AWK"(The AWK Programming
Language) 4.3
関係データベース・システム AWKもどきの問い合わせ言語q (page.139) を、
SQLに対応させ、カラム属性の別名に日本語指定を可能とした例を下記に示す。
この問合せ言語は、AWK言語の欄指定
'$1 ... $NF' と
'$属性'
形式で表のカラム指定を受け付けるため、AWK構文による SQLを意識しない
表への問合せが可能である。
make jdbcq
${AWK4J} -f Q.awk 'jdbc:hsqldb:hsql://localhost/sampledb'
-
$ #
アジア大陸の国名と人口を表示
$ $continent
~ /Asia/ { print $country,
$population }
$ # 国の平均面積を表示 (組込み変数 NRは読み込みデータ件数)
$ { area += $area
} END { print area/NR }
$ # カナダから日本にマッチする国のデータを表示
$ /Canada/,/Japan/ {
$ print $国,
$大陸,
$首都
$ }
問合せのための表定義ファイル (辞書)
#
relfile: 問合せ命令(SQL)と列名(属性の別名)を定義
# # 注釈
# TABLE識別 :
#
属性(英字で始まる英数字) [ 別名(英字で始まる英数字または日本語) ] ...
# !
データ抽出の前に実行する shell コマンド
# ?
データを抽出する SQL文
countries:
country
国 ...
area
面積
population 人口
continent 大陸
?SELECT * FROM COUNTRIES ORDER BY COUNTRY
...
# 4.3 関係データベース・システム: AWKもどきの問い合わせ言語q: page.139
BEGIN { url = ARGV[1]; ARGV[1] = ""
readrel("relfile") # 表定義ファイルの読み込み
RS = ""
# 空行までを一つの問合せスクリプトとする
}
/./ { doquery($0) }
function readrel(f ,i) {
while (getline <f > 0)
{
# parse relfile
if ($0 ~
/^[ \t]*#/) {
# comment
} else if
($0 ~ /^[A-Za-z]+ *:/) { # name:
gsub(/[^A-Za-z]+/, "",
$0) # remove all but name
relname[++nrel] = $0
} else if
($0 ~ /^[ \t]*!/) { # !command...
cmd[nrel, ++ncmd[nrel]] =
substr($0,index($0,"!")+1)
} else if
($0 ~ /^[ \t]*\?/) { # ?query SQL...
$0 = substr($0,index($0,"?")+1)
sub(/^[ \t]+/, " ")
querySql[nrel] = querySql[nrel] $0
} else if
($0 ~ /^[ \t]*[A-Za-z][A-Za-z0-9]*[
\t]*/) {
attr[nrel, $1] =
++nattr[nrel] # 属性(英字で始まる英数字)
for (i = 2; i <= NF; i++)
if ("" !=
$(i)) # 属性の別名(英字で始まる英数字または日本語)
attr[nrel, $(i)] = nattr[nrel]
} else if
($0 !~ /^[ \t]*$/) { # not white space
print "bad line in relfile:", $0
}
}
}
function doquery(s, q, i, j) {
q = s
for (i in
qattr) # clean up for next query
delete
qattr[i]
query = s
# put
$names in query into qattr, without $
#
属性(英字で始まる英数字または日本語、プラットフォーム非依存とするため Unicodeで指定 u3041:ぁ fa2d:鶴)
while (match(s,
/\$[A-Za-z\u3041-\ufa2d][A-Za-z0-9\u3041-\ufa2d]*/))
{
qattr[substr(s, RSTART+1, RLENGTH-1)] = 1
s =
substr(s, RSTART+RLENGTH+1)
}
for (i = 1; i <= nrel
&& !subset(qattr, attr, i); )
i++
if (i >
nrel) #
didn't find a table with all attributes
missing(qattr)
else {
# table i contains attributes in query
for (j in
qattr) # create awk program
gsub("\\$" j, "$" attr[i,j], query)
for (j =
1; j <= ncmd[i]; j++) # create table i
if (system(cmd[i, j]) != 0) {
print
"command failed, query skipped\n", cmd[i,j]
return
}
awkcmd =
sprintf("%s -e '%s' '\"\"' -F='\\t'
-vOFS='\\t' '%s;;%s'",
ENVIRON["AWK4SQL"], query, url,
querySql[i])
system(awkcmd) # AWK4J で問合せ
}
}
function subset(q, a, r, i) { #
is q a subset of a[r]?
for (i in q)
if
(!((r,i) in a))
return 0
return 1
}
function missing(x, i) {
print "no table contains all of the
following attributes:"
for (i in x)
print i
}
Note: このスクリプトそのものには特に目新しい機能はない。
問合せのために system関数で起動動された awk4j
がファイル名として指定された URLで RDBMSにアクセスするところがミソ。
サンプル (sample/make) は、規定値として、 HSQLDB を使用するように設定している、
HSQLDB を使用する場合は、 http://hsqldb.org/
からダウンロードするか、
OpenOffice
を使用しているなら、 "${OpenOffice}/program/classes/hsqldb.jar" または
"/user/share/java/hsqldb-XXX.jar" を ${awk4j}/ext
にコピーする。 (環境設定は不要)
SQLite を使用する場合は、 Pure Java版の JDBC Driver付き SQLite
をダ
ウンロードし、 "sqlitejdbc-XX-nested.jar" を ${awk4j}/ext
にコピーする。 (環境設定は不要)
« フリーで入手可能な RDBMS一覧 »
RDBMS |
データベース URL (例) |
jar (lib に配置) |
Apache Derby |
jdbc:derby:sampledb;create=true (組込みモード)
jdbc:derby://localhost/sampledb |
derby.jar derbyclient.jar derbynet.jar derbytools.jar |
HSQLDB |
jdbc:hsqldb:file:rdb/hsqldb/sampledb;shutdown=true
(組込みモード)
jdbc:hsqldb:hsql://localhost/sampledb |
hsqldb.jar |
H2 |
jdbc:h2:file:rdb/h2/sampledb (組込みモード)
jdbc:h2:tcp://localhost/sampledb |
h2.jar |
MySQL |
jdbc:mysql://localhost/sampledb |
mysql-connector-java-XX-bin.jar |
PostgreSQL |
jdbc:postgresql://localhost/sampledb |
postgresql-XX.jdbc3.jar |
SQLite |
jdbc:sqlite:rdb/sqlite/sampledbe |
sqlitejdbc-XX-nested.jar |
SQLite |
jdbc:sqlite:[${HOME}/databases/]filename;appId |
awk4j Android サポートに含む |
awk4j 実行環境の設定 -
awk4j.properties
lib/properties のパラメータをを利用する RDBMS 環境に合わせて設定する。
# jdbc データベース URLを "jdbc:?:path"
で指定した場合の "?" サブプロトコルの規定値 (オプション)
org.awk4j.io.JdbcSocket.subprotocol=sqlite
RDBMS 固有環境の設定 - subprotocol.properties
利用する RDBMS の接続パラメータを指定する。
# jdbc ドライバのクラス名 (必須)
jdbc.driver=org.hsqldb.jdbcDriver
# jdbc データベース URLを "jdbc:subprotocol:?" とした場合の "?" の規定値 (オプション)
jdbc.path=file:../sample/rdb/hsqldb/sampledb;shutdown=true
# username, password この行以降はドライバで解釈されるため、環境変数での指定は不可
user=ユーザ名
passwd=パスワード
# RDBMS 固有の接続パラメータ
Note: 上記の規定値の参照指定 "?"
の利用により、
URLを "jdbc:?:?"
とすることにより、スクリプトは
RDBMS 非依存となる。 また、これらの規定値は環境変数で指定することも可能。
ex. export org.awk4j.io.JdbcSocket.subprotocol=hsqldb
export jdbc.path=file:../sample/rdb/hsqldb/sampledb;shutdown=true
- Apache
Derby - Java SE6 にバンドルされている (Pure Java RDBMS)
- HSQLDB
- OpenOffice などに組み込まれている (Pure Java RDBMS)
- H2
- もう一つの Hypersonic SQL (Pure Java RDBMS)
- MySQL
- MySQL本家
- PostgreSQL
- 日本PostgreSQLユーザ会
- SQLiteJDBC
- JDBC Driver付き SQLite (Pure Java RDBMS)