stvkoch/simple-query

此软件包最新版本(dev-master)没有提供许可证信息。

简单但强大的查询构建器。支持子查询条件。查看测试文件夹以了解其易用性。

dev-master 2017-12-22 17:53 UTC

This package is not auto-updated.

Last update: 2024-09-14 18:36:00 UTC


README

主分支 - 稳定版本:Travis-ci

开发 - 不稳定版本 Travis-ci

路线图

- 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 端计算更快,也应进行基准测试。
  • 在生产环境中禁用查询日志。