将 PDO 与 PostgreSQL 一起使用时如何忽略问号作为占位符
Posted
技术标签:
【中文标题】将 PDO 与 PostgreSQL 一起使用时如何忽略问号作为占位符【英文标题】:How to ignore question mark as placeholder when using PDO with PostgreSQL 【发布时间】:2016-07-10 11:09:12 【问题描述】:注意:
这个问题可以被认为是这个Question的重复。 它确实指出了 PDO 的相同问题。但由于目标不同,它的变通解决方案略有不同。我将在那里发布 JSONB 的解决方法和 php 票证的链接。
当我准备以下查询时:
SELECT * FROM post WHERE locations ? :location;
出现以下警告:
警告:PDO::prepare(): SQLSTATE[HY093]: 无效参数号:/path/file.php 第 xx 行中的混合命名参数和位置参数
问号是有效的PostgreSQL operator,但 PDO 将其视为占位符。
是否有适当的方法来配置 PDO 以忽略作为占位符的问号?
我将在下面发布一个解决方法。希望有更好的方法
编辑 我在 PHP 错误跟踪系统中添加了 ticket
【问题讨论】:
已经被问过几次了,例如***.com/questions/16311939/… 没有好的答案。 @AlexBlex,是的,不是的。我读了那个问题(和其他几个),但它不一样。检查我的解决方法。我会在 PHP PDO 开一张票来解决这个问题 实际上,问题和答案在我看来都是重复的——mikl 使用了?
运算符(在这种情况下,在 hstore 上而不是 json 上)并且 Craig Ringer 建议使用函数作为解决方法(看起来实现操作符的内置函数,而不是创建一个新函数)。
BTW 不确定 PHP/PDO 但尝试删除列名和运算符之间的空格:WHERE locations? :location;
@Abelisto 不幸的是,根据我的测试,PDO 的解析器太聪明了,仍然可以发现 ?
。
【参考方案1】:
这是我的问题的解决方法。它通过使用PostgreSQL函数替换?
运算符解决了这个问题。
我不太喜欢它,因为它不会使 PDO 更符合 PostgreSQL。但我没有找到真正的解决方案。
CREATE FUNCTION json_key_exists(JSONB,TEXT) RETURNS BOOLEAN LANGUAGE SQL STABLE AS $f$
SELECT $1 ? $2
$f$;
现在我可以使用查询了:
SELECT * FROM post WHERE json_key_exists(locations, :location);
解决方法是由来自 freenode #postgresql 的神话般的 RhodiumToad 提出的
编辑
正如@Abelisto 建议的那样,不需要创建上面的函数,因为jsonb_exists(jsonb, text)
是avialabe
【讨论】:
您可以探索?
运算符定义(psql中的\do+ "?"
),发现它使用函数jsonb_exists(jsonb, text)
作为其背景。所以你不需要定义你的函数,而是重用已经存在的函数。
我想建议使用自定义不可变函数,其中包含?
,因为 jsonb_exists() 不可索引,而 ?
是。见dba.stackexchange.com/questions/90002/…
@НЛО 顺便说一句,你错了。 create index i on t(jsonb_exists(x,'a'::text));
和索引也使用得很好。【参考方案2】:
自 PHP 7.4 起,supports for escaping question mark have landed.
(...) 问号可以通过加倍 (...) 来转义。这意味着“??”字符串将被翻译为“?”将查询发送到数据库时,而“?”仍将被解释为位置参数占位符。
在您的示例中,您可以使用:
$sql = "SELECT * FROM post WHERE locations ?? :location;";
【讨论】:
【参考方案3】:好的,最简单的方法是create the new operator 使用相同的选项,例如:
-- Operator: ~!@#%^&(jsonb, text)
-- DROP OPERATOR ~!@#%^&(jsonb, text);
CREATE OPERATOR
~!@#%^& -- Change it to any other non-conflicted symbols combination
(
PROCEDURE = jsonb_exists,
LEFTARG = jsonb,
RIGHTARG = text,
RESTRICT = contsel,
JOIN = contjoinsel);
COMMENT ON OPERATOR ~!@#%^&(jsonb, text) IS 'key exists';
(原始脚本由pgAdmin生成)
并以通常的方式使用它
SELECT * FROM post WHERE locations ~!@#%^& :location;
【讨论】:
很好的解决方法。我想使用哪一个的决定将与查询的类型和数量有关。【参考方案4】:你可以使用
jsonb_exists
而不是 ?
jsonb_exists_any
而不是 ?|
jsonb_exists_all
而不是 ?&
但是postgresql site上没有文档。
【讨论】:
未定义函数:7 错误:函数 jsonb_exists_any(json, text[]) 不存在,postgres 10【参考方案5】:对于搜索键并根据 Yoann 的回答,我已经测试过表达式 ( jsonbData ? 'keySearched' ) 等效于 jsonb_exists(jsonbData , 'keySearched')
【讨论】:
【参考方案6】:使用CREATE OPERATOR ~@& (LEFTARG = jsonb, RIGHTARG = text[], PROCEDURE = jsonb_exists_any)
并使用~@& 代替?|一切都会好起来的
【讨论】:
【参考方案7】:这对我有用:
jsonb_exists(some_jsonb_array,'search_value');
【讨论】:
以上是关于将 PDO 与 PostgreSQL 一起使用时如何忽略问号作为占位符的主要内容,如果未能解决你的问题,请参考以下文章
是否可以将 Doctrine 与持久 PDO 连接一起使用?