qstart-soft/query-builder

用于创建 DML(数据操作语言)SQL 语句的库。

v1.0.4 2024-09-30 20:44 UTC

This package is auto-updated.

Last update: 2024-09-30 20:47:26 UTC


README

用于创建 DML(数据操作语言)SQL 语句的库。

  • 第1部分:基础
  • 第2部分:表格格式
  • 第3部分:条件格式
  • 第4部分:SELECT SQL 语句
  • 第5部分:INSERT SQL 语句
  • 第6部分:UPDATE SQL 语句
  • 第7部分:DELETE SQL 语句

第1部分:基础

入口点
创建 SQL 语句的入口点是 Query::class 工厂。

use Qstart\Db\QueryBuilder\Query;

$select = Query::select();
$insert = Query::insert();
$update = Query::update();
$delete = Query::delete();

创建
获取 SQL 语句和绑定参数

use Qstart\Db\QueryBuilder\Query;

$query = Query::select();
// ...
$builder = $query->getQueryBuilder()
// If necessary, you can set the dialect for the query builder
$builder->setDialect(DialectSQL::POSTGRESQL);

$expr = $builder->build();
// Binding parameters
$params = $expr->getParams();
// Sql string
$sql = $expr->getExpression();

表达式
表达式是继承自 \Qstart\Db\QueryBuilder\DML\Expression\ExprInterface 接口的自定义类。
这些类允许您为 SQL 查询创建特定表达式。

初始表达式类允许您传递一个不可变的表达式,该表达式将添加到查询中而不会被修改

use Qstart\Db\QueryBuilder\DML\Expression\Expr;

$expr = new Expr('created_at > now()');

// This is the sql expression
$expression = $expr->getExpression();
// This is the binding params
$params = $expr->getParams();

其他几个表达式

use Qstart\Db\QueryBuilder\DML\Expression\BetweenExpr;
use Qstart\Db\QueryBuilder\DML\Expression\CompareExpr;
use Qstart\Db\QueryBuilder\DML\Expression\InExpr;

$expr = new CompareExpr('!=', 'id', 20);
$expression = $expr->getExpression();
// id != :v1
$params = $expr->getParams();
// ['v1' => 20]

$expr = new BetweenExpr('id', 10, 20);
$expression = $expr->getExpression();
// id BETWEEN :v1 AND :v2
$params = $expr->getParams();
// ['v1' => 10, 'v2' => 20]

$expr = new InExpr('id', [10, 20], true);
$expression = $expr->getExpression();
// id NOT IN (:v3, :v4)
$params = $expr->getParams();
// ['v3' => 10, 'v4' => 20]

确实,对于不同的 SQL 语法,相同的构造可能具有不同的语法。
为此,您可以将方言传递到表达式中。

use Qstart\Db\QueryBuilder\DML\Expression\Expr;
use Qstart\Db\QueryBuilder\Helper\DialectSQL;

$expr = new Expr('created_at > now()');

$expressionCh = $expr->getExpression(DialectSQL::CLICKHOUSE);
$expressionPg = $expr->getExpression(DialectSQL::POSTGRESQL);
$params = $expr->getParams();

第2部分:表格格式

所有可用方法中的表格格式相同

  • join()
  • innerJoin()
  • leftJoin()
  • rightJoin()
  • SelectQuery::from()
  • UpdateQuery::joinFrom()
  • UpdateQuery::setTable()
  • InsertQuery::into()
  • DeleteQuery::from()

可用格式(以 SelectQuery::from() 方法为例)

use Qstart\Db\QueryBuilder\Query;
use Qstart\Db\QueryBuilder\DML\Expression\Expr;

$query = Query::select();

// Table name only
$query->from('user');
$query->from(['user']);
// Table name with alias
$query->from('user u');
$query->from(['u' => 'user']);

