是否有可能做一个“之间?和?” cakephp 2.5 中的 LIKE 条件在哪里?在 cakephp 2.5 中,我写了类似的东西
'conditions' => ['start_date BETWEEN ? AND ?' => ['2014-01-01', '2014-12-32']]
我该如何迁移它?
另外我会写类似
'conditions' => [ '? BETWEEN start_date AND end_date'] => '2014-03-31']
是否有可能做一个“之间?和?” cakephp 2.5 中的 LIKE 条件在哪里?在 cakephp 2.5 中,我写了类似的东西
'conditions' => ['start_date BETWEEN ? AND ?' => ['2014-01-01', '2014-12-32']]
我该如何迁移它?
另外我会写类似
'conditions' => [ '? BETWEEN start_date AND end_date'] => '2014-03-31']
开箱即用地支持之间的表达式,但是它们仅支持第一种情况而无需额外的摆弄:
$Query = $Table
->find()
->where(function($exp) {
return $exp->between('start_date', '2014-01-01', '2014-12-32', 'date');
});
如果您想通过 between 方法处理第二种情况,那么您必须将所有值作为表达式传递,这很容易出错,因为在这种情况下它们不会受到转义/参数绑定的影响,您d 必须自己做(这不是推荐的!请参阅手册PDO::quote()
中的安全说明),类似于:
use Cake\Database\Expression\IdentifierExpression;
use Cake\Database\Expression\QueryExpression;
use Cake\ORM\Query;
// ...
$Query = $Table
->find()
->where(function(QueryExpression $exp, Query $query) {
return $exp->between(
$query->newExpr(
$query->connection()->driver()->quote(
'2014-03-31',
\PDO::PARAM_STR
)
),
new IdentifierExpression('start_date'),
new IdentifierExpression('end_date')
);
});
对于 CakePHP 附带的所有 SQL 方言都支持的这种基本 SQL 表达式,这可能有点不方便,因此您可能有理由在这里使用带有值 bindig 的原始 SQL 片段。
然而应该注意的是,当涉及到例如跨方言支持时,表达式通常是更好的选择,因为它们可以(或多或少)在编译时轻松转换,请参阅SqlDialectTrait::_expressionTranslators()
. 此外,表达式通常支持自动标识符引用。
通过手动值绑定,您几乎可以创建任何您喜欢的东西。但是应该注意的是,只要有可能,您应该使用表达式来代替,因为它们更容易移植,这对于很多表达式来说都是开箱即用的。
$Query = $Table
->find()
->where([
'start_date BETWEEN :start AND :end'
])
->bind(':start', '2014-01-01', 'date')
->bind(':end', '2014-12-31', 'date');
这样第二种情况也可以很容易地解决,例如:
$Query = $Table
->find()
->where([
':date BETWEEN start_date AND end_date'
])
->bind(':date', '2014-03-31', 'date');
也可以将两者混合使用,即使用使用自定义绑定的表达式,类似于以下内容:
use Cake\Database\Expression\IdentifierExpression;
use Cake\Database\Expression\QueryExpression;
use Cake\ORM\Query;
// ...
$Query = $Table
->find()
->where(function(QueryExpression $exp, Query $query) {
return $exp->between(
$query->newExpr(':date'),
new IdentifierExpression('start_date'),
new IdentifierExpression('end_date')
);
})
->bind(':date', '2014-03-31', 'date');
这样,您可以使用可能的可移植表达式来处理第二种情况,而不必担心手动引用/转义输入数据和标识符。
话虽如此,最终BETWEEN
与使用两个单独的简单条件相同:
$Query = $Table
->find()
->where([
'start_date >=' => '2014-01-01',
'start_date <=' => '2014-12-32',
]);
$Query = $Table
->find()
->where([
'start_date >=' => '2014-03-31',
'end_date <=' => '2014-03-31',
]);
但是不要生气,如果您一直阅读到这里,至少您了解了查询构建器的来龙去脉。
目前似乎只有两种选择。核心现在支持开箱即用,以下仅供参考。
Cake\ORM\Query
目前,ORM 查询构建器find()
(
https://github.com/cakephp/cakephp/issues/4926
因此,为了能够使用绑定,您必须使用底层数据库查询构建器 ( Cake\Database\Query
),例如可以通过Connection::newQuery()
.
这是一个例子:
$conn = ConnectionManager::get('default');
$Query = $conn->newQuery();
$Query
->select('*')
->from('table_name')
->where([
'start_date BETWEEN :start AND :end'
])
->bind(':start', new \DateTime('2014-01-01'), 'date')
->bind(':end', new \DateTime('2014-12-31'), 'date');
debug($Query->execute()->fetchAll());
这将导致类似于此的查询
SELECT
*
FROM
table_name
WHERE
start_date BETWEEN '2014-01-01' AND '2014-12-31'
另一种选择是生成适当的 SQL 片段的自定义表达式类。这是一个例子。
列名应该被包装到标识符表达式对象中,以便它们被自动引用(如果启用自动引用),键 > 值数组语法用于绑定值,其中数组键是实际值,数组值是数据类型。
请注意,直接传递用户输入的列名是不安全的,因为它们没有被转义!使用白名单或类似名称以确保列名可以安全使用!
use App\Database\Expression\BetweenComparison;
use Cake\Database\Expression\IdentifierExpression;
// ...
$between = new BetweenComparison(
new IdentifierExpression('created'),
['2014-01-01' => 'date'],
['2014-12-31' => 'date']
);
$TableName = TableRegistry::get('TableName');
$Query = $TableName
->find()
->where($between);
debug($Query->execute()->fetchAll());
这将生成与上述类似的查询。
use App\Database\Expression\BetweenComparison;
use Cake\Database\Expression\IdentifierExpression;
// ...
$between = new BetweenComparison(
['2014-03-31' => 'date'],
new IdentifierExpression('start_date'),
new IdentifierExpression('end_date')
);
$TableName = TableRegistry::get('TableName');
$Query = $TableName
->find()
->where($between);
debug($Query->execute()->fetchAll());
另一方面,这将导致类似于此的查询
SELECT
*
FROM
table_name
WHERE
'2014-03-31' BETWEEN start_date AND end_date
namespace App\Database\Expression;
use Cake\Database\ExpressionInterface;
use Cake\Database\ValueBinder;
class BetweenComparison implements ExpressionInterface {
protected $_field;
protected $_valueA;
protected $_valueB;
public function __construct($field, $valueA, $valueB) {
$this->_field = $field;
$this->_valueA = $valueA;
$this->_valueB = $valueB;
}
public function sql(ValueBinder $generator) {
$field = $this->_compilePart($this->_field, $generator);
$valueA = $this->_compilePart($this->_valueA, $generator);
$valueB = $this->_compilePart($this->_valueB, $generator);
return sprintf('%s BETWEEN %s AND %s', $field, $valueA, $valueB);
}
public function traverse(callable $callable) {
$this->_traversePart($this->_field, $callable);
$this->_traversePart($this->_valueA, $callable);
$this->_traversePart($this->_valueB, $callable);
}
protected function _bindValue($value, $generator, $type) {
$placeholder = $generator->placeholder('c');
$generator->bind($placeholder, $value, $type);
return $placeholder;
}
protected function _compilePart($value, $generator) {
if ($value instanceof ExpressionInterface) {
return $value->sql($generator);
} else if(is_array($value)) {
return $this->_bindValue(key($value), $generator, current($value));
}
return $value;
}
protected function _traversePart($value, callable $callable) {
if ($value instanceof ExpressionInterface) {
$callable($value);
$value->traverse($callable);
}
}
}
您可以使用以下两种方法之一。
方法一:
$start_date = '2014-01-01 00:00:00';
$end_date = '2014-12-31 23:59:59';
$query = $this->Table->find('all')
->where(function ($exp, $q) use($start_date,$end_date) {
return $exp->between('start_date', $start_date, $end_date);
});
$result = $query->toArray();
方法二:
$start_date = '2014-01-01 00:00:00';
$end_date = '2014-12-31 23:59:59';
$query = $this->Table->find('all')
->where([
'start_date BETWEEN :start AND :end'
])
->bind(':start', new \DateTime($start_date), 'datetime')
->bind(':end', new \DateTime($end_date), 'datetime');
$result = $query->toArray();
我正在这样使用它
$this->Table->find()->where(['data_inicio BETWEEN '.'\''.$data_inicio.'\''.' AND .'\''.$data_final.'\''.' ']);
大家好,请使用此查询根据值范围获取数据
$query = $this->Leads->find('all',
array('conditions'=>array('postcode BETWEEN '.$postcodeFrom.' and'.$postcodeTo.''), 'recursive'=>-1));
debug($query);
print_r($query->toArray());