在 mysqli 中输出 Inserted.row

OUTPUT Inserted.row in mysqli

我有以下 sql table:

id|email|fbid

当我执行查询时

 INSERT INTO users(email,fbid) VALUES('randomvalue','otherrandomvalue')

我想获取插入行的id。为此,我尝试像这样编辑查询:

 INSERT INTO users(email,fbid) VALUES('randomvalue','otherrandomvalue') OUTPUT Inserted.id

但我得到:

1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'OUTPUT Inserted.id' at line 1

可能是什么问题?

不幸的是(据我所知) does not support output as 确实如此。

您确实可以选择要在单行插入中完成的操作(假设 auto_increment 主键):

SELECT LAST_INSERT_ID();

不幸的是,不会在批量插入的情况下工作——尽管在你的情况下你不是(至少不是在你的例子),所以这应该没问题。

如果您正在使用 php 那么最好使用以下代码:

 if ($conn->query($sql) === TRUE) {
  $last_id = $conn->insert_id;
    echo "New record created successfully. Last inserted ID is: " . $last_id;
 } else {
   echo "Error: " . $sql . "<br>" . $conn->error;
  }

其中 $conn 是连接变量。

我将使用我在下面描述的过程来处理我为个人使用而编写的私人家庭(非企业)应用程序的相同情况。我知道这个问题现在已经有一年了,但似乎没有适合批处理的答案。我找不到合适的答案。 MySQL 似乎没有内置的设施来处理这类事情。

我担心这个解决方案的可靠性,当它被投入生产环境时,多个不同的 users/jobs 可以同时访问同一个过程来进行插入。我相信我已经通过将连接 ID 添加到 @by 变量赋值来解决这些问题。这样做使得 by 具有 a:会话的连接 ID 和 b:执行插入的 program/job/procedure 的名称。结合插入的日期和时间,我相信这三个值提供了一个非常安全的密钥来检索正确的插入行集。如果对此需要绝对确定性,您可以添加 GUID 类型(或 varchar)的第三列生成一个 GUID 变量以插入其中,然后使用 GUID 变量以及 @by 和 @now 作为您的键。我觉得这对我的目的来说是不必要的,因为我将在其中使用它的过程是一个在服务器上而不是在 PHP 中运行的事件(作业)脚本。因此,除非有人要求,否则我不会举例说明。

警告

如果您在 PHP 中执行此操作,请考虑在您的进程中使用 GUID 列而不是 CreatedBy。在 PHP 中执行此操作很重要,因为在插入记录和尝试检索 IDS 之间您的连接可能会丢失,并且带有连接 ID 的 CreatedBy 将变得无用。但是,如果您有在 PHP 中创建的 GUID,则可以循环直到连接成功或使用保存在文件中某处的 GUID 进行恢复。出于我的目的,不需要此级别的连接安全性,因此我不会这样做。

此解决方案的关键是 CreatedBy 是连接 ID 与执行插入的作业或过程的名称相结合,而 CreatedDate 是一个 CURRENT_TIMESTAMP 保存在一个变量中,该变量通过下面的代码。假设您有一个名为 "TestTable" 的 table。它具有以下结构:

测试"Insert Into"table

CREATE TABLE TestTable (
      TestTableID INT NOT NULL AUTO_INCREMENT
    , Name VARCHAR(100) NOT NULL
    , CreatedBy VARCHAR(50) NOT NULL
    , CreatedDate DATETIME NOT NULL
    , PRIMARY KEY (TestTableID)
);

Temp table 用于存储插入的 ID

这个临时 table 将保存插入到 TestTable 中的行的主键 ID。它有一个简单的结构,只有一个字段,既是 temp table 的主键,也是 inserted table (TestTable)

的主键
DROP TEMPORARY TABLE IF EXISTS tTestTablesInserted;
CREATE TEMPORARY TABLE tTestTablesInserted(
      TestTableID INT NOT NULL
    , PRIMARY KEY (TestTableID)
);

变量

这很重要。您需要将 CreatedBy 和 CreatedDate 存储在变量中。 CreatedBy 存储用于 consistency/coding 实践,CreatedDate 非常重要,因为您将使用它作为检索插入行的键。

@by 的示例:CONID(576) BuildTestTableData

请注意,将连接 ID 封装为表明它是什么的东西很重要,因为它被用作 "composite" 和一个字段中的其他信息

@now 的示例:'2016-03-11 09:51:10'

请注意,使用 LEFT(50) 封装 @by 很重要,以避免在插入到 CreatedBy VARCHAR(50) 列时触发截断错误。我知道这发生在 sql 服务器中,但不太确定 mysql。如果 mysql 在截断数据时没有抛出异常,则在您将截断值插入字段然后匹配检索失败的地方可能会出现静默错误,因为您正在尝试匹配的非截断版本字符串到字符串的截断版本。如果 mysql 在插入时不截断(即它不强制类型值限制)那么这不是一个真正的问题。我根据我的 sql 服务器经验按照标准做法进行操作。

SET @by = LEFT(CONCAT('CONID(', CONNECTION_ID(), ') BuildTestTableData'), 50);
SET @now = CURRENT_TIMESTAMP;

插入测试表

插入测试 table,指定 @by 和 @now

的 CreatedBy 和 CreatedDate
INSERT INTO TestTable (
      Name
    , CreatedBy
    , CreatedDate
)
SELECT Name
     , @by
     , @now
FROM SomeDataSource
WHERE BusinessRulesMatch = 1
;

检索插入的 ID

现在,使用@by 和@now 检索测试中插入的行的 ID table

INSERT INTO tTestTablesInserted (TestTableID)
SELECT TestTableID
FROM TestTable
WHERE CreatedBy = @by
  AND CreatedDate = @now
;

对检索到的信息做任何事情

/*DO SOME STUFF HERE*/
SELECT * 
FROM tTestTablesInserted tti
JOIN TestTable tt
    ON tt.TestTableID = tti.TestTableID
;