// You can also pass an expression or another query instead of the table name
$query->from(['u' => Query::select()->from('user')]);
// Result: SELECT * FROM (SELECT * FROM user) AS u
$query->from(['u' => new Expr("(SELECT * FROM user)")]);
// Result: SELECT * FROM (SELECT * FROM user) AS u
// Same thing without alias
$query->from(Query::select()->from('user'));
$query->from(new Expr("SELECT * FROM user"));

// You can also set several tables in any available format
$query->from(['u' => 'user', 's' => 'session']);
// Result: SELECT * FROM user AS u, session AS s

您还可以更改第一个表的别名

  • SelectQuery::from()
  • UpdateQuery::setTable()
  • InsertQuery::into()
  • DeleteQuery::from()

示例

use Qstart\Db\QueryBuilder\Query;

$query = Query::select()->from(['user'])->alias('u');
// Result: SELECT * FROM user AS u

$query = Query::select()->from(['u' => 'user'])->alias('t');
// Result: SELECT * FROM user AS t

$query = Query::select()->from(['u' => 'user', "s" => "session"])->alias('t');
// Result: SELECT * FROM user AS t, session AS s

第3部分:条件格式

任何条件都可以以下格式传递

1. 相等条件数组。

数组是键值对。键是左侧表达式。值是以下选项之一

use Qstart\Db\QueryBuilder\Query;
use Qstart\Db\QueryBuilder\DML\Expression\Expr;

$conditions = ['user_id' => 10, 'session_id' => 101];
// user_id = 10 AND session_id = 101
$conditions = ['user_id' => [10, 20], 'session_id' => 101];
// user_id IN (10, 20) AND session_id = 101
$conditions = ['user_id' => Query::select()->select('id')->from('user'), 'session_id' => 101];
// user_id IN (SELECT id FROM user) AND session_id = 101
$conditions = ['user_id' => new Expr("LEAST(10, 20)"), 'session_id' => 101];
// user_id = LEAST(10, 20) AND session_id = 101

Query::select()->where($conditions);

2. 任何继承自 ExprInterface 的 Expression 实例

use Qstart\Db\QueryBuilder\Query;
use Qstart\Db\QueryBuilder\DML\Expression\Expr;
use Qstart\Db\QueryBuilder\DML\Expression\InExpr;

$conditions = new Expr('created_at >= now()');
// created_at >= now()
$conditions = new InExpr('id', [10, 20], true);
// id NOT IN (10, 20)

Query::select()->where($conditions);

3. 字符串格式

use Qstart\Db\QueryBuilder\Query;

$conditions = 'created_at >= now()'
Query::select()->from('user')->where($conditions);
// SELECT * FROM user WHERE created_at >= now()

$conditions = [
    'and',
    'created_at >= now()',
    ['id' => 2]
]
Query::select()->from('user')->where($conditions);
// SELECT * FROM user WHERE (created_at >= now()) AND (id = 2)

4. 使用 "OR"、"AND"、"NOT" 操作符进行分组

然后需要使用 AND、OR、NOT 操作符组合条件。
所有这些组合都具有相同的格式 [operator, condition, condition, ...]

数组中的第一个必须是 AND / OR / NOT 操作符。
接下来,通过逗号分隔,是条件,可以是三种格式之一(数组、表达式、字符串)。这些条件也可以使用 AND / OR / NOT 操作符的格式

例如:['AND', $condition1, $condition2, ['OR', $condition3, $condition4]]

use Qstart\Db\QueryBuilder\DML\Expression\Expr;
use Qstart\Db\QueryBuilder\DML\Expression\InExpr;

$conditions = ['and', ['user_id' => 10, 'session_id' => 101], new Expr("id = LEAST(10, 20)")];
// (user_id = 10 AND session_id = 101) AND (id = LEAST(10, 20))
$conditions = ['or', ['user_id' => 10, 'session_id' => 101], new Expr("id = LEAST(10, 20)")];
// (user_id = 10 AND session_id = 101) OR (id = LEAST(10, 20))
$conditions = ['not', ['user_id' => 10, 'session_id' => 101], new Expr("id = LEAST(10, 20)")];
// NOT ((user_id = 10 AND session_id = 101) AND (id = LEAST(10, 20)))

