好的,我已经确认这可以在PHP上正常使用。

$ php --version
PHP 5.6.16 (cli) (built: Dec 30 2015 15:09:50) (DEBUG)

<pdo version>
pdo_pgsql
PDO Driver for PostgreSQL   enabled
PostgreSQL(libpq) Version   9.4.0
Module version  1.0.2
Revision    $Id: fe003f8ab9041c47e97784d215c2488c4bda724d $

我想使用PDO在PHP中重新创建以下SQL:
UPDATE relationships SET status = 4 WHERE created > NOW() - interval '2 seconds';

该脚本正在工作:
<?php

$db = new PDO('pgsql:dbname=db;host=localhost;user=stevetauber');
$stmt = $db->prepare("UPDATE relationships SET status = 4 WHERE created > NOW() - interval '?'");
$stmt->execute(array("2 seconds"));

这是带有命名占位符的地方:
<?php

$db = new PDO('pgsql:dbname=db;host=localhost;user=stevetauber');
$stmt = $db->prepare("UPDATE relationships SET status = 4 WHERE created > NOW() - interval ':blah'");
$stmt->execute(array(":blah" => "2 seconds"));

这给出了这个错误:
Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: :blah in ... line 5

现在根据PHP documentation


 <?php
 $stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE '%?%'");
 $stmt->execute(array($_GET['name']));

 // placeholder must be used in the place of the whole value
 $stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE ?");
 $stmt->execute(array("%$_GET[name]%"));
 ?>

这是更新的代码:
<?php

$db = new PDO('pgsql:dbname=db;host=localhost;user=stevetauber');
$stmt = $db->prepare("UPDATE relationships SET status = 4 WHERE created > NOW() - :blah");
$stmt->execute(array(":blah" => "interval '2 seconds'"));

产生以下数据库错误(无脚本错误):
ERROR:  operator does not exist: timestamp with time zone > interval at character 51
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.
STATEMENT:  UPDATE relationships SET status = 4 WHERE created > NOW() - $1

PDO在这里做一些奇怪的事情,因为:
# select NOW() - interval '2 seconds' as a , pg_typeof(NOW() - interval '2 seconds') as b;
               a               |            b
-------------------------------+--------------------------
 2015-12-30 18:02:20.956453+00 | timestamp with time zone
(1 row)

那么如何在PostgreSQL和interval中使用命名占位符?

最佳答案

占位符用于纯值,不适用于用单位(或其他任何内容)修饰的值。

要在占位符中表示interval '2 seconds',有两种选择:

在查询中输入

  • ,输入:secs * interval '1 second'并将:secs绑定(bind)到php
  • 中的一个数字
  • 或写:cast(:mystring as interval),然后将:mystring绑定(bind)到字符串'2 seconds'。将通过显式强制转换对其进行动态解释。


  • 当尝试使用psql命令行客户端与PDO驱动程序进行比较时,请使用带有postgres native PREPARE占位符的EXECUTE$N SQL语句,而不是将参数值直接写在查询中。当PDO::ATTR_EMULATE_PREPARES设置为false时,这将与PHP驱动程序本质上的功能匹配。

    在问题的最后一部分,当在psql中尝试此操作时(您的查询只是简化为不需要表):
    select now() > now() - interval '2 seconds';
    

    它确实起作用并返回't'(true)。

    但是,如果您尝试这样做:
    prepare p as select now() > now() - $1;
    

    如果失败



    这与PDO的准备/执行错误相同。

    另一方面,这确实有效:
    => prepare p as select now() > now() - interval '1 second'*$1;
    PREPARE
    
    => execute p(2);
    ?column?
    ----------
    t
    

    关于postgresql - 在PHP和PostgreSQL中使用带间隔的命名占位符失败,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34528986/

    10-11 03:31
    查看更多