PHP MySQL PDO:最后插入ROW而不是ID

时间:2015-03-12 09:00:51

标签: php mysql database pdo last-insert-id

我目前有一个脚本,可以在使用表单添加新元素时自动插入新数据。

我用

 public string PDO::lastInsertId ([ string $name = NULL ] )

逻辑当然。现在我只想知道如果表没有ID字段且没有自动增量字段,这是否会导致任何问题。

除此之外,如果这意味着使用了错误的数据库结构。 我想确保这个例程适用于任何情况。好的数据库或糟糕的数据库结构。没关系。

我的意思是我想用数据取回行,以便我可以搜索它。

E.G。

1

将新数据插入数据库

$query = $pdo->prepare("INSERT INTO `tablename` SET `data_name`='John', `data_familyname`='Doe', 'data_age`=45, `data_wife`='Sarah Doe'");
$query->execute();

2

完全获取最后插入的行

///$LastID = $pdo->lastInsertId(); 
$query = $pdo->prepare("SELECT `data_name`,`data_familyname`,`data_age`,`data_wife` FROM `tablename` WHERE LAST IDFIELD = ".$pdo->lastInsertId());
$query->execute();
$row = $query->fetch();

行包含

array(
        'data_name'         =>      'John',
        'data_familyname'   =>      'Doe',
        'data_age'          =>      '45',
        'data_wife'         =>      'Sarah Doe'
    );

3

然后使用与刚刚插入的数据完全相同的数据更新最后插入的行

$query = $pdo->prepare("UPDATE `tablename` SET `data_name`='Chris' WHERE `data_name`=? AND `data_familyname`=? AND 'data_age`=? AND `data_wife`=?");
$query->execute(array_values($row));

最后一个查询基本上是:

UPDATE `tablename` SET `data_name`='Chris' 
WHERE `data_name`='John' AND `data_familyname`='Doe' AND 'data_age`='45' AND `data_wife`='Sarah Doe'

当然存在重复数据的可能性。而且您只想修改最后一行。如果数据库具有任何良好的结构,那就是我的意思。

但是为了防止重复数据,可以添加:

行包含

array(
        'data_id'           =>      20,
        'data_name'         =>      'John',
        'data_familyname'   =>      'Doe',
        'data_age'          =>      '45',
        'data_wife'         =>      'Sarah Doe'
    );

重点是

第2步

不起作用,因为我只是花了几分钟的时间。但是,我想知道是否有任何类似的功能或例程与我刚才提到的相同。

希望我明白我想要的东西。

我的解决方案最终是:

