【问题标题】:MariaDB conditional insert with placeholders doesn't work with PDO带有占位符的 MariaDB 条件插入不适用于 PDO
【发布时间】:2019-09-15 05:17:58
【问题描述】:

我的博客有以下表格:

tags 包含列 tag_id (A.I.) 和 tag

post_tags 具有列post_idtag_id。它描述了哪些标签属于哪些帖子。

我正在尝试进行一些 SQL 查询,将给定的tag 绑定到post_tags 中的给定post_id,但如果tagtags 中不存在,它会首先在那里创建它。

$query = 
SQL
DELIMITER //

BEGIN NOT ATOMIC
    IF NOT EXISTS (SELECT `tags`.`tag` FROM `tags` WHERE `tag`  = :tagname) THEN 
       INSERT INTO `tags` (`tag_id`, `tag`) VALUES (NULL, :tagname);
    END IF;
END //

DELIMITER ;

INSERT INTO post_tags (post_id, tag_id)  SELECT :postid, tags.tag_id FROM tags WHERE tags.tag = :tagname;

然后我有以下 PHP 代码来执行这个过程:

// all $db variables are given, known and correct.
$pdoconn = new PDO("mysql:host=$dbhost;dbname=$db", $dbuser, $dbpass);
$pdoconn -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$taginsert = $pdoconn -> prepare($query);

$id = 0; // The post_id. This is given, known and correct.
$tags = array(); // Array of strings (the tags)
foreach ($tags as $tag){
    try{
        $taginsert -> bindValue(":tagname", $tag, PDO::PARAM_STR);
        $taginsert -> bindValue(":postid", $id, PDO::PARAM_INT);
        $taginsert -> execute();
    } catch(PDOException $e){
        $message = $e->getMessage();
        var_dump($message);
    }
}

$taginsert -> close();

这应该足够简单。事实上,当替换实际值的占位符并从 phpMyAdmin 中执行原始查询时,它可以工作!但是当我执行 pdo php 代码时,它只是转储了这个错误:

string(284) "SQLSTATE[42000]: 语法错误或访问冲突:1064 您的 SQL 语法有错误;请查看与您的 MariaDB 服务器版本相对应的手册,了解在 'DELIMITER // 附近使用的正确语法如果不存在则开始非原子(从tags' at line 1" 中选择tags.tag 不用说这个神秘的错误信息对我没有用。

我正在使用 php 7.3 和 10.1.30-MariaDB-1~xenial

【问题讨论】:

  • 尝试删除分隔符,因为它只需要命令行。此外,PDO 一次只能处理 1 个查询语句,因此您必须将其分解为两个单独的查询。
  • 我不是 100% 确定 MariaDB,但我不相信 MySQL 在存储过程和函数定义。在过去,当需要它并且允许连接时,我能够制作“临时”存储过程来做我需要的事情,然后再删除它们。 (3 个查询:create proc、exec proc、drop proc)
  • @aynber 解决了错误,但也给出了一个新的:(11 确实是它卡住的帖子) SQLSTATE[42000]:语法错误或访问冲突:1064 你有一个错误你的 SQL 语法;检查与您的 MariaDB 服务器版本相对应的手册,以在第 7 行的 'INSERT post_tags (post_id, tag_id) SELECT 11, tags.tag_id FROM tags' 附近使用正确的语法。所以,是的,我会分手的。
  • 我认为整个任务可以用一个语句来完成。请参阅 IODKU 和 LAST_INSERT_ID()。

标签: php mysql if-statement pdo mariadb


【解决方案1】:

我使用以下 php 代码达到了预期的效果:

请记住,我的错误/边界检查在这里很少,因为我知道我正在使用的数据集。

$pdo = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
$postid;
$tags = [];
$tagidStmt      = $pdo->prepare("SELECT tag_id FROM tags WHERE tag = :tagname;"); // $tag
$linkExistsStmt = $pdo->prepare("SELECT * FROM post_tags WHERE post_id = :postid AND tag_id = :tagid;"); // $postid, $tagid
$insertionStmt  = $pdo->prepare("INSERT INTO post_tags (post_id, tag_id) VALUES (:postid, :tagid);"); // $postid, $tagid

foreach ($tags as $tag){
    $tagidStmt -> execute(['tagname' => $tag]);
    $tagid = ($tagidStmt -> fetch())["tag_id"];
    $tagid = intval($tagid);

    $linkExistsStmt -> execute(['postid' => $postid, 'tagid' => $tagid]);
    $linkExists = $linkExistsStmt -> fetch();

    if ($linkExists === false){
        $insertion = $insertionStmt -> execute(['postid' => $postid, 'tagid' => $tagid]);
    }
}

【讨论】:

    猜你喜欢
    • 2013-01-13
    • 2016-07-15
    • 2015-03-28
    • 2014-10-15
    • 1970-01-01
    • 2018-06-22
    • 2017-10-25
    • 2012-09-25
    • 2012-01-27
    相关资源
    最近更新 更多