smelnik / clickhouse-builder
Clickhouse sql 查询构建器
Requires
- php: ~7.1
- myclabs/php-enum: ^1.5
- the-tinderbox/clickhouse-php-client: ~1.0.0
Requires (Dev)
- illuminate/config: ^5.4
- illuminate/database: ^5.4
- illuminate/events: ^5.4
- mockery/mockery: ^0.9.9
- phpunit/phpunit: ^6.1
README
要求
php 7.1
安装
通过 composer
composer require esazykin/clickhouse-builder
用法
为了使用查询构建器,我们必须先实例化并在构造函数中传递 the-tinderbox/clickhouse-php-client。
$server = new Tinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass'); $client = new Tinderbox\Clickhouse\Client($server); $builder = new Builder($client);
之后我们可以构建和执行 SQL 查询。
选择列
$builder->select('column', 'column2', 'column3 as alias'); $builder->select(['column', 'column2', 'column3 as alias']); $builder->select(['column', 'column2', 'column3' => 'alias']);
所有这些调用将被转换成以下的 SQL
SELECT `column`, `column2`, `column3` AS `alias`
我们也可以将闭包作为列传递。在这种情况下,闭包将接收 Column 类的实例,我们可以在其中设置列的属性。这对于包含许多函数、子查询等的复杂表达式非常有用。
$builder->select(function ($column) { $column->name('time')->sumIf('time', '>', 10); });
将编译成
SELECT sumIf(`time`, time > 10)
$builder->select(function ($column) { $column->as('alias') //or ->name('alias') in this case ->query() ->select('column') ->from('table'); });
将编译成
SELECT (SELECT `column` FROM `table) as `alias`
也可以通过以下任何一种方法实现相同的行为
$1 = $builder->select(function ($column) { $column->as('alias') //or ->name('alias') in this case ->query(function ($query) { $query->select('column')->from('table'); }) }); $2 = $builder->select(function ($column) { $column->as('alias') //or ->name('alias') in this case ->query($builder->select('column')->from('table')); });
注意!列上的函数不稳定,处于开发中。
从
$builder->select('column')->from('table', 'alias');
生成以下查询
SELECT `column` FROM `table` as `alias`
也可以传递闭包或构建器作为执行子查询的参数。
$builder->from(function ($from) { $from->query()->select('column')->from('table'); });
SELECT * FROM (SELECT `column` FROM `table`)
或者
$builder->from(function ($from) { $from->query(function ($query) { $query->select('column')->from('table'); }); });
或者
$builder->from(function ($from) { $from->query($builder->select('column')->from('table')); });
或者
$builder->from($builder->select('column')->from('table'));
这些都是上面列出的相同 SQL 查询的不同变体。
样本系数
$builder->select('column')->from('table')->sample(0.1);
SELECT `column` FROM `table` SAMPLE 0.1
我认为不需要额外的文字)
连接
$builder->from('table')->join('another_table', 'any', 'left', ['column1', 'column2'], true);
SELECT * FROM `table` GLOBAL ANY LEFT JOIN `another_table` USING `column1`, `column2`
要作为第一个参数执行子查询,你可以传递闭包或构建器。
$builder->from('table')->join(function ($query) { $query->select('column1', 'column2')->from('table2'); }, 'any', 'left', ['column1', 'column2']); $builder->from('table')->join($builder->select('column1', 'column2')->from('table2'), 'any', 'left', ['column1', 'column2']);
SELECT * FROM `table` ANY LEFT JOIN (SELECT `column1`, `column2` FROM `table2`) USING `column1`, `column2`
还有许多具有硬编码参数的辅助函数,如严格或类型及其组合。
$builder->from('table')->anyLeftJoin('table', ['column']); $builder->from('table')->allLeftJoin('table', ['column']); $builder->from('table')->allInnerJoin('table', ['column']); $builder->from('table')->anyInnerJoin('table', ['column']); $buulder->from('table')->leftJoin('table', 'any', ['column']); $buulder->from('table')->innerJoin('table', 'all', ['column']);
临时表的使用
在某些情况下,你可能需要根据用户 ID 过滤用户,但 ID 的数量非常大。你可以将用户 ID 存储在本地文件中,将其上传到服务器,并将其用作临时表。
/* * Add file with users ids to builder as _users table * Also, we must define data structure in file. In example below * structure will be like ['UInt64'] */ $builder->addFile('users.csv', '_users', ['UInt64']); $builder->select(raw('count()'))->from('clicks')->whereIn('userId', new Identifier('_users'));
将产生
SELECT count() FROM `clicks` WHERE `userId` IN `_users`
如果你想让表自动检测,请在调用 whereIn 之前调用 addFile 方法。
你可以在查询构建器的 whereIn、prewhereIn、havingIn 和 join 语句中使用本地文件。
Prewhere, where, having
所有示例都将关于 where,但 prewhere 和 having 也有相同的行为。
$builder->from('table')->where('column', '=', 'value'); $builder->from('table')->where('column', 'value');
SELECT * FROM `table` WHERE `column` = 'value'
所有字符串值都将用单引号括起来。如果没有提供运算符,则使用 =。如果没有提供运算符并且值是数组,则使用 IN。
$builder->from('table')->where(function ($query) { $query->where('column1', 'value')->where('column2', 'value'); });
SELECT * FROM `table` WHERE (`column1` = 'value' AND `column2` = 'value')
如果第一个参数传递了闭包,那么内部的所有 where 语句都将用括号括起来。但如果在该构建器(闭包内部)指定了 from,则它将被转换为子查询。
$builder->from('table')->where(function ($query) { $query->select('column')->from('table'); })
SELECT * FROM `table` WHERE (SELECT `column` FROM `table`)
对于值参数,几乎相同,只是没有括号。传递给值参数的任何闭包或构建器实例都将转换为子查询。
$builder->from('table')->where('column', 'IN', function ($query) { $query->select('column')->from('table'); });
SELECT * FROM `table` WHERE `column` IN (SELECT `column` FROM `table`)
你也可以传递该语句的内部表示,它将被使用。我不会深入解释这一点,因为这不是首选的用法。
像连接一样,有许多具有硬编码参数的辅助函数。
$builder->where(); $builder->orWhere(); $builder->whereRaw(); $builer->orWhereRaw(); $builder->whereIn(); $builder->orWhereIn(); $builder->whereGlobalIn(); $builder->orWhereGlobalIn(); $builder->whereGlobalNotIn(); $builder->orWhereGlobalNotIn(); $builder->whereNotIn(); $builder->orWhereNotIn(); $builder->whereBetween(); $builder->orWhereBetween(); $builder->whereNotBetween(); $builder->orWhereNotBetween(); $builder->whereBetweenColumns(); $builder->orWhereBetweenColumns(); $builder->whereNotBetweenColumns(); $builder->orWhereNotBetweenColumns();
还有一个通过字典创建 where 的方法
$builder->whereDict('dict', 'attribute', 'key', '=', 'value');
SELECT dictGetString('dict', 'attribute', 'key') as `attribute` WHERE `attribute` = 'value'
如果你想要使用复杂的键,你可以传递一个数组作为 $key,然后数组将被转换为元组。默认情况下,所有字符串都将用单引号括起来,但你可以传递一个 Identifier 实例来传递,例如列名
$builder->whereDict('dict', 'attribute', [new Identifier('column'), 'string value'], '=', 'value');
将产生
SELECT dictGetString('dict', 'attribute', tuple(`column`, 'string value')) as `attribute` WHERE `attribute` = 'value'
Group By
与 select 类似。
$builder->from('table')->select('column', raw('count()')->groupBy('attribute');
最终的查询将像
SELECT `column`, count() FROM `table` GROUP BY `attribute`
Order By
$builder->from('table')->orderBy('column', 'asc', 'fr');
在上面的例子中,第三个参数是可选的
SELECT * FROM `table` ORDER BY `column` ASC COLLATE 'fr'
别名
$builder->orderByAsc('column'); $builder->orderByDesc('column');
对于列,其行为与 select 方法中相同。
Limit
有两种类型的限制。限制和限制 n by。
Limit n by
$builder->from('table')->limitBy(1, 'column1', 'column2');
将产生
SELECT * FROM `table` LIMIT 1 BY `column1`, `column2`
简单的限制
$builder->from('table')->limit(10, 100);
将产生
SELECT * FROM `table` LIMIT 100, 10
$builder->from('table')->limit(10, 100);
SELECT * FROM `table` LIMIT 100, 10
UNION ALL
在unionAll方法中可以传递闭包或构建器实例。如果是闭包内部,将传递构建器实例。
$builder->from('table')->unionAll(function($query) { $query->select('column1')->from('table'); })->unionAll($builder->select('column2')->from('table'));
SELECT * FROM `table` UNION ALL SELECT `column1` FROM `table` UNION ALL SELECT `column2` FROM `table`
执行请求并获取结果。
在构建请求后,您必须调用get()方法将请求发送到服务器。还有机会进行异步请求。它的功能几乎与unionAll相同。
$builder->from('table')->asyncWithQuery(function($query) { $query->from('table'); }); $builder->from('table')->asyncWithQuery($builder->from('table')); $builder->from('table')->asyncWithQuery()->from('table');
这些调用将产生相同的行为。两个将异步执行的查询。现在,如果您调用get()方法,结果将返回一个数组,其中数值索引对应于具有该编号的请求的结果。