【问题标题】:How to ignore question mark as placeholder when using PDO with PostgreSQL将 PDO 与 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

【问题讨论】:

  • 已经被问过几次了,例如stackoverflow.com/questions/16311939/… 没有好的答案。
  • @AlexBlex,是的,不是的。我读了那个问题(和其他几个),但它不一样。检查我的解决方法。我会在 PHP PDO 开一张票来解决这个问题
  • 实际上,问题和答案在我看来都是重复的——mikl 使用了 ? 运算符(在这种情况下,在 hstore 上而不是 json 上)并且 Craig Ringer 建议使用函数作为解决方法(看起来实现操作符的内置函数,而不是创建一个新函数)。
  • BTW 不确定 PHP/PDO 但尝试删除列名和运算符之间的空格:WHERE locations? :location;
  • @Abelisto 不幸的是,根据我的测试,PDO 的解析器太聪明了,仍然可以发现 ?

标签: php postgresql 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');
        

        【讨论】:

          猜你喜欢
          • 2013-04-25
          • 2011-11-01
          • 2018-05-16
          • 1970-01-01
          • 2016-06-23
          • 2021-06-17
          • 2011-07-09
          相关资源
          最近更新 更多