// Lets combine it
$conditions = [
    'and',
    ['or', ['id' => 2], ['id' => 3]],
    ['not', ['session_id' => 10]]
];
// ((id = 2) OR (id = 3)) AND (NOT (session_id = 10))

如何使用 SELECT 查询,例如

use Qstart\Db\QueryBuilder\Query;

$query = Query::select()->where(['and', $condition1, $condition2]);
// Its equal with:
$query = Query::select()->where($condition1)->andWhere($condition2);

$query = Query::select()->where(['or', $condition1, $condition2]);
// Its equal with:
$query = Query::select()->where($condition1)->orWhere($condition2);

第4部分:SELECT SQL 语句

1. 选择

要构建 SELECT 子句,您需要使用方法

  • Query::select()->select() 创建 SELECT 子句
  • Query::select()->addSelect() 添加值到 SELECT 子句
  • Query::select()->distinct(true) 添加 DISTINCT 关键字

方法 select() 会覆盖之前添加的所有值!

子句可以以不同的格式构建。

use Qstart\Db\QueryBuilder\Query;
use Qstart\Db\QueryBuilder\DML\Expression\Expr;

// 1. String format
Query::select()->select('id, name, surname');

// 2. Array alias-value format
Query::select()
    ->select([
        'id',
        'name' => "name || ' ' || surname",
        new Expr('created_at::DATE as date'),
        'cnt' => Query::select()->select('COUNT(*)')->from('user')
    ]);
// Result: SELECT id, name || ' ' || surname AS name, created_at::DATE as date, (SELECT COUNT(*) FROM user) AS cnt

// 3. Add values
Query::select()->select('id, name')->addSelect(new Expr('created_at::DATE as date'));
// Result: SELECT id, name, created_at::DATE as date

// 4. Reset values
Query::select()->select(null);

// 4. Distinct
Query::select()->select('id, name')->distinct(true);
// // Result: SELECT DISTINCT id, name

2. WHERE

要构建 WHERE 子句,您需要使用方法

  • Query::select()->where() 创建 WHERE 子句
    Query::select()->andWhere() 使用 AND 操作符将条件添加到当前条件中。相同 - ['and', current conditions, new conditions]
  • Query::select()->orWhere() 使用 OR 操作符将条件添加到当前条件中。相同 - ['or', current conditions, new conditions]
    方法 where() 会覆盖之前添加的所有值!
  • 所有方法都接受在 '条件格式' 中描述的格式中的条件。
    您还可以使用将移除条件中所有 NULL 值的方法。对于 Expression 实例,将调用 ExprInterface::isEmpty() 方法。

Query::select()->filterWhere()

Query::select()->andFilterWhere()

use Qstart\Db\QueryBuilder\Query;

Query::select()->where(['id' => 2])->andWhere(['user_id' => 3]);

Query::select()->orFilterWhere()

  • 方法 filterWhere() 会覆盖之前添加的所有值!
  • Query::select()->andFilterWhere()
  • Query::select()->orFilterWhere()

方法 filterWhere() 会覆盖之前添加的所有值!

Query::select()->andFilterWhere()

use Qstart\Db\QueryBuilder\Query;
use Qstart\Db\QueryBuilder\DML\Expression\CompareExpr;

Query::select()->filterWhere(['id' => null])->andFilterWhere(new CompareExpr('>=', 'id', null));
// Result will be without WHERE clause

3. 分组 BY

要构建GROUP BY子句,您需要使用方法

  • Query::select()->groupBy() 创建GROUP BY子句
  • Query::select()->addGroupBy() 向GROUP BY子句添加值

方法groupBy()会覆盖之前添加的所有值!

