INSERT + SELECT + ON DUPLICATE KEY 与 SELECT 子句中的列别名

Posted

技术标签:

【中文标题】INSERT + SELECT + ON DUPLICATE KEY 与 SELECT 子句中的列别名【英文标题】:INSERT + SELECT + ON DUPLICATE KEY with column aliases in SELECT clause 【发布时间】:2015-05-18 02:49:39 【问题描述】:

在 SELECT 子句具有列别名的查询中尝试将 INSERT、SELECT 和 ON DUPLICATE KEY 链接在一起时,我遇到了一个相当令人惊讶的障碍。例如,考虑以下情况:

表格

CREATE TABLE source ( 
    id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    v INT NOT NULL
);
INSERT INTO source (v) VALUES (1), (2), (3);
CREATE TABLE dest (
    id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    v INT NOT NULL
);

假设我试图用POW(source.v,2) 的值填充dest.v,而不管dest 中是否已经存在值。当然,我试过了:

INSERT INTO dest 
    SELECT id, POW(v, 2) AS p FROM source 
    ON DUPLICATE KEY UPDATE dest.v=source.p;

但是,mysql 坚持认为 source.p 不存在:

错误 1054 (42S22):“字段列表”中的未知列“source.p”

相当不方便,我不得不求助于使用更慢更麻烦的查询:

INSERT INTO dest 
    SELECT * FROM ( 
         SELECT id, POW(v, 2) AS p FROM source 
    ) s
    ON DUPLICATE KEY UPDATE dest.v=s.p;

这与原始查询几乎没有什么不同,但有效。为什么会这样?

【问题讨论】:

您的替代代码只是添加了一组新记录,因为选择结果中没有键字段来进行重复的键击。 【参考方案1】:

我总是在下面写查询

INSERT INTO dest ( id, v)
SELECT id, POW(v, 2) AS p FROM source 
ON DUPLICATE KEY UPDATE dest.v=VALUES(v);

VALUES() 避免再次编写相同的表达式。始终尝试指定要插入的列名称,以防万一您将来添加新列

【讨论】:

似乎UPDATE dest.v=VALUES(v);dest.v 设置为自身。也许我应该澄清一下:如果source 中的值发生变化,则查询需要更改dest 中的值。例如,如果我运行UPDATE source SET v=v*2;SELECT v FROM dest WHERE id=3 在这种情况下应该产生 36。 values(v) 表示将使用您在插入中制定的值。请阅读手册中的更多内容:dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html 哦,真的!对不起,我误会了;我误解了VALUES的功能。【参考方案2】:

函数的别名只是由 mysql 评估以供直接使用。一个不太糟糕的替代查询可能是:

INSERT INTO dest (v) 
    SELECT POW(v, 2) AS p FROM source 
    ON DUPLICATE KEY UPDATE dest.v=POW(v, 2);

(未测试...)

【讨论】:

所以如果dest 中存在键,则不会在SELECT 子句中评估POW(v, 2) 已评估,只有分配的别名不可用。我们可以称之为 MySQL 的一个改进点。你会在更多的情况下遇到这种情况(够难过的)。也许 MariaDB 项目会更快地处理这种改进(拭目以待)

以上是关于INSERT + SELECT + ON DUPLICATE KEY 与 SELECT 子句中的列别名的主要内容,如果未能解决你的问题,请参考以下文章

MySQL INSERT INTO / ON DUPLICATE KEY 与 SELECT 语句问题

SQL中 怎么将indentify_insert 设置为on?请高手们帮忙,急啊!!!。。。

INSERT ON DUPLICATE KEY:一起添加值

表连接到底咋回事,就是产生中间结果啊!用于给select/insert等操作用

INSERT ... ON DUPLICATE KEY UPDATE Syntax 专题

在多模块 Java 应用程序中的 INSERT/UPDATE 之前禁用 SELECT