MySql中select from一个将要更新的关系目标

本文详细介绍了在MySQL中如何解决在更新操作中引用自身子查询时遇到的问题,通过将子查询衍生关系实体化为临时表来实现数据更新与查询的同步。同时提供了多个相关链接供深入学习。

MySql中如何select from一个将要更新的关系目标:

问题陈述:

在《数据库系统概念第五版》(<DatabaseSystem Concepts> Fifth Edition),第三章,3.10.3SQL的更新,有个例子是:

+-------------------------+--------------------+------------+

|account_number | branch_name | balance |

+------------------------+---------------------+------------+

|A-101                 | Downtown     | 500.00  |

|A-102                 | Perryridge     | 400.00  |

|A-201                 | Brighton        | 900.00  |

|A-215                 | Mianus          | 700.00   |

|A-217                 | Brighton        | 750.00   |

|A-222                 | Redwood        | 700.00  |

|A-305                 | Round Hill     | 350.00   |

+------------------------+----------------------+------------+

updateaccount

setbalance = balance * 1.05

wherebalance > (select avg(balance)

fromaccount);

然后就报错了!有没有!如下:

Youcan't specify target table 'account' for update in FROM clause

错误就是你不能指向并选择一个将要修改或是更新的目标关系。

http://dev.mysql.com/doc/refman/5.0/en/update.html写到:

Currently,you cannot update a table and select from the same table in asubquery.”

但是很多情况下,我想用一些数据要更新一个关系,而这些数据恰好是通过就指向这个关系的子查询得到的,例如本例子我需要聚集函数算accountbalance均值。


解决方法:

MySQL会将from从句中子查询的衍生关系(derivedtable)实体化成一个临时表(temporarytable),所以我们将(selectavg(balance) from account) 再套入一个from从句即可:

updateaccount

setbalance = balance * 1.05

wherebalance >( select avg(tmp.balance)

from (select * from account ) as tmp

)


参考:

  1. http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/

  2. http://dev.mysql.com/doc/refman/5.0/en/update.html

  3. http://forge.mysql.com/wiki/MySQL_Internals