子句可以以不同的格式构建。

use Qstart\Db\QueryBuilder\Query;

// 1. String format
Query::select()->from('user')->groupBy('id, name');
// SELECT * FROM user GROUP BY id, name

// 2. Array format
Query::select()->from('user')->groupBy(['id', 'name']);
// SELECT * FROM user GROUP BY id, name

// 3. Expression/Query format
Query::select()->from('user')->groupBy(new Expr('id, name'));
// SELECT * FROM user GROUP BY id, name

// 4. Add values
Query::select()->from('user')->groupBy('id, name')->addGroupBy(new Expr('created_at::DATE'));
// Result: SELECT * FROM user GROUP BY  id, name, created_at::DATE

// 5. Reset values
Query::select()->groupBy(null);

4. 排序

要构建ORDER BY子句,您需要使用方法

  • Query::select()->orderBy() 创建ORDER BY子句
  • Query::select()->addOrderBy() 向ORDER BY子句添加值

方法orderBy()会覆盖之前添加的所有值!

子句可以以不同的格式构建。

use Qstart\Db\QueryBuilder\Query;

// 1. String format
Query::select()->from('user')->orderBy('id, name');
// SELECT * FROM user ORDER BY id, name

// 2. Array format
Query::select()->from('user')->orderBy(['id' => SORT_ASC, 'name' => SORT_DESC]);
// SELECT * FROM user ORDER BY id ASC, name DESC

// 3. Expression/Query format
Query::select()->from('user')->orderBy(new Expr('id ASC, name DESC'));
// SELECT * FROM user ORDER BY id ASC, name DESC

// 4. Mix format
Query::select()->from('user')->orderBy(['id' => SORT_ASC, 'name' => SORT_DESC, new Expr('created_at::DATE DESC')]);
// SELECT * FROM user ORDER BY id ASC, name DESC, created_at::DATE DESC

// 5. Add values
Query::select()->from('user')->orderBy('id DESC')->addOrderBy(new Expr('created_at::DATE DESC'));
// Result: SELECT * FROM user ORDER BY id DESC, created_at::DATE DESC

// 6. Reset values
Query::select()->orderBy(null);

5. HAVING

要构建HAVING子句,您需要使用方法

  • Query::select()->having()
  • Query::select()->andHaving()
  • Query::select()->orHaving()

方法having()会覆盖之前添加的所有值!

这些方法的工作方式与'WHERE'方法类似。

6. OFFSET

要构建OFFSET子句,您需要使用方法

  • Query::select()->offset()

使用null值来禁用偏移。
偏移量可以是int|ExprInterface|SelectQuery|null

use Qstart\Db\QueryBuilder\Query;

// 1. Integer
Query::select()->from('user')->offset(10);
// SELECT * FROM user OFFSET 10

// 2. Expression
Query::select()->from('user')->offset(new Expr("length('SPARK')"));
// SELECT * FROM user OFFSET length('SPARK')

// 2. Reset value
Query::select()->from('user')->offset(null);

7. LIMIT

要构建LIMIT子句,您需要使用方法

  • Query::select()->limit()

使用null值来禁用限制。
偏移量可以是int|ExprInterface|SelectQuery|null

use Qstart\Db\QueryBuilder\Query;

// 1. Integer
Query::select()->from('user')->limit(10);
// SELECT * FROM user LIMIT 10

// 2. Expression
Query::select()->from('user')->limit(new Expr("length('SPARK')"));
// SELECT * FROM user LIMIT length('SPARK')

// 2. Reset value
Query::select()->from('user')->limit(null);

8. JOIN

要构建不同的JOIN子句,您需要使用方法

  • Query::select()->join()
  • Query::select()->leftJoin()
  • Query::select()->rightJoin()
  • Query::select()->innerJoin()

所有这些方法都接受与“条件格式”部分中描述的格式相同的条件。
此外,所有这些方法都接受与“表格式”部分中描述的格式相同的表。

