arungowda325/clickhouse-query-builder

该软件包最新版本(1.1.0)没有提供许可证信息。

Clickhouse SQL 查询构建器

1.1.0 2023-06-30 06:15 UTC

This package is auto-updated.

Last update: 2024-09-30 01:32:48 UTC


README

Build Status Coverage Status

需求

php 7.1+

安装

通过 composer

composer require arungowda325/clickhouse-builder

使用方法

要使用查询构建器,我们必须先实例化并传递给构造函数 arungowda325/clickhouse-php-client

$server = new Wolverine\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass');
$serverProvider = (new Wolverine\Clickhouse\ServerProvider())->addServer($server);

$client = new Wolverine\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`

还有许多具有硬编码参数的辅助函数,例如严格或类型及其组合。

$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 存储在本地文件中,将其上传到服务器,并将其用作临时表。

有关本地文件的更多信息,请参阅此处的“使用本地文件”部分。

选择

您应该传递具有声明表结构的 TempTable 实例,将其附加到查询中。

$builder->addFile(new TempTable('numbersTable', 'numbers.tsv', ['number' => 'UInt64'], Format::TSV));

$builder->table(raw('numbers(0,1000)')->whereIn('number', 'numbersTable')->get();

如果您希望自动检测表,请在调用 whereIn 之前调用 addFile 方法。

您可以在查询构建器的 whereInprewhereInhavingInjoin 语句中使用本地文件。

插入

如果您想将文件或文件插入 Clickhouse,可以使用 insertFileinsertFiles 方法。

$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 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

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' => [
        ...
        \Wolverine\ClickhouseBuilder\Integrations\Laravel\ClickhouseServiceProvider::class,
        ...
    ]

Lumen

bootstrap/app.php 中添加

$app->register(\Wolverine\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(...);

您可以使用 serversclusters 配置指令,并通过 onClusterusing 方法选择查询应在哪个服务器上执行。如果您想选择集群之外的服务器,只需调用 onCluster(null) 然后调用 using 方法。您可以使用带有或不带有选择集群的 usingRandomServerusing 方法。