我使用一些自定义DQL函数来过滤PostgreSQL中的一些JSONB字段的行。这是我的查询功能:
private function findTopLevelResources(): array {
return $this->createQueryBuilder('r')
->where("JSON_EXISTS(r.contents, '-1') = FALSE")
->getQuery()
->getResult();
}
运行此代码会产生DriverException
的{{1}}:
AbstractPostgreSQLDriver
我尝试从PHPStorm手动执行原始SQL查询,但它没有错误。
如何在Doctrine中使用它?
为什么这个查询不能与Doctrine一起使用,但是当我手动测试时呢?
此处An exception occurred while executing 'SELECT r0_.id AS id_0, r0_.marking AS marking_1, r0_.contents AS contents_2, r0_.kind_id AS kind_id_3 FROM resource r0_ WHERE r0_.contents?'-1' = false':
SQLSTATE[3F000]: Invalid schema name: 7 ERROR: schema "r0_" does not exist
LINE 1: ... r0_.kind_id AS kind_id_3 FROM resource r0_ WHERE r0_.conten...
^
:(基于syslogic/doctrine-json-functions)
JSON_EXISTS
通过Symfony的YAML配置注册如下:
class JsonExists extends FunctionNode
{
const FUNCTION_NAME = 'JSON_EXISTS';
const OPERATOR = '?';
public $jsonData;
public $jsonPath;
public function getSql(SqlWalker $sqlWalker)
{
$jsonData = $sqlWalker->walkStringPrimary($this->jsonData);
$jsonPath = $this->jsonPath->value;
return $jsonData . self::OPERATOR . "'$jsonPath'";
}
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->jsonData = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$this->jsonPath = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}
东西的版本:
答案 0 :(得分:1)
错误消息是错误的线索。
实际问题是由PDO引起的(这就是为什么它可以从PHPStorm运行)。当它看到这样的查询时:
SELECT * FROM foo WHERE contents?'bar'
它将其视为参数化查询,并将问号?
视为参数。由于某种原因,它有时会导致无意义的错误消息。这个特定情况可以通过在问号后面添加一个空格来解决,但对于中间没有空格的运算符?|
和?&
不起作用。
解决方案是使用与运算符(this question saved the day)对应的函数。人们可以通过这样的查询找出它们的调用方式:
SELECT oprname, oprcode FROM pg_operator WHERE oprname IN ('?', '?|', '?&')
以下是与JSON相关的结果部分:
?
→jsonb_exists
?|
→jsonb_exists_any
?&
→jsonb_exists_all
因此,不是通过PDO导致问题的先前查询,而是可以使用这个等效的:
SELECT * FROM foo WHERE jsonb_exists(contents, 'bar')