用法示例

use Qstart\Db\QueryBuilder\Query;

Query::select()->from('user u')->leftJoin('session s', 'u.id = s.user_id');
// Result: SELECT * FROM user u LEFT JOIN session s ON u.id = s.user_id

9. UNION

要使用联合查询,您需要使用方法。

  • Query::select()->union() 添加联合查询
  • Query::select()->deleteUnion() 删除所有联合查询

ORDER BY子句将从所有查询中组合并添加到联合查询的末尾

查询可以是string|ExprInterface|SelectQuery

use Qstart\Db\QueryBuilder\Query;
use Qstart\Db\QueryBuilder\DML\Expression\Expr;

$query = Query::select()
    ->from('table t')->where(['user_id' => 2])->orderBy('created_at')
    ->union(Query::select()->from('table2 t2')->where(['user_id' => 12])->orderBy('id'), true)
    ->union(Query::select()->from('table3 t3')->where(['user_id' => 22]))
    ->union(new Expr('SELECT * FROM table4 t4 WHERE user_id = :id', ['id' => 32]))
    ->union('SELECT * FROM table5 t5', true);

// Result:
<<<SQL
SELECT * FROM table t WHERE user_id = :v1
UNION ALL
SELECT * FROM table2 t2 WHERE user_id = :v2
UNION
SELECT * FROM table3 t3 WHERE user_id = :v3
UNION
SELECT * FROM table4 t4 WHERE user_id = :id
UNION ALL
SELECT * FROM table5 t5
ORDER BY created_at, id
SQL;

第5部分:INSERT SQL 语句

创建INSERT INTO语句的格式
INSERT INTO table_name (column1, column2, column3, ...) VALUES (value1, value2, value3, ...);

要指定表名使用

  • Query::insert()->into()
    此方法接受与“表格式”部分中描述的格式相同的表。

要向VALUES子句添加值组,请使用方法

  • Query::insert()->addValues($data)
    数据应为格式为[column1 => value1, ...]的数组或QueryInterface的实例
  • Query::insert()->addMultipleValues($data)
    数据应为格式为[column1 => value1, ...]的数组数组

要更改语句的开始或结束,请使用方法

  • Query::insert()->setStartOfQuery()
    表达式INSERT INTO将被替换为传递的表达式
  • Query::insert()->setEndOfQuery()
    表达式将被添加到查询的末尾
use Qstart\Db\QueryBuilder\Query;

$query = Query::insert()->into('user')->addValues(['name' => 'John', 'surname' => 'Jonson']);
// Result: INSERT INTO user (name, surname) VALUES (:v1, :v2)

$query->setStartOfQuery('INSERT IGNORE INTO')->setEndOfQuery('RETURNING id');
// Result: INSERT IGNORE INTO user (name, surname) VALUES (:v1, :v2) RETURNING id

$query = Query::insert()->into('user')->addMultipleValues([['name' => 'John', 'surname' => 'Jonson'], ['surname' => 'Nelson', 'name' => 'Mike']]);
// Result: INSERT INTO user (name, surname) VALUES (:v1, :v2), (:v4, :v3)

第6部分:UPDATE SQL 语句

1. 表

要指定表名使用

  • Query::update()->setTable()
    此方法接受与“表格式”部分中描述的格式相同的表。
use Qstart\Db\QueryBuilder\Query;

$query = Query::update()->setTable('user');
// Result: UPDATE user

2. SET

要构建SET子句,您需要使用方法

  • Query::update()->set($attributes)
    要创建SET子句
  • Query::update()->addSet($attributes)
    要将属性添加到SET子句

方法set()会覆盖之前添加的所有属性!

属性可以以不同的格式传递。
如果我们带有关键传递它,我们将尝试将值添加为查询参数。
如果未传递键,则值将是一个字符串。
值可以传递为字符串、ExprInterface实例或QueryInterface实例。

