PHP Conference Nagoya 2025

SQLite3::createAggregate

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

SQLite3::createAggregateЗарегистрировать функцию PHP в качестве агрегирующей функции SQL

Описание

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

Регистрирует функцию PHP или пользовательскую функцию в качестве агрегирующей функции SQL для использования в запросах.

Список параметров

name

Имя агрегирующей функции SQL, которая должна быть создана или переопределена.

stepCallback

Функция обратного вызова, которая будет вызвана для каждой строки результирующего набора. Ваша PHP-функция должна аккумулировать результат и хранить его в контексте агрегации.

Эта функция должна быть определена следующим образом:

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

Для первой строки должно равняться null; Для всех последующих строк его значение должно быть равно значению, возвращённому на предыдущем шаге; вы должны использовать его для сохранения состояния агрегации.

rownumber

Номер текущей строки.

value

Первый аргумент переданный агрегатору.

values

Последующие аргументы.

Возвращаемое значение функции будет использовано как параметр context при следующем запуске функции, либо как значение передаваемое финализирующей функции.

finalCallback

Функция обратного вызова для вычисление итогового агрегированного значения. Она будет вызвана как только все строки результирующего набора будут обработаны, ей будет передан агрегирующий контекст и она вернёт финальное значение. Данная функция должна вернуть значение типа понятного SQLite (т.е. скалярный тип).

Эта функция должна быть определена следующим образом:

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

Содержит результат самого последнего вызова агрегирующей функции.

rownumber

Всегда 0.

Возвращаемое значение этой функции будет использовано как возвращаемое значение всего агрегатора.

argCount

Количество аргументов, которое принимает функция агрегирования 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)

В этом примере мы написали агрегирующую функцию, которая вычисляет самой длинной строки в одной колонке таблицы. Для каждой строки вызывается функция max_len_step и ей передаётся параметр $context. Этот параметр ничем не отличается от обычной переменной PHP и спокойно может содержать массив или объект. В этом примере мы используем её для хранения максимальной найденной длины строки. Если $string будет иметь длину больше, чем текущая сохранённая, то значение контекста будет обновлено.

После того, как все строки обработаны, SQLite вызовет функцию max_len_finalize, для окончательной подготовки результата. Тут мы можем произвести необходимые расчёты на основе данных из $context. В нашем простом примере никакая постобработке не нужна и мы просто возвращаем полученное значение.

Подсказка

НЕ рекомендуется хранить копию значений в контексте, а обработку производить в финализирующей функции, так как это может привести к большому потреблению памяти при обработке запроса. Просто представьте, сколько памяти вам понадобится для хранения миллиона строк, по 32 байта каждая, в памяти.

Подсказка

Для переопределения встроенных в SQLite агрегирующих функций вы можете использовать SQLite3::createAggregate().

Добавить

Примечания пользователей 2 notes

up
4
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