Mysql 为什么此SQL查询不起作用?

Mysql 为什么此SQL查询不起作用?,mysql,sql,Mysql,Sql,我编写了此查询,但出现以下错误: 致命错误:未捕获的异常“PDOException”带有消息 'SQLSTATE[42000]:语法错误或访问冲突:1064您有 SQL语法错误;检查与您的产品相对应的手册 MariaDB服务器版本,以便在“BEGIN INSERT”附近使用正确的语法 进入forum\u topics\u track(userid,topic\u id,'c'在第3行 我想这是不言自明的,但我的目标是检查记录是否存在,如果不存在,则插入它 IF NOT EXISTS

我编写了此查询,但出现以下错误:

致命错误:未捕获的异常“PDOException”带有消息 'SQLSTATE[42000]:语法错误或访问冲突:1064您有 SQL语法错误;检查与您的产品相对应的手册 MariaDB服务器版本,以便在“BEGIN INSERT”附近使用正确的语法 进入
forum\u topics\u track
userid
topic\u id
,'c'在第3行

我想这是不言自明的,但我的目标是检查记录是否存在,如果不存在,则插入它

IF NOT EXISTS 
                (SELECT * FROM `forum_topics_track` WHERE `userid` = '{$userid}' AND `topic_id` = '{$topic_id}') 
            BEGIN
                INSERT INTO `forum_topics_track` (`userid`, `topic_id`, `category_id`) 
                VALUES ('{$topic_id}', '{$category_id}', '{$userid}')
            END;

一个更快的选择是在
userid
topic\u id
上有一个唯一的索引

CREATE UNIQUE INDEX forum_topics_track_ndx ON forum_topics_track(userid, topic_id);
那你就可以做了

INSERT IGNORE INTO `forum_topics_track` (`userid`, `topic_id`, `category_id`) 
            VALUES ('{$topic_id}', '{$category_id}', '{$userid}');
这将始终成功(如果数据已经存在,则可能什么也不做)


或者您可以查看重复键更新的
技巧。

一个更快的替代方法是在
用户id
主题id
上有一个唯一的索引

CREATE UNIQUE INDEX forum_topics_track_ndx ON forum_topics_track(userid, topic_id);
那你就可以做了

INSERT IGNORE INTO `forum_topics_track` (`userid`, `topic_id`, `category_id`) 
            VALUES ('{$topic_id}', '{$category_id}', '{$userid}');
这将始终成功(如果数据已经存在,则可能什么也不做)


或者您可以查看重复密钥更新的
技巧。

这是实现逻辑的错误方法。如果您希望每个用户和主题在
论坛主题跟踪中出现一次,则让数据库强制执行约束。使用唯一索引或约束很容易:

create unique index unq_forum_topics_track_user_topic on forum_topics_track(user_id, topic_id);
然后,您可以执行插入并忽略或处理错误:

INSERT INTO `forum_topics_track` (`userid`, `topic_id`, `category_id`) 
    VALUES ('{$topic_id}', '{$category_id}', '{$userid}')
    ON DUPLICATE KEY UPDATE userid = VALUES(userid);

逻辑中不需要
IF
。事实上,使用
IF
只会因竞争条件而引发问题,并不能真正保证数据库中的任何内容。

这是错误的逻辑实现方式。如果您希望每个用户和主题都出现在
论坛主题跟踪中一次,那么就让数据库强制执行约束。使用唯一索引或约束很容易:

create unique index unq_forum_topics_track_user_topic on forum_topics_track(user_id, topic_id);
然后,您可以执行插入并忽略或处理错误:

INSERT INTO `forum_topics_track` (`userid`, `topic_id`, `category_id`) 
    VALUES ('{$topic_id}', '{$category_id}', '{$userid}')
    ON DUPLICATE KEY UPDATE userid = VALUES(userid);

逻辑中不需要
IF
。事实上,使用
IF
只会由于竞争条件而引发问题,并不能真正保证数据库中的任何内容。

IF NOT EXISTS是一个在MS-SQL中可用但在MySQL中不可用的子句。请尝试以下查询

INSERT INTO `forum_topics_track` (`userid`, `topic_id`, `category_id`) 
SELECT '{$topic_id}', '{$category_id}', '{$userid}'
WHERE NOT EXISTS(
    SELECT * FROM `forum_topics_track` WHERE `userid` = '{$userid}' AND `topic_id` = '{$topic_id}'
)

IF NOT EXISTS是一个在MS-SQL中可用但在MySQL中不可用的子句。请尝试以下查询

INSERT INTO `forum_topics_track` (`userid`, `topic_id`, `category_id`) 
SELECT '{$topic_id}', '{$category_id}', '{$userid}'
WHERE NOT EXISTS(
    SELECT * FROM `forum_topics_track` WHERE `userid` = '{$userid}' AND `topic_id` = '{$topic_id}'
)

没有必要先检查任何东西。事实上,它完全起反作用!没有必要先检查任何东西。事实上,它完全起反作用!是的,这是我尝试的第一件事,它起了作用。谢谢你和其他人回答了我的问题。是的,这是我尝试的第一件事,它起了作用。谢谢你,对其他人,我不知道这回答了我的问题。如果没有FROM子句,您不能使用WHERE子句。但是您可以使用FROM子句中的子查询来修复它。嗨,Paul,我测试了这个查询,它工作正常。只有在我尝试运行查询的以下部分时,才会需要FROM子句。如果不存在,请选择“{$topic_id}”、“{$category_id}”、“{$userid}”(从我测试它的
forum\u topics\u track
WHERE
userid
='{$userid}'和
topic\u id
='{$topic\u id}')中选择*,让我惊讶的是它成功了。但是它在我本地的MariaDB 10.0.19上不起作用。我很确定它在MySQL 5.6上也不起作用,但是我这里没有要测试的安装。如果你看一下,你会发现,
WHERE
如果没有
FROM
:“[FROM table\u references[PARTITION\u list][WHERE_条件]…]。因此,虽然它在MySQL 5.7上工作,但这种行为没有被记录。我在参考手册中发现,SELECT也可以用于检索不引用任何表而计算的行。例如:MySQL>SELECT 1+1;->2允许在没有引用表的情况下指定DUAL作为伪表名:MySQL>SELEC来自DUAL的T1+1;->2(几乎类似于oracle SQL)这是真的,我已经用过很多次了。但是在这个例子中没有WHERE子句。没有FROM子句,你不能使用WHERE子句。但是你可以用FROM子句中的子查询来修复它。嗨,Paul,我测试了这个查询,它工作得很好。只有在我尝试运行查询的以下部分时,才会需要FROM子句。选择“{$topic id},”{$category\u id}',{$userid}不存在的地方(从
forum\u topics\u track
WHERE
userid
='{$userid}'和
topic\u id
='{$topic\u id}中选择*),我对其进行了测试(运行MySQL 5.7),让我惊讶的是它成功了。但是它在我本地的MariaDB 10.0.19上不起作用。我很确定它在MySQL 5.6上也不起作用,但是我这里没有要测试的安装。如果你看一下,你会发现,
WHERE
如果没有
FROM
:“[FROM table\u references[PARTITION\u list][WHERE_条件]…]。因此,虽然它在MySQL 5.7上工作,但这种行为没有被记录。我在参考手册中发现,SELECT也可以用于检索不引用任何表而计算的行。例如:MySQL>SELECT 1+1;->2允许在没有引用表的情况下指定DUAL作为伪表名:MySQL>SELECDUAL中的t1+1;->2(几乎类似于oracle SQL),这是正确的,我已经多次使用过它,但在该示例中没有WHERE子句。