SQLite3::createAggregate

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

SQLite3::createAggregateSQL の集約関数として使用する PHP 関数を登録する

説明

public SQLite3::createAggregate(
    string $name,
    callable $stepCallback,
    callable $finalCallback,
    int $argCount = -1
): bool

SQL の集約関数として使用する PHP 関数を登録します。 これは SQL 文の中で使用されるものです。

パラメータ

name

作成あるいは再定義したい SQL 集約関数の名前。

stepCallback

結果セットの各行ごとにコールされるコールバック関数。 この関数で結果を集約し、集約処理のコンテキストに保存すべきです。

このコールバック関数は、以下のように定義すべきです:

step(
    mixed $context,
    int $rownumber,
    mixed $value,
    mixed ...$values
): mixed
context

最初の行では null です。 2行目以降は、step 関数から返された値をとります。 これは、集約の状況を管理するのに使います。

rownumber

現在の行番号

value

集約に渡されるはじめの引数

values

集約に渡されるふたつめ以降の引数

この関数の戻り値は、 次のステップで呼ばれる際、または finalize 関数での context の引数として使われます。

finalCallback

各行からの "段階的に処理された" データを集約するコールバック関数です。 いったん全データが処理されると、この関数が呼ばれます。 集約処理のコンテキストからデータを取り出し、結果を返すべきです。 このコールバック関数は SQLite が理解する型を返します。 (例: スカラー型)

このコールバック関数は、以下のように定義すべきです:

fini(mixed $context, int $rownumber): mixed
context

最後に呼ばれた step 関数から返された値を保持します。

rownumber

常に 0.

この関数の戻り値は、集約の戻り値として使われます。

argCount

SQL 集約関数が受け取るパラメータの数。 負の値を指定すると、SQL 集約関数は任意の数の引数を受け取るようになります。

戻り値

集約関数の作成に成功した場合に true、失敗した場合に false を返します

例1 max_length 集約関数の例

<?php
$data
= array(
'one',
'two',
'three',
'four',
'five',
'six',
'seven',
'eight',
'nine',
'ten',
);
$db = new SQLite3(':memory:');
$db->exec("CREATE TABLE strings(a)");
$insert = $db->prepare('INSERT INTO strings VALUES (?)');
foreach (
$data as $str) {
$insert->bindValue(1, $str);
$insert->execute();
}
$insert = null;

function
max_len_step($context, $rownumber, $string)
{
if (
strlen($string) > $context) {
$context = strlen($string);
}
return
$context;
}

function
max_len_finalize($context, $rownumber)
{
return
$context === null ? 0 : $context;
}

$db->createAggregate('max_len', 'max_len_step', 'max_len_finalize');

var_dump($db->querySingle('SELECT max_len(a) from strings'));
?>

上の例の出力は以下となります。

int(5)

この例では、テーブルのカラムに入っている一番長い文字列を集約する関数を作っています。 1行ごとに、max_len_step 関数が呼ばれ、 $context パラメータが渡されます。 context パラメータ は他のPHPの変数のように振る舞いますし、配列やオブジェクトを格納することさえできます。 この例では、単にこれまで見てきたものの中から一番大きな長さを保持するのに使っています。 つまり、$string が現在の最大値より大きな長さをもっていたら、 context を新しい最大値に更新しています。

全ての行を処理し終わったら、SQLite は 集約結果を決めるために max_len_finalize 関数を呼び出します。 ここでは、$context で見つかったデータを基にして、 ある種の計算を行うことができます。 私達のシンプルな例では、結果を段階的に計算してきているので、 単に context に入っている値を返すだけで済みます。

ヒント

値のコピーを context に保存し、一番最後に処理することは推奨できません。 なぜなら、SQLite がクエリを処理するのにたくさんのメモリを使うことになるからです。 - 100万行の情報がメモリに格納されていたとして、 それぞれの行が32バイトの長さを持っていたとすると、 どれくらいのメモリが必要になるのかを考えてみてください。

ヒント

SQLite のネイティブなSQL関数を上書きするために SQLite3::createAggregate() を使うことができます。

add a note

User Contributed Notes 2 notes

up
6
boris dot dd at gmail dot com
7 years ago
<?php
class Test extends SQLite3
{
public function
__construct($file)
{
parent::__construct($file);
$this->createAggregate('groupConcat', [$this, 'concatStep'], [$this, 'concatFinal']);
}
public function
concatStep(&$context, $rowId, $string, $delimiter)
{
if (!isset(
$context)) {
$context = [
'delimiter' => $delimiter,
'data' => []
];
}
$context['data'][] = $string;
return
$context;
}
public function
concatFinal(&$context)
{
return
implode($context['delimiter'], $context['data']);
}
}
$SQLite = new Test('/tmp/test.sqlite');
$SQLite->exec("create table `test` (`id` TEXT, `color` TEXT, `size` TEXT)");
$SQLite->exec("insert into `test` (`id`, `color`, `size`) values ('1', 'red', 'M')");
$SQLite->exec("insert into `test` (`id`, `color`, `size`) values ('1', 'green', 'M')");
$SQLite->exec("insert into `test` (`id`, `color`, `size`) values ('1', 'blue', 'S')");
$Result = $SQLite->query("select `size`, groupConcat(`color`, ';') as `color` from `test` group by `size`");
while (
$row = $Result->fetchArray(SQLITE3_ASSOC)) {
print_r($row);
}
/*
Array
(
[size] => M
[color] => red;green
)
Array
(
[size] => S
[color] => blue
)
*/
up
-3
sukmaagungsaputra at gmail dot com
9 years ago
Lacks of example, right?
Let's try to give to SQlite3 the capability like ones of MySQL's
- REGEXP operator,
- MD5 function, and
- GROUP_CONCAT aggregate function

$db = new SQLite3($filename);
$db->createFunction('regexp', function ($a,$b) { return preg_match("/$a/i", $b); });
$db->createFunction('md5', function ($a) { return md5($a); });
$db->createAggregate ('group_concat',
function(&$context, $rownumber, $str) { $context[]=$str; return $context; },
function(&$context) {return implode(",", (array) $context); });
To Top