データベース†

4 個の関数。

SQLOPEN†

書式†

SQLOPEN( path [, mode] )

引数†

Parameter Description
path データベースファイルのパス(yaya.dll からの相対パス、または絶対パス)。":memory:" ならメモリ上のデータベース
mode 開き方(省略可。下記参照)。省略時は "rwc"
mode†
mode 動作
"rwc" 読み書き。ファイルが無ければ作る(省略時)
"rw" 読み書き。ファイルが無ければ失敗する
"r" 読み取り専用。ファイルが無ければ失敗する

戻り値†

解説†

SQLite のデータベースを開く。開いたデータベースには、SQLEXEC と SQLQUERY で SQL を実行する。

FOPEN と同じく、データベースは開いたときのパスで識別する。以降の SQLEXEC・SQLQUERY・SQLCLOSE には、SQLOPEN と同じ書き方のパスを渡す。"data.db" と "./data.db" のように書き方が違うと、同じファイルでも別のものとして扱われ、2つ目の接続が開く(SQLite のロックで守られるので中身は壊れないが、閉じるときはそれぞれ閉じる必要がある)。

データベースの中身(表の作り方、ジャーナルの方式など)は SQL で指定する。たとえば書き込みの多い用途では、開いた直後に SQLEXEC(path, "PRAGMA journal_mode=WAL") を実行しておくとよい。

SQLite の拡張機能の読み込み(load_extension)は使えない。

エラー†
状況 警告 GETLASTERROR
引数がない W0008 8
path または mode が文字列でない W0009 9
path が空文字列 W0010 10
mode が不正 W0012 12
データベースを開けない W0029 29

W0029 の警告には SQLite のエラーメッセージが付く。

使用例†

if SQLOPEN("ghost.db") == 0 {
    // 開けなかった
}
SQLEXEC("ghost.db", "CREATE TABLE IF NOT EXISTS talk(id INTEGER PRIMARY KEY, text TEXT)")

SQLOPEN(":memory:")      // メモリ上の作業用データベース
SQLOPEN("ref.db", "r")   // 読み取り専用

互換性†

関連項目†


SQLCLOSE†

書式†

SQLCLOSE( path )

引数†

Parameter Description
path SQLOPEN で開いたデータベースのパス

戻り値†

返り値はない(VOID)。

解説†

SQLOPEN で開いたデータベースを閉じる。終わっていないトランザクションはロールバックされる。

閉じ忘れたデータベースは unload のときに自動で閉じる。

エラー†
状況 警告 GETLASTERROR
引数がない W0008 8
path が文字列でない W0009 9
開いていない W0015 15

使用例†

SQLOPEN("ghost.db")
SQLEXEC("ghost.db", "INSERT INTO talk(text) VALUES(?)", "こんにちは")
SQLCLOSE("ghost.db")

互換性†

関連項目†


SQLEXEC†

書式†

SQLEXEC( path, sql [, param...] )

引数†

Parameter Description
path SQLOPEN で開いたデータベースのパス
sql 実行する SQL。; で区切って複数の文を書ける
param SQL のパラメータに入れる値(省略可。下記の パラメータ)

戻り値†

解説†

SQL を実行する。表を作る、行を追加・変更・削除する、トランザクションを始める、といった結果の行を使わない SQL に使う。SELECT の結果を受け取るときは SQLQUERY を使う(SQLEXEC で SELECT を実行すると、結果の行は捨てられる)。

sql に複数の文があれば、先頭から順に実行する。途中の文でエラーになったら、そこで止まる。それまでに実行した文は取り消されないので、まとめて取り消したいときはトランザクション(BEGIN 〜 COMMIT)の中で実行する。

パラメータ†

SQL の中の ?(または ?1 のような番号付き)や :名前 @名前 $名前 の位置に値を入れられる。値を SQL の文字列に直接埋め込むと、' を含む文字列でエラーになったり、意図しない SQL が実行されたりする(SQL インジェクション)。外から受け取った文字列は必ずパラメータで渡すこと。

param の渡し方は2通りある。

  1. 値を並べる: param がすべて整数・実数・文字列・VOID のとき、1回だけ実行する。? に先頭から順に入る
  2. 1回分ずつ配列かハッシュにする: param がすべて配列かハッシュのとき、1つを1回分として、その数だけ実行する - ハッシュ: :名前 @名前 $名前 に、キーが「名前」の値が入る - 配列: ? に要素が先頭から順に入る

値が足りないパラメータや、ハッシュにキーが無いパラメータには NULL が入る。値とハッシュ・配列を混ぜて渡すと W0009 になる。

逆に、値がパラメータより多いときは、余った値は使われず、W0030 の警告が出る(実行はする)。1 の形では param の数が、2 の形では配列の要素数が、? の数(?3 のような番号付きなら最大の番号)より多いと警告になる。ハッシュは使われなかったキーがあっても警告しない。

関数に配列を渡すと、いちばん外側の配列は引数に展開される(値の入れ子と多次元代入)。そのため、値の配列 (1, "a") を渡すと 1 の「値を並べる」になり、ハッシュの配列や、配列の配列(PARSEJSON などで得たもの)を渡すと 2 の「1回分ずつ」になる。

(1, 2), (3, 4) と書いたり、値の配列の変数を2つ並べたりしても、, で1つの配列につながるので「1回分ずつ」にはならず、1 の形で1回だけ実行される(? が 2 つなら 3 と 4 は使われず、W0030 になる)。1回分ずつにしたいときは、配列の配列やハッシュの配列を作って渡す。

