在使用PHP操作Oracle数据库时如何获取最后插入的ID?

3

我有两张用以下代码创建的表:

CREATE TABLE t1 (id NUMBER GENERATED AS IDENTITY);
CREATE TABLE t2 (id NUMBER GENERATED AS IDENTITY);

我往t1表中插入一些数据,然后需要将生成的ID插入到t2表中。
例如:
"insert into t1 (name, description) values ('asd','dsa')"
**getting that autogenerated ID
"insert into t2 (idFromt1,name) values (idFromt1,'sarasa')"

我看到很多例子都这样做:

"insert into t1 (name, description) values ('asd','dsa') returning ID into inserted_id";

但是我不会/不知道如何从php中检索“inserted_id”变量以进行第二次插入。


可能是检索Oracle最后插入的IDENTITY的重复问题。 - Code Spirit
哦,我不知道。 - Emepese
@CodeSpirit 我看不出这个问题和那个问题有什么重复之处。这个问题是关于 PHP 的,而另一个问题则不是。 - Manngo
7个回答

3

我正在搜索PDO相关的内容,然后看到了这个:

$qry="INSERT INTO t1 (NOMBRE) VALUES ('sarasa') returning ID into :inserted_id";

$parsed = oci_parse($this->conn, $qry);

oci_bind_by_name($parsed, ":inserted_id", $idNumber,32);
oci_execute($parsed);
echo $idNumber;

我以为oci_bind_by_name只能单向传递,但事实并非如此。 这将生成的id保存到变量$idNumber中,正是我所需要的。感谢大家的回答。


2
你可以使用(应该使用?)返回值。
例如,使用PDO:
``` $stmt = $pdo->prepare($sql); $stmt->execute($params); $result = $stmt->fetch(); return $result; ```
"Original Answer"翻译成"最初的回答"。
$query = "insert into t1 (name, description) values ('asd','dsa') returning ID";

$stmt = $pdo->query($query);

$id = $stmt->fetchColumn();

1

对我来说,这些答案都不太适用——我一直得到NULL作为我的最后插入的标识符。碰巧(真的尝试了所有方法),我发现在执行以下操作之前:

$stmt->bindParam('idfoo', $idfoo, PDO::PARAM_INT, 8);

您需要将 $idfoo 设置为整数类型。我不知道原因。像这样:
$idfoo = (int)null;

这个整数可以是任何值,但是对我来说更清晰的做法是将其初始化为空值,以确保其类型正确。

完整示例:

$query = "insert into t2 (name, description) values (:name, :description) returning ID into :idfoo";
$stmt = $connection->prepare($query);  

$name = 'adsjim';
$description = 'lead dev';

$params = array('name'=>$name, 'description'=>$description);
foreach ($params as $key=>$value){
      $stmt->bindValue($key,$value);
}
$idfoo = (int)null;
$stmt->bindParam('idfoo', $idfoo, PDO::PARAM_INT, 8);

$stmt->execute();
// insert id is now in the $idfoo variable
var_dump($idfoo);

在数据库中,身份列字面上被称为ID - 将其替换为您的列名。

这实际上是因为PHP 8开始重视数据类型。在许多情况下,您可能需要定义(int)或(array)。请参阅PHP 8迁移文档,以更好地了解PHP 7.4和8.0之间的差异 https://www.php.net/manual/en/migration80.php - Syed M. Sannan

1
使用 PDO::lastInsertID
示例:
$stmt = $db->prepare("...");
$stmt->execute();
$id = $db->lastInsertId();

Don't use

SELECT MAX(id) FROM table;

因为如果在选择操作之前执行其他的插入查询,那么在事务中它可能会导致不安全,而且对你来说也无法正常工作。


Oracle驱动程序不支持lastInsertId()。 - Sergio A. Kessler

0

这个问题涉及到使用PDO和Oracle的PHP。但是,这些解决方案都不适用于我。Emepese的答案使用了本地OCI驱动程序而不是PDO,并且PDO::lastInsertId在Oracle中不起作用。

Cid的答案让我接近成功,还有一个来自如何在php中获取最后插入记录的序列ID?的答案。

但我的情况更加复杂。我已经有了一个带有$stmt->prepare($query)$stmt->execute(array('name'=>$name, 'desc'=>$desc));的查询语句。为了使它工作,我写了这个:

$query = "insert into t1 (name, desc) values (:name, :desc) returning ID into :PK_ID";
// move params to an array:
$params = array('name'=>$name, 'desc'=>$desc);
foreach ($params as $key=>$value){
      $stmt->bindValue($key,$value);
}
$stmt->bindParam('PK_ID',$id,PDO::PARAM_INT|PDO::PARAM_INPUT_OUTPUT,32);
// Important! Remove all parameters from the execute command:
$stmt->execute();
// insert id is now in the $id variable - do something with it
echo "I inserted $id!";

我希望这能帮助其他人节省时间,尝试使用自增列、Oracle序列和绑定参数。


0

@Volod的回答是正确的,但这里有一个更详细的例子,展示如何使用PDO来完成它。

$db = new PDO(…);                                               //  1
$prepared = 'insert into t1 (name, description) values (?,?)';  //  2
$prepared -> execute(['asd','dsa']);                            //  3
$id = $db -> lastInsertId();                                    //  4
//  etc

这个例子使用了预处理语句来保证安全性。

  1. 创建一个新的PDO对象连接到数据库。
  2. 创建一个包含预处理语句的新的PDOStatement对象。预处理语句是没有实际数据的,问号(?)是数据的占位符。即使它们代表字符串,也包括引号。
  3. 用要插入的值的数组运行预处理语句。
  4. 无论实际的DBMS如何,PDO都将使用lastInsertId()方法获取最新的自动生成的id

PDO的一个优点是通过使用自己的方法来处理DBMS之间的差异。在这种情况下,我们不关心Oracle如何获取id,而是依赖于PDO来解决问题。

如果您正在使用来自不受信任来源(例如用户)的数据或者需要多次运行语句,则使用预处理语句非常重要。如果您只是使用可信数据运行一次,则可以更简单地完成:

$db = new PDO(…);
$db -> exec ("insert into t1 (name, description) values ('asd','dsa')';
$id = $db -> lastInsertId();
//  etc

-2

可以使用{{link1:PDO::lastInsertId}} 或者

SELECT MAX(id) FROM table;

2
MAX(id)是一个糟糕的想法。它取决于竞争状态。 - Cid

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