use Qstart\Db\QueryBuilder\Query;
use Qstart\Db\QueryBuilder\DML\Expression\Expr;

// 1. Format of attributes
$query = Query::update()
    ->setTable('"user"')
    ->set([
        'name' => 'John', // name=:v19,
        'age' => new Expr('18 + 10'), // age=18 + 10,
        'last_session_at' => Query::select()->from('session')->select('MAX(created_at)')->where(['user_id' => 123])
    ])
    ->addSet("status='active'") // status='active',
    ->addSet(new Expr('is_active = TRUE')); // is_active = TRUE,

// Result: UPDATE "user" SET name = :v1, age = 18 + 10, last_session_at = (SELECT MAX(created_at) FROM session WHERE user_id = :v2), status='active', is_active = TRUE

// 2. Reset SET clause
$query = Query::update()->setTable('"user"')->set(null);

3. WHERE

要构建WHERE子句,请参阅“第3部分. 选择SQL语句”中的描述。格式和方法将与选择SQL语句完全相同。

4. JOIN

要构建不同的JOIN子句,请参阅“第3部分. 选择SQL语句”中的描述。格式和方法将与选择SQL语句完全相同。

5. JOIN FROM

要构建FROM子句,您需要使用方法

  • Query::update()->joinFrom() 此方法接受与“表格式”部分中描述的格式相同的表。

使用空值禁用 FROM 子句

use Qstart\Db\QueryBuilder\Query;

$query = Query::update()->setTable('user')->joinFrom('session');
// Result: UPDATE user FROM session

6. 限制

要构建 LIMIT 子句,请参阅“第 3 部分. 选择 SQL 语句”中的说明。格式和方法将与选择 SQL 语句完全相同

7. 开始和结束子句

要更改语句的开始或结束,请使用方法

  • Query::update()->setStartOfQuery()
    表达式 UPDATE 将被传入的表达式替换
  • Query::update()->setEndOfQuery()
    表达式将被添加到查询的末尾
use Qstart\Db\QueryBuilder\Query;

$query = Query::update()
    ->setTable('user')
    ->setStartOfQuery('UPDATE ONLY')
    ->setEndOfQuery('RETURNING id');
// Result: UPDATE ONLY user RETURNING id

第7部分:DELETE SQL 语句

1. 从

要指定表名使用

  • Query::delete()->from()
    此方法接受与“表格式”部分中描述的格式相同的表。
use Qstart\Db\QueryBuilder\Query;

$query = Query::delete()->from('user');
// Result: DELETE FROM user

2. WHERE

要构建WHERE子句,请参阅“第3部分. 选择SQL语句”中的描述。格式和方法将与选择SQL语句完全相同。

3. 连接

要构建不同的JOIN子句,请参阅“第3部分. 选择SQL语句”中的描述。格式和方法将与选择SQL语句完全相同。

4. 使用

要构建 USING 子句,需要使用方法

  • Query::delete()->using() 此方法接受表格格式,如上述 '表格格式' 部分中所述。

使用空值禁用 USING 子句

use Qstart\Db\QueryBuilder\Query;

$query = Query::delete()->from('user')->using('session');
// Result: DELETE FROM user USING session

5. 限制

要构建 LIMIT 子句,请参阅“第 3 部分. 选择 SQL 语句”中的说明。格式和方法将与选择 SQL 语句完全相同

6. 开始和结束子句

要更改语句的开始或结束,请使用方法

  • Query::delete()->setStartOfQuery()
    表达式 DELETE FROM 将被传入的表达式替换
  • Query::delete()->setEndOfQuery()
    表达式将被添加到查询的末尾
use Qstart\Db\QueryBuilder\Query;

$query = Query::delete()
    ->from('user')
    ->setStartOfQuery('DELETE FROM ONLY')
    ->setEndOfQuery('RETURNING id');
// Result: DELETE FROM ONLY user RETURNING id