SQL 文で使用するユーザー定義集約関数を登録する

# Pdo\Sqlite::createAggregate

(PHP 8 >= 8.4.0)

Pdo\Sqlite::createAggregate — SQL 文で使用するユーザー定義集約関数を登録する

### 説明

public function Pdo\Sqlite::createAggregate(
string `$name`,
callable `$step`,
callable `$finalize`,
int `$numArgs` = -1
): bool

このメソッドは Pdo\Sqlite::createFunction() と似ていますが、クエリのすべての行を集約する関数を登録する点が 異なります。

この関数と Pdo\Sqlite::createFunction() の最大の違いは、集約関数の登録には 2 つの関数が必要であるということです。

ヒント

このメソッドを使用してネイティブ SQL 関数を上書きすることができます。

### パラメータ

`name`
  SQL 文で使用する関数の名前。
`step`
  結果セットの各行を処理するコールバック関数。 この関数は、結果を蓄積して集約コンテキストに保存しなければなりません。

  定義は次のとおりです:

  function step(
  mixed `$context`,
  int `$rownumber`,
  mixed `$value`,
  mixed `...$values`
  ): mixed
  `context`
    最初の行では `null` 2行目以降では、この関数が前回返した値です。 この値で集約の状態を管理します。
  `rownumber`
    現在の行番号
  `value`
    集約関数に渡されるはじめの引数
  `values`
    集約関数に渡されるふたつめ以降の引数
  この関数の戻り値を、次の関数呼び出し、または ファイナライズ関数の`context` 引数として 使います。
`finalize`
  すべての行が処理された後で呼び出されるコールバック関数。 ここでは、集約コンテキストからデータを取得して結果を返します。 この関数が返す値は、SQLite が理解できる形式 (すなわち スカラー型) でなければなりません。

  定義は次のとおりです:

  function fini(mixed `$context`, int `$rowcount`): mixed
  `context`

    ステップ関数の最後の戻り値

  `rowcount`

    ステップ関数が処理した行数

  この関数の戻り値が、 集約関数全体の戻り値となります。
`numArgs`
  コールバック関数があらかじめ定義済みの引数を受け取る場合に、 SQLite のパーサーに渡すヒント。

### 戻り値

成功した場合に `true` を、失敗した場合に `false` を返します。

### 例

例1 Pdo\Sqlite::createAggregate() example

この例では、SQLクエリの中で使用できる `max_length` という名前のユーザー定義集約関数を作成しています。

この例では、`max_length` という集約関数を 作成しています。この関数はテーブルの特定のカラム内で 最も長い文字列の長さを計算します。 各行に対し `max_len_step` 関数が呼ばれ、 その際に `$context` パラメータが渡されます。 この context パラメータには、他の PHP 変数と同様 array や object などを格納できます。 この例では、これまでの中で最大の文字列長を格納するために利用しています。 もし $string が現在の最大値よりも長ければ、 context に格納した最大長を新たな値で更新します。

全ての行が処理された後、 SQLite は集約関数の結果を計算するため `max_len_finalize` 関数を呼び出します。 `$context` 内のデータに基づいて何らかの計算を行うことも可能です。 この例では、結果はクエリの進行中に計算されているため、 context の値をそのまま返すことができます。

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

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

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

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

    var_dump($db->query('SELECT max_len(a) from strings')->fetchAll());

    ?>

ヒント

結果の値を context に蓄積し、最後に一括で処理する方法は推奨 「しません」。これは、SQLite のメモリ消費量が大きくなるからです。 仮に 32 バイトの長さのデータが百万件あったとして、 それを蓄積しておくのにどれだけのメモリが必要になるか 考えてみましょう。

### 参考

- Pdo\Sqlite::createFunction() - SQL 文で使用するユーザー定義関数を登録する
- Pdo\Sqlite::createCollation() - SQL文で文字列比較関数として使うユーザー定義関数を登録する
- sqlite_create_function()
- sqlite_create_aggregate()

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open