在PHP的PDO中,如何获取PostgreSQL upsert查询的“RETURNING”子句的值

3

我有一个在postgreSQL中编写的upsert查询

$statement = 'INSERT INTO "CharactersUnlockToBuyLevels"
                ("CharacterId", "LevelId", "AmountToBuy", "EagleStatueId", "Location", 
                 "MapCoordinateTop", "MapCoordinateLeft")
              VALUES 
                (:CharacterId, :LevelId, :AmountToBuy, :EagleStatueId, :Location, 
                 :MapCoordinateTop, :MapCoordinateLeft)
              ON CONFLICT
                ("CharacterId")
              DO UPDATE 
                SET 
                  "LevelId" = EXCLUDED."LevelId",
                  "AmountToBuy" = EXCLUDED."AmountToBuy",
                  "EagleStatueId" = EXCLUDED."EagleStatueId",
                  "Location" = EXCLUDED."Location",
                  "MapCoordinateTop" = EXCLUDED."MapCoordinateTop",
                  "MapCoordinateLeft" = EXCLUDED."MapCoordinateLeft"                            
              RETURNING "CharacterUnlockToBuyLevelId"
             ';

这个查询正常工作,如果我在PgAdmin中运行它,我会得到期望的“CharacterUnlockToBuyLevelId”返回值。然而,如果我使用PHP的PDO准备并执行它,我似乎无法获得RETURNING的值。

$stmt = $this->db->prepare($statement);
$returnedId = $stmt->execute(array(
     'CharacterId' => $characterId,
     'LevelId' => $unlockMethod['LevelId'],
     'AmountToBuy' => $unlockMethod['AmountToBuy'],
     'EagleStatueId' => $unlockMethod['EagleStatueId'],
     'Location' => $unlockMethod['Location'],
     'MapCoordinateTop' => $unlockMethod['MapCoordinateTop'],
     'MapCoordinateLeft' => $unlockMethod['MapCoordinateLeft'],
));

这只是返回了true,所以$returnedId实际上不会保存id的值,而只是true。我该如何使用PDO的预处理语句从upsert查询中获取RETURNING值?


你尝试过使用 with i as (. . . ) select i.* from i 吗? - Gordon Linoff
可以这样做,但我想尽可能保持我的查询干净,不要构建额外的内容来获取已经返回的值,并且正在寻找PHP PDO的解决方案。 - Pascale
我注意到查询返回了一列,但你似乎在读取多列。 - Gordon Linoff
我不明白你上一条评论的意思,它可能是更新现有记录或插入新记录。我只需要知道更新/插入记录的主键“CharacterUnlockToBuyLevelId”,所以这就是我返回的内容。 - Pascale
仅在RETURNING子句中的列将在结果集中返回。 - Gordon Linoff
我知道,但是执行语句不会返回那些值,它在成功时返回“true”,在失败时返回“false”。那么,我如何使用PDO来使用预处理语句,同时仍然从RETURNING子句中获取我的值呢? 我想我们彼此之间存在误解 :p - Pascale
2个回答

2

来自http://php.net/manual/en/pdostatement.execute.php:

public bool PDOStatement::execute ([ array $input_parameters ] )

要获取返回值,请尝试使用fetchAll

$stmt = $this->db->prepare($statement);
$returnedId = $stmt->execute(array(
     'CharacterId' => $characterId,
     'LevelId' => $unlockMethod['LevelId'],
     'AmountToBuy' => $unlockMethod['AmountToBuy'],
     'EagleStatueId' => $unlockMethod['EagleStatueId'],
     'Location' => $unlockMethod['Location'],
     'MapCoordinateTop' => $unlockMethod['MapCoordinateTop'],
     'MapCoordinateLeft' => $unlockMethod['MapCoordinateLeft'],
));
$yourVal=$stmt->fetchAll();

谢谢Vao,我希望能够在一次数据库调用中获取它,而不是之后再去获取,但我想那是不可能的。 既然我知道只返回一行数据且只有一个值,我使用了fetchColumn()。这样可以直接给我id号码,避免了我从fetchAll()或fetch()返回的数组中获取它。 - Pascale

0

如果你准备扩展PDOStatement类,可以稍微简化这个过程。诀窍是在你扩展的 execute 方法中包装 fetchAll

因为PDOStatement是间接生成的,所以你首先需要告诉PDO使用你的扩展版本,而不是标准版本:

$pdo=new PDO($dsn,$user,$password) or die('oops');
$pdo->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('DBStatement',array($pdo)));

... 其中 DBStatement 将是您扩展的 PDOStatement

然后,您可以按照以下方式扩展该类:

class DBStatement extends PDOStatement {
    public $pdo;
    protected function __construct($pdo) {
        $this->pdo = $pdo;
    }
    function executeReturning($data=null) {
        parent::execute($data);
        return $this->fetchAll();
    }
}

第一部分需要让你的新类与原始类相同。第二部分执行语句,然后返回结果。

然后你可以按照以下方式调用它:

$sql='INSERT INTO testing(data) VALUES(?) RETURNING id,data';
$pds=$pdo->prepare($sql);
print_r($pds->executeReturning(['this space for rent']));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接