stvkoch / simple-query
简单但强大的查询构建器。支持子查询条件。查看测试文件夹以了解其易用性。
Requires
- crysalead/inflector: ^2.0
Requires (Dev)
- phpunit/phpunit: ^5.0
This package is not auto-updated.
Last update: 2024-09-14 18:36:00 UTC
README
路线图
- calculate query hashCode independ of insertion order. For this change array to splheap
README 索引
- 简单 SELECT 查询
- 模型
- 查询方法
- 示例
- 改进
在示例中查看
简单 SELECT 查询
$model = \Simple\Model(['table'=>'superA', 'alias'=>'A']);
$query = (new \Simple\Query($model))
->where($model->field('username'), 'superUser');
echo $query->sqlSelect();
// SELECT A.* FROM superA AS A WHERE A.username = (?)
// use 'bindParameters' propriety to bind parameters in your database statement
$query->bindParameters
// ['superUser']
// more real example
$supossed_mysql_stmt = $con->prepare($query->sqlSelect());
// you can bind_param this way
foreach ($query->bindParameters as $value) {
$supossed_mysql_stmt->bind_param(
$query->type($value), // return 'i', 'd' or 's'
$value
);
}
...
为什么我们不基于自己的字符串 SQL 构建?
使用 SQL Builder 您可以
- increase security, avoid sql injection.
- create powerful query without specific order.
- use bind values.
- create easy subquery conditions using query object.
- apply patterns to interprete request and build personal queries.
- not dependent of ORMs.
关于模型
模型允许将表结构分离,以避免在创建更复杂的查询时发生冲突。
构造函数
$model = new \Simple\Model([
'table' => 'nameOfTable',
'alias' => 'shortName',
'pk' => 'id' ## default value
]);
pk()
模型(表)的主键
#example
$model = new \Simple\Model([
'table'=>'superA',
'alias'=>'A'
]);
echo $model->pk();
# A.id
fk(\Simple\Model $modelB)
如何将模型 $modelB 中的键在 Model 中表示为外键。这在连接时非常有用。
#example
$modelA = new \Simple\Model([
'table'=>'superA',
'alias'=>'A'
]);
$modelB = new \Simple\Model([
'table'=>'megaB',
'alias'=>'B'
]);
echo $modelA->fk($modelB);
# A.idMegaB
field($fieldName)
有用的方法返回防冲突的字段名
$modelA = new \Simple\Model([
'table'=>'superA',
'alias'=>'A'
]);
echo $modelA->field('name');
# A.name
table()
返回表名
alias()
返回别名表
现在我们可以构建查询了!!
namespace My\Model;
class User extends \Simple\Model {
protected $table = 'user';
protected $alias = 'us';
}
$userModel = new \My\Model\User();
$query = new \Simple\Query($userModel);
$query->where($userModel->field('username'), $usernameParameter);
$stmt = $mysql_con->prepare($query->sqlSelect());
....
多个条件
# example A
$userModel = new \Simple\Model(['table'=>'users']);
$query = new \Simple\Query($userModel);
$query->where($userModel->field('username'), $value);
$query->where($userModel->field('password'), $hashPass);
# example B
$userModel = new \Simple\Model(['table'=>'users']);
$query = new \Simple\Query($userModel);
$query->where($userModel->field('name'), 'John%', 'LIKE');
# OR condition
$query->where($userModel->field('surename'), 'John%', 'LIKE', 'OR');
...
# query equal method don't use bind parameter. equal method inject value inside of query. and work in the same way of where
$query->equal($model->field('status'), 1);
# IS NULL
$query->where($model->field('age'), 'NULL', 'IS');
# IS NOT NULL
$query->where($model->field('age'), 'NULL', 'IS NOT');
子查询条件
$modelUser = new \Simple\Model(['table'=>'user']);
$modelOrder = new \Simple\Model(['table'=>'order']);
// get all user are active customer in holiday month
$queryOrder = new \Simple\Query($modelOrder);
$queryOrder->field($modelOrder->fk($modelUser))
->where('createAt BETWEEN (?) AND (?)', ['2015-12-01','2015-12-31'], 'RAW')
->group($modelOrder->fk($modelUser));
$query = new \Simple\Query($modelUser);
$query->where($modelUser->field($modelUser->pk()), $queryOrder, 'IN')
->order($modelUser->field('name'))
->page(1, 20);
+'SELECT user.* FROM user WHERE user.id IN (SELECT order.idUser FROM order WHERE createAt BETWEEN (?) AND (?) GROUP BY order.idUser) ORDER BY user.name ASC LIMIT 0, 20'
Where
添加条件。这适用于 'having' 方法
$query
->where($fieldName, $valueToBind, $function = '=', $operator = 'AND')
->where(...);
支持条件函数
'=','>','<','<=','>='
'IS'
'IS NO'
'IN'
'NOT IN'
'RAW' (not apply function condition, you should provide complete condition)
示例
'=','>','<','<=','>=', '!='
$query->where('field', $value, '!=');
'IN' 或 'NOT IN'
$query->where('field', array($value1, $value2), 'IN');
'RAW'(不应用函数条件,您应该提供完整的条件)RAW 函数是一个强大的函数条件。
$query->where('name = (?) AND age = (?) AND actice=1', [$value1, $value2], 'RAW');
equal
equal 方法添加未由查询解析或编码的条件。这是一个危险功能,但有必要在将键表添加到连接条件时使用。
$queryJoin = new \Simple\Query($modelB); $queryJoin->equal($modelA->pk(), $modelB->fk($modelA));
分组
$query->group($model->pk());
$query->group($model->field('name'));
...
排序
$query->order($model->field('name'), 'DESC');
// accept DESC or ASC
连接
连接是另一个复杂结构,\Simple\Query 帮助您使其简单而强大。使用 \Simple\Query,您可以连接模型和查询对象。连接表使用表间相关键进行工作。通常这些键是某个表的主键和您的外键(表示某个表的主键)
\Simple\Model 有两个方法可以帮助您组织键 pk() 和 fk()。
#example A
$modelA = new ModelA();
$modelB = new ModelB();
$query = new \Simple\Query($modelA);
$query->join('left', $modelB);
#example A.2. Allow join queries
$modelA = new ModelA();
$modelB = new ModelB();
$query = new \Simple\Query($modelA);
$query->join('left',
(new \Simple\Query($modelB))
->equal($modelA->pk(), $modelA->fk($modelB))
->where('name', $paramName)
);
分页或限制
# calc limit and offset based on page and perPage values
$query->page($page, $perPage);
# or you can use limit and offset directly
$query->limit(0, 10);
构建 SQL SELECT
$query->sqlSelect();
构建 SQL COUNT
$query->sqlCountSelect();
构建 SQL UPDATE
$query->sqlUpdate();
构建 SQL INSERT
$query->sqlInsert();
构建 SQL DELETE
$query->sqlDelete();
绑定参数
当您与值一起工作时,Simple Query Build 总是与 SQL 语句一起工作。
$stmt = $con->prepare($query->sqlSelect()); $query->bind($stmt)->execute()->get_result();
或者您可以通过这种方式绑定您的值
# more real example
$supossed_mysql_stmt = $con->prepare($query->sqlSelect());
# you can bind_param this way
foreach ($query->bindParameters as $value) {
$supossed_mysql_stmt->bind_param(
$query->type($value),#return 'i', 'd' or 's'
$value
);
}
改进
- 创建用于 WHERE、ORDER 和 JOIN 中的字段的索引。
- 尝试在组合索引中将条件字段分组。
- 使用正确的类型长度来存储您的数据。只有在真正需要时才使用大数据存储数据类型!
- 基准测试您的查询和索引。
- 使用 EXPLAIN 来发现如何以及需要改进什么。
- 尝试发现是否在 PHP 端分页更快。基准测试这个选择!
- 即使 COUNT 查询,如果是在 PHP 端计算更快,也应进行基准测试。
- 在生产环境中禁用查询日志。