sql に複数の文があるときは、どの文にも同じパラメータが使われる(? の番号は文ごとに 1 から数える)。前の文の続きの値が次の文に入るわけではない。INSERT INTO t VALUES (?); INSERT INTO u VALUES (?) に "first", "second" を渡すと、どちらの文にも "first" が入り、"second" は使われない(W0030)。文ごとに違う値を入れたいときは、文を分けて実行するか、ハッシュで :名前 を使う。

2 の形で多くの行を追加するときは、BEGIN と COMMIT で囲むと、1行ずつファイルに書き込まれないので速い。

値の対応†
YAYA SQLite YAYA に戻したとき
整数 INTEGER 整数
実数 REAL 実数
文字列 TEXT(UTF-8) 文字列
空(VOID) NULL 空(VOID)
― BLOB 16進数の文字列(hex() と同じ大文字)
準備済みの文の再利用†

同じ sql の文字列で実行すると、前回 SQLite が解析した結果(準備済みの文)を使い回すので速い。パラメータで値を変えながら同じ sql を何度も実行するとよい。値を SQL の文字列に埋め込むと毎回別の sql になり、使い回せない。

エラー†
状況 警告 GETLASTERROR
引数が足りない W0008 8
path または sql が文字列でない、param が上記のどちらの形でもない W0009 9
データベースを開いていない W0015 15
SQL の実行に失敗した(文法の誤り、制約違反、読み取り専用など) W0029 29
param の値がパラメータより多い(実行は成功する) W0030 30

W0029 の警告には SQLite のエラーメッセージが付く(例: SQLEXEC : UNIQUE constraint failed: talk.id)。W0030 の警告にはパラメータの数と値の数が付く(例: SQLEXEC : parameters 2, values 4)。

W0030 は実行に成功したときに出るので、返値は成功時と同じ(変更された行数)。GETLASTERROR は成功しても 0 に戻らないので、W0030 を調べるときは先に SETLASTERROR(0) しておく。

使用例†

SQLOPEN("ghost.db")
SQLEXEC("ghost.db", "CREATE TABLE IF NOT EXISTS talk(id INTEGER PRIMARY KEY, text TEXT, score REAL); CREATE INDEX IF NOT EXISTS talk_score ON talk(score)")

// 値を並べる
SQLEXEC("ghost.db", "INSERT INTO talk(text, score) VALUES(?, ?)", "こんにちは", 1.5)   // 1

// ハッシュで名前を指定する
_h = IHASH("text", "こんばんは", "score", 2)
SQLEXEC("ghost.db", "INSERT INTO talk(text, score) VALUES(:text, :score)", _h)   // 1

// ハッシュの配列で、まとめて追加する
_rows = (IHASH("text", "a", "score", 3), IHASH("text", "b", "score", 4))
SQLEXEC("ghost.db", "BEGIN")
SQLEXEC("ghost.db", "INSERT INTO talk(text, score) VALUES(:text, :score)", _rows)   // 2
SQLEXEC("ghost.db", "COMMIT")

SQLEXEC("ghost.db", "UPDATE talk SET score = score + 1 WHERE score >= ?", 3)   // 2
SQLEXEC("ghost.db", "DELETE FROM talk WHERE text = ?", "a")                     // 1

// 直前に追加した行の id は SQL の関数で得る
SQLQUERY("ghost.db", "SELECT last_insert_rowid() AS id")[0]["id"]

互換性†

関連項目†


SQLQUERY†

書式†

SQLQUERY( path, sql [, param...] )

引数†

Parameter Description
path SQLOPEN で開いたデータベースのパス
sql 実行する SQL(主に SELECT)
param SQL のパラメータに入れる値(省略可。SQLEXEC と同じ)

戻り値†

解説†

SQL を実行して、結果の行を返す。パラメータの渡し方、値の対応、エラーは SQLEXEC と同じ。

空の結果(空の汎用配列)と失敗(VOID)は GETTYPE で見分けられる(それぞれ 4 と 0)。

使用例†

SQLOPEN("ghost.db")

_rows = SQLQUERY("ghost.db", "SELECT id, text, score FROM talk WHERE score >= ? ORDER BY score DESC LIMIT 10", 2)
ARRAYSIZE(_rows)       // 行数
_rows[0]["text"]       // 1行目の text

foreach _rows; _r {
    // _r["id"] _r["text"] _r["score"]
}

// 集計には AS で名前を付ける
SQLQUERY("ghost.db", "SELECT count(*) AS n, avg(score) AS avg FROM talk")[0]["n"]

// JSON で保存した列を SQLite の JSON 関数で検索する
SQLEXEC("ghost.db", "CREATE TABLE IF NOT EXISTS ev(id TEXT PRIMARY KEY, json TEXT)")
_ev = PARSEJSON('{"id":"abc","tags":[["p","xyz"],["e","def"]]}')
SQLEXEC("ghost.db", "INSERT OR IGNORE INTO ev VALUES(?, ?)", _ev["id"], DUMPJSON(_ev))
SQLQUERY("ghost.db", "SELECT ev.id, t.value->>1 AS v FROM ev, json_each(ev.json, '$.tags') t WHERE t.value->>0 = ?", "e")
// → 要素1つ:IHASH("id", "abc", "v", "def")

互換性†

関連項目†