$sth = $pdo_connection->prepare("INSERT INTO `pdo_test` SET 
                            `pdo_name`              =       'John Doe',
                            `pdo_description`       =       'John Doe who served in Vietnam and every other war game as a default name',
                            `pdo_text`              =       'Some text BLABLA'
                        ");
$sth ->execute();

$stmt               = $pdo_connection->query("SELECT LAST_INSERT_ID()");
$result             = $stmt->fetch(PDO::FETCH_ASSOC);
$lastID             = $result['LAST_INSERT_ID()'];


$stmt               = $pdo_connection->prepare("SHOW COLUMNS FROM `pdo_test` WHERE EXTRA LIKE '%AUTO_INCREMENT%'");
$stmt->execute();
$row                = $stmt->fetch(PDO::FETCH_ASSOC);
$AutoIncrementField = $row['Field'];


$stmt               = $pdo_connection->prepare('SELECT * FROM `pdo_test` WHERE `'.$AutoIncrementField.'` = ?');
$stmt->execute(array($lastID));
$result             = $stmt->fetch(PDO::FETCH_ASSOC);

echo print_r($result);

结果:

Array
(
    [pdo_id]            =>      64
    [pdo_name]          =>      John Doe
    [pdo_counter]       =>      0
    [pdo_description]   =>      John Doe who served in Vietnam and every other war game as a default name
    [pdo_text]          =>      Some text BLABLA
)

但AutoIncrement字段似乎是必不可少的。

第二个解决方案,但仍然使用AutoIncrement字段。

(由Edwin Lambregts提议)

请注意,此解决方案不是故障安全!因为查询选择最后插入的行...但是所有实例!因此,如果另一个用户刚刚插入了一个新行...您将看到他的输入而不是您的输入。如果更新发生在两者之间,则会发生这种情况。

$sth = $pdo_connection->prepare("INSERT INTO `pdo_test` SET 
                            `pdo_name`              =       'John Doe',
                            `pdo_description`       =       'John Doe who served in Vietnam and every other war game as a default name',
                            `pdo_text`              =       'Some text BLABLA'
                        ");
$sth ->execute();


$stmt               = $pdo_connection->prepare("SHOW COLUMNS FROM `pdo_test` WHERE EXTRA LIKE '%AUTO_INCREMENT%'");
$stmt->execute();
$row                = $stmt->fetch(PDO::FETCH_ASSOC);
$AutoIncrementField = $row['Field'];


$stmt               = $pdo_connection->prepare('SELECT * FROM `pdo_test` ORDER BY `'.$AutoIncrementField.'` DESC LIMIT 0,1');
$stmt->execute();
$result             = $stmt->fetch(PDO::FETCH_ASSOC);

结果是:

Array
(
    [pdo_id]            =>      67
    [pdo_name]          =>      John Doe
    [pdo_counter]       =>      0
    [pdo_description]   =>      John Doe who served in Vietnam and every other war game as a default name
    [pdo_text]          =>      Some text BLABLA
)

3 个答案:

答案 0 :(得分:1)

我不确定你的问题是什么,但为了不弄乱你桌子里的东西,你必须实现这些:

  1. 桌面上有PK(主键)。它为您提供了唯一标识每一行的方法。它应该是唯一标识每一行的字段或字段组合。理论上,他PK的最佳候选者是存储在表中的实体的内在属性,用于标识实体。例如,对于Country表,PK的合适候选者是完整的国家/地区名称。在现实世界中,AUTO_INCREMENT字段的发明是因为:

    • 某些表只是没有可用作PK的列或一组列;例如,用于存储程序生成的日志条目的表 - 即使其中一些条目相同,也必须存储所有条目;使用PK字段为他们创建了一个人工AUTO_INCREMENT;
    • PK的最佳候选列类型为string时(上例中的国家/地区名称)或PK的候选列是两列或更多列的集合时,将其用作PK会对表格产生负面影响;人工PK(创建为AUTO_INCREMENT整数字段)会生成较小的索引,从而提高使用它的查询的速度。
  2. INSERT上,您可以为PK生成一个值并将其放入查询中,或者依赖数据库为您生成一个值(如果PKAUTO_INCREMENT字段。

    • 如果为PK生成值,则需要确保表中尚不存在该值。您可以在INSERT之前检查它是否不存在,或者您可以尝试INSERT并检查它是否成功。即使您之前检查过,INSERT仍然可能会失败,因为该脚本的另一个实例可以同时运行,并为INSERT生成PK相同的值。在这种情况下,您需要生成另一个值并再次尝试INSERT,此工作流程将重复,直到成功为止。对我来说,这看起来不是一个好策略。
    • 您可以让数据库为PK生成一个唯一值(为NULL查询中PK提供INSERT或不提供MySQL所有)然后询问它产生的价值。 AUTO_INCREMENT为此目的提供LAST_INSERT_ID()功能。摘自文档:

        

      生成的ID在每个连接的服务器中维护。这意味着函数返回给定客户端的值是为该客户端影响AUTO_INCREMENT的最新语句生成的第一个AUTO_INCREMENT值。此值不受其他客户端的影响,即使它们生成自己的INSERT值。此行为可确保每个客户端都可以检索自己的ID,而无需关心其他客户端的活动,也无需锁定或事务。

      数据库处理所有事情:值是唯一的,它不会干扰尝试同时插入同一个表的脚本的其他实例(甚至其他代码); PK成功,AUTO_INCREMENT是唯一的,我会找回标识行的值,而不是别人的行。

  3. 有一个额外的列不是表中存储的实体的固有属性,这是为它产生的好处付出的小代价。

    这只是一个指南,只有在帮助时才应添加人工AUTO_INCREMENTED。在上面带有国家/地区表的示例中,不需要PK Country列:

    • 该表只包含几百行;其中没有插入或删除(实际上有,但只有一次;在您需要更改PK表之前,您的应用程序可能会退役);
    • CHAR[2]有一个很好的候选人:是ISO-3166国家/地区代码;甚至有两种口味:2个字母和3个字母 - 选择你最喜欢的;它是CHAR[3](或PK),因为表格很小,因为{{1}}不会影响性能。

答案 1 :(得分:0)

无需使用id即可获得最后插入的记录/行。

MySQL语法:

SELECT column_name FROM table_name ORDER BY column_name DESC LIMIT 1

它只会显示最后插入的记录。

来源:http://www.w3schools.com/sql/sql_func_last.asp

答案 2 :(得分:-1)

$stmt = $db->prepare("...");  
$stmt->execute();  
$id = $db->lastInsertId();