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?请高手们帮忙,急啊!!!。。。
表连接到底咋回事,就是产生中间结果啊!用于给select/insert等操作用