我正在尝试根据提交的会话开始时间过滤半径计费数据库。在MySQL数据库中,字段“ acctstartime”定义为DATETIME。
这是我要构建的有效SQL查询:
SELECT * FROM radacct WHERE DATE_FORMAT(acctstarttime, '%Y-%m-%d') = DATE_FORMAT('2019-08-10' , '%Y-%m-%d') ORDER BY "radacctid" DESC LIMIT 100
在我的ZF3-Controller中,我正在使用Zend \ Db抽象层基于提交的参数来构建SQL查询。但不幸的是,Db层转义了%-Signs并生成了一个不起作用的SQL字符串:
SELECT * FROM radacct WHERE DATE_FORMAT(acctstarttime, '%%Y-%%m-%%d') = DATE_FORMAT('2019-01-01' , '%%Y-%%m-%%d') AND "acctstarttime" = '2019-01-01' ORDER BY "radacctid" DESC LIMIT 100
在第136行的文件zend-db/src/Sql/Expression.php
中:
$expression = str_replace('%', '%%', $this->expression);
有人知道如何生成上面的查询吗?或者也许是做同样事情的另一种方法?我没有找到使用DATE_TIME的此类表达式的任何解决方法。
控制器:
class AccountingController extends AbstractRestfulJsonController {
protected $service;
public function __construct(RadiusService $service) {
$this->service = $service;
}
public function get($id) {
return $this->getList();
}
public function getList() {
$viewModel = new JsonModel();
try {
$filter = [];
$paramsRoute = $this->params()->fromRoute();
$paramsQuery = $this->params()->fromQuery();
$params = (OBJECT) array_merge($paramsRoute, $paramsQuery);
if(isset($params->id)) {
$filter['radacctid'] = (int) $params->id;
}
// ...
if(isset($params->sessionStartTime) && strlen($params->sessionStartTime) > 0) {
$filter[] = new Expression("DATE_FORMAT(acctstarttime, '%Y-%m-%d') = DATE_FORMAT('" . $params->sessionStartTime . "' , '%Y-%m-%d')");
}
// ...
$data = $this->service->getAccounting($filter);
$viewModel->setVariable('state', 'ok');
$viewModel->setVariable('count', $data['totalItems']);
$viewModel->setVariable('data', $data['items']);
} catch (\Exception $e) {
$viewModel->setVariable('state', 'nok');
$viewModel->setVariable('message', $e->getMessage());
}
return $viewModel;
}
}
所以“ SUBSTRING(acctstarttime,1,10)='”。 substr($ params-> sessionStartTime,0,10)。 “'”?
[另一种方法,也许是“更清洁”的方法,是编写自己的类并重写getExpressionData
方法以不转义值。例如:
use Zend\Db\Sql\Predicate\Expression;
public class NonEscapedExpression
{
/**
* @return array
* @throws Exception\RuntimeException
*/
public function getExpressionData()
{
$parameters = (is_scalar($this->parameters)) ? [$this->parameters] : $this->parameters;
$parametersCount = count($parameters);
if ($parametersCount == 0) {
return [
str_ireplace(self::PLACEHOLDER, '', $expression)
];
}
// assign locally, escaping % signs
$expression = str_replace(self::PLACEHOLDER, '%s', $expression, $count);
// test number of replacements without considering same variable begin used many times first, which is
// faster, if the test fails then resort to regex which are slow and used rarely
if ($count !== $parametersCount && $parametersCount === preg_match_all('/\:[a-zA-Z0-9_]*/', $expression)) {
throw new Exception\RuntimeException(
'The number of replacements in the expression does not match the number of parameters'
);
}
foreach ($parameters as $parameter) {
list($values[], $types[]) = $this->normalizeArgument($parameter, self::TYPE_VALUE);
}
return [[
$expression,
$values,
$types
]];
}
}
但是您应该小心使用它。