<think>好的,用户现在想了解MySQL中的SELECT INTO FROM语句的功能和用法。我需要根据提供的引用内容来整理回答,同时结合之前关于DELIMITER的回答中的知识。 首先,用户提到的引用[1]到[5]主要涉及SELECT INTO的不同使用场景和版本变化。引用[1]指出,从MySQL 8.0.20开始,INTO的位置发生了变化,推荐放在语句末尾,而之前的用法会被废弃。这意味着需要强调语法的新旧差异,避免用户在使用时出现兼容性问题。 引用[2]、[3]、[4]、[5]展示了SELECT INTO的具体示例,包括将查询结果插入到新表或现有表中。需要注意的是,在MySQL中,SELECT INTO有两种形式:一种是创建新表并插入数据(SELECT ... INTO OUTFILE),另一种是将数据插入到现有表中(INSERT INTO ... SELECT)。但根据引用中的例子,用户可能更关注的是将查询结果存储到新表或变量中,或者插入到现有表中。 接下来,我需要确认用户的问题重点。用户询问的是SELECT INTO FROM的功能和用法,可能需要区分不同的应用场景,比如导出数据到文件、创建新表、插入现有表,以及存储到变量中。同时,版本差异也是关键点,特别是MySQL 8.0.20后的语法变化。 在之前的回答中,用户了解了DELIMITER的用途,但当前问题与数据查询和导出相关,可能需要结构化的回答,分点说明功能、用法、版本变化、注意事项等。同时,用户可能需要示例来更好地理解,例如创建新表的例子、插入到现有表的例子,以及变量赋值的例子。 需要注意引用中的警告,比如旧版语法在锁定子句前使用INTO会产生警告,未来可能被移除,这部分需要特别提醒用户,避免使用过时的语法。此外,INTO OUTFILE的用法需要文件权限,这也是常见的问题点,应该在注意事项中提到。 用户可能的应用场景包括数据备份、报表生成、临时数据处理等,这些可以作为典型应用场景来举例,帮助用户理解何时使用该语句。 最后,生成相关问题需要考虑用户可能进一步的问题,比如性能优化、权限问题、错误处理等,确保覆盖用户可能的疑问点。</think>### MySQL中 `SELECT...INTO...FROM` 语句详解 --- #### 一、核心功能 `SELECT...INTO...FROM` 在MySQL中主要用于**将查询结果存储到指定位置**,包含以下三类典型场景: 1. **创建新表并插入数据** ```sql SELECT [列] INTO 新表名 FROM 原表 [条件]; -- 自动创建新表并插入查询结果 ``` 2. **导出数据到文件** ```sql SELECT [列] INTO OUTFILE '文件路径' FROM 表 [条件]; -- 结果导出为文件 ``` 3. **存储到变量** ```sql SELECT [列] INTO @变量名 FROM 表 [条件]; -- 将查询结果赋值给用户变量 ``` --- #### 二、语法演进(版本差异) - **MySQL 8.0.20之前** `INTO` 子句可放置在 `FROM` 前或语句末尾,但存在语法歧义风险[^1]。 ```sql SELECT col1, col2 INTO @var1, @var2 FROM table WHERE id=1; -- 旧版合法语法 ``` - **MySQL 8.0.20及之后** 官方强制要求 `INTO` **必须置于语句末尾**,此前的位置(如 `FROM` 前)会触发警告,未来版本可能完全禁用[^1]。 ```sql SELECT col1, col2 FROM table WHERE id=1 INTO @var1, @var2; -- 新版推荐语法 ``` --- #### 三、具体用法与示例 ##### 1. 创建新表(自动建表) ```sql -- 创建新表 `employees_backup`,结构与查询结果一致 SELECT * INTO employees_backup FROM employees WHERE department = 'IT'; ``` - **限制**:新表必须不存在,否则报错;字段属性(如索引、约束)不会继承[^3]。 ##### 2. 导出数据到文件 ```sql SELECT name, salary INTO OUTFILE '/tmp/employees.csv' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' FROM employees WHERE salary > 5000; ``` - **关键参数**: - `FIELDS TERMINATED BY`:列分隔符(默认`\t`) - `LINES TERMINATED BY`:行分隔符(默认`\n`) - **权限要求**:MySQL服务需有文件系统写入权限[^1]。 ##### 3. 存储到用户变量 ```sql SELECT COUNT(*) INTO @total FROM orders WHERE status = 'completed'; SELECT @total; -- 输出变量值 ``` ##### 4. 插入现有表(需结合 `INSERT`) ```sql -- 将查询结果插入已存在的表(需字段匹配) INSERT INTO sales_report (product, revenue) SELECT product, SUM(price*quantity) FROM orders GROUP BY product; ``` --- #### 四、典型应用场景 1. **数据备份** 快速备份关键数据到新表或文件[^4]: ```sql SELECT * INTO OUTFILE '/backup/2023_orders.csv' FROM orders WHERE year=2023; ``` 2. **中间结果存储** 复杂查询中暂存中间结果: ```sql CREATE TEMPORARY TABLE temp_sales AS SELECT product, SUM(amount) FROM sales GROUP BY product; ``` 3. **变量传递** 存储统计结果供后续SQL使用: ```sql SELECT AVG(salary) INTO @avg_salary FROM employees; UPDATE salaries SET adjustment = salary * 0.1 WHERE salary < @avg_salary; ``` --- #### 五、注意事项与常见错误 | 问题类型 | 原因与解决方案 | |------------------------|-------------------------------------------------------------------------------| | **表已存在错误** | `CREATE TABLE ... SELECT` 替代 `SELECT INTO` 若需覆盖现有表[^2] | | **文件写入权限错误** | 检查MySQL用户对目标目录的写权限,或使用 `SHOW VARIABLES LIKE 'secure_file_priv'` 确认允许路径 | | **字段不匹配错误** | 插入现有表时需确保目标表字段数量、类型与查询结果一致[^5] | | **版本兼容性问题** | MySQL 8.0.20+ 需将 `INTO` 放在语句末尾,否则触发警告 `ER_WARN_DEPRECATED_SYNTAX`[^1] | --- #### 六、与类似语句对比 | 语句 | 核心差异 | |-------------------------|-------------------------------------------------------------------------| | `CREATE TABLE ... AS SELECT` | 显式创建新表,支持字段定义和约束,替代 `SELECT INTO` 的自动建表功能[^3] | | `INSERT INTO ... SELECT` | 向已有表插入数据,需手动匹配字段 | | `LOAD DATA INFILE` | 从文件导入数据,与 `INTO OUTFILE` 互为逆向操作 | --- ### 相关问题 1. 如何将 `SELECT...INTO` 的结果追加到现有文件? 2. 在MySQL 8.0.20+中如何兼容旧版 `SELECT INTO` 语法? 3. `SELECT INTO OUTFILE` 导出的文件格式如何自定义? --- 通过合理使用 `SELECT...INTO...FROM`,可实现高效的数据导出、转换与暂存操作,但需特别注意版本语法差异和权限配置[^1][^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值