the-tinderbox / clickhouse-builder
Clickhouse SQL 查询构建器
Requires
- php: ^7.1|^8.0
- myclabs/php-enum: ^1.5
- the-tinderbox/clickhouse-php-client: ^3.0
Requires (Dev)
- illuminate/config: 5.*
- illuminate/database: 5.*
- illuminate/events: 5.*
- illuminate/pagination: 5.*
- mockery/mockery: ^0.9.9|^1.4
- phpunit/phpunit: ^6.1|^9.5
- dev-master
- 6.1.0
- 6.0.0
- 5.3.0
- 5.2.1
- 5.2.0
- 5.1.1
- 5.1.0
- 5.0.0
- 4.1.0
- 4.0.3
- 4.0.2
- 4.0.1
- 4.0.0
- 3.1.0
- 3.0.1
- 3.0.0
- 2.3.0
- 2.2.0
- 2.1.0
- 2.0.2
- 2.0.1
- 2.0.0
- 1.3.0
- 1.2.1
- 1.2.0
- 1.1.2
- 1.1.1
- 1.1.0
- 1.0.13
- 1.0.12
- 1.0.11
- 1.0.10
- 1.0.9
- 1.0.8
- 1.0.7
- 1.0.6
- 1.0.5
- 1.0.4
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
- dev-optimize_builder_insert
- dev-proxy_and_join
- dev-stable_release
- dev-new_release
This package is auto-updated.
Last update: 2024-08-30 01:26:01 UTC
README
需求
php 7.1+
安装
通过 composer
composer require the-tinderbox/clickhouse-builder
用法
为了使用查询构建器,我们必须先实例化并传递给构造函数 the-tinderbox/clickhouse-php-client
。
$server = new Tinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass'); $serverProvider = (new Tinderbox\Clickhouse\ServerProvider())->addServer($server); $client = new Tinderbox\Clickhouse\Client($serverProvider); $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, 'alias');
SELECT * FROM `table` GLOBAL ANY LEFT JOIN `another_table` AS `alias` USING `column1`, `column2`
要作为第一个参数执行子查询,您可以通过传递闭包或构建器。
$builder->from('table')->join(function ($join) { $join->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`
此外,还有许多具有硬编码参数的辅助函数,例如 strict 或 type 以及它们的组合。
$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']);
您也可以使用数组连接。
$builder->from('test')->arrayJoin('someArr'); $builder->from('test')->leftArrayJoin('someArr');
SELECT * FROM `test` ARRAY JOIN `someArr` SELECT * FROM `test` LEFT ARRAY JOIN `someArr`
临时表的使用
有些情况下,您需要根据用户的 ID 过滤用户,但 ID 的数量很大。您可以将用户 ID 存储在本地文件中,将其上传到服务器,并将其用作临时表。
有关本地文件的更多信息,请参阅 此处 的 Using local files
部分。
选择
您应该传递具有声明表结构的 TempTable
实例来附加文件到查询。
$builder->addFile(new TempTable('numbersTable', 'numbers.tsv', ['number' => 'UInt64'], Format::TSV)); $builder->table(raw('numbers(0,1000)')->whereIn('number', 'numbersTable')->get();
如果您希望自动检测表,请在调用 whereIn
之前调用 addFile
方法。
您可以在查询构建器的 whereIn
、prewhereIn
、havingIn
和 join
语句中使用本地文件。
插入
如果您想将文件或文件插入 Clickhouse,可以使用 insertFile
和 insertFiles
方法。
$builder->table('test')->insertFile(['date', 'userId'], 'test.tsv', Format::TSV);
或者您可以将文件批次传递到 insertFiles
方法,所有文件都将异步插入。
$builder->table('test')-insertFiles(['date', 'userId'], [
'test-1.tsv',
'test-2.tsv',
'test-3.tsv',
'test-4.tsv',
'test-5.tsv',
'test-6.tsv',
'test-7.tsv',
], Format::TSV)
此外,您还可以使用辅助函数并将数据插入具有 Memory 引擎的临时表。
$builder->table('test')->values('test.tsv')->format(Format::TSV);
into_memory_table($builder, [
'date' => 'Date',
'userId' => 'UInt64'
]);
辅助函数将删除名为 test
的临时表并创建具有声明结构、Memory 引擎的表,并将来自 test.tsv
文件的数据插入到刚刚创建的表中。
如果您想在执行查询并删除它之后填充某些表,这很有帮助。
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
有两种类型的limit。Limit和limit n by。
Limit n by
$builder->from('table')->limitBy(1, 'column1', 'column2');
将产生
SELECT * FROM `table` LIMIT 1 BY `column1`, `column2`
简单limit
$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()
方法,结果将返回一个数组,其中数字索引对应于具有此编号的请求的结果。
集成
Laravel或Lumen < 5.5
您可以在Laravel/Lumen应用程序中使用此构建器。
Laravel
在config/app.php
中添加
'providers' => [ ... \Tinderbox\ClickhouseBuilder\Integrations\Laravel\ClickhouseServiceProvider::class, ... ]
Lumen
在bootstrap/app.php
中添加
$app->register(\Tinderbox\ClickhouseBuilder\Integrations\Laravel\ClickhouseServiceProvider::class);
通过config/database.php
进行连接配置。
单个服务器的示例
'connections' => [ 'clickhouse' => [ 'driver' => 'clickhouse', 'host' => 'ch-00.domain.com', 'port' => '', 'database' => '', 'username' => '', 'password' => '', 'options' => [ 'timeout' => 10, 'protocol' => 'https' ] ] ]
获取一个新的构建器
DB::connection('clickhouse')->query();
或者
'connections' => [ 'clickhouse' => [ 'driver' => 'clickhouse', 'servers' => [ [ 'host' => 'ch-00.domain.com', 'port' => '', 'database' => '', 'username' => '', 'password' => '', 'options' => [ 'timeout' => 10, 'protocol' => 'https' ] ], [ 'host' => 'ch-01.domain.com', 'port' => '', 'database' => '', 'username' => '', 'password' => '', 'options' => [ 'timeout' => 10, 'protocol' => 'https' ] ] ] ] ]
集群的示例
'connections' => [ 'clickhouse' => [ 'driver' => 'clickhouse', 'clusters' => [ 'cluster-name' => [ [ 'host' => '', 'port' => '', 'database' => '', 'username' => '', 'password' => '', 'options' => [ 'timeout' => 10, 'protocol' => 'https' ] ], [ 'host' => '', 'port' => '', 'database' => '', 'username' => '', 'password' => '', 'options' => [ 'timeout' => 10, 'protocol' => 'https' ] ] ] ] ] ]
带标签的服务的示例
'connections' => [ 'clickhouse' => [ 'driver' => 'clickhouse', 'servers' => [ [ 'host' => 'ch-00.domain.com', 'port' => '', 'database' => '', 'username' => '', 'password' => '', 'options' => [ 'timeout' => 10, 'protocol' => 'https', 'tags' => [ 'tag' ], ], ], [ 'host' => 'ch-01.domain.com', 'port' => '', 'database' => '', 'username' => '', 'password' => '', 'options' => [ 'timeout' => 10, 'protocol' => 'https' ], ], ], ], ]
选择没有集群的服务器
DB::connection('clickhouse')->using('ch-01.domain.com')->select(...);
或者在每个新查询上随机执行服务器
DB::connection('clickhouse')->usingRandomServer()->select(...);
选择集群
DB::connection('clickhouse')->onCluster('test')->select(...);
使用带标签的服务器
DB::connection('clickhouse')->usingServerWithTag('tag')->select(...);
您可以使用servers
和clusters
配置指令,并通过onCluster
和using
方法选择应在哪个服务器上执行查询。如果您想选择集群外的服务器,只需调用onCluster(null)
然后调用using
方法。您可以调用usingRandomServer
和using
方法,所选集群或否。