sql语句之表间字段值复制遇到的一些问题--基于mysql
好久没来园子了,转眼2017已经到3月份了,前段时间一直忙没时间写博客(其实是自己懒),感觉内心好惭愧。昨天临下班前,技术老大突然对我说要改下表结构,问我能不能实现将一个表的字段值复制到另外一个表的某个字段中去,感觉这好拗口,其实就是表间字段值复制。于是,昨晚加了会儿班百度了下然后自己在本地测试了下,还真弄出来了,下面就把这个sql语句记下来,以备忘。
1,背景和需求
两张表a_user和b_user结构如下:
a_user
+--------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+----------------+
| id_a | int(11) | NO | PRI | NULL | auto_increment|
| a_name| varchar(45)| YES | | NULL | |
+--------+-------------+------+-----+---------+----------------+
b_user
+--------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+----------------+
| id_b | int(11) | NO | PRI | NULL |auto_increment|
| a_id | int(11) | NO | MUL | NULL | |
| b_name| varchar(45)| YES | | NULL | |
+--------+-------------+------+-----+---------+----------------+
两表间关系:表b_user的a_id外键参考表a_user的主键id_a。
记录分别如下:
a_user
+------+--------+
| id_a | a_name |
+------+--------+
| 1 | |
| 2 | |
| 3 | |
| 4 | |
+------+--------+
b_user
+------+------+--------+
| id_b | a_id | b_name |
+------+------+--------+
| 1 | 1 | 张三 |
| 2 | 2 | 李四 |
| 3 | 2 | 李四 |
| 4 | 3 | 王五 |
| 5 | 3 | 王五 |
| 6 | 3 | 王五 |
| 7 | 4 | 赵六 |
| 8 | 4 | 赵六 |
+------+------+--------+
需求:将b_user表中b_name字段的值复制到a_user表中的a_name。
2,百度和解决遇到的问题
百度了下,发现用这个sql语句靠点儿谱:
update a_user set a_name = (select b_name from b_user where id_a = a_id);
这个语句大概是指,更新表a_user的a_name字段,将表b_user中b_name字段的值作为值来源,但直接执行上面的语句时mysql会报错如下:
ERROR 1242 (21000): Subquery returns more than 1 row
意思是,update语句期望数据来源行数应该与a_user表中的行数4行是相等的,但是上面的子查询结果却是......,等下,上面的子查询可以执行么?当然不可以。其实上面的子查询也就相当于:
select b_name from b_user left join a_user on a_id = id_a;
但是它返回的结果是8行,与表a_user的行数不同。
(1)剔除数据来源的重复行
那么先解决这个问题,将重复的记录剔除不就可以了么: select distinct a_id, b_name from b_user left join a_user on a_id = id_a; 它返回的结果如下:
+------+--------+
| a_id | b_name |
+------+--------+
| 1 | 张三 |
| 2 | 李四 |
| 3 | 王五 |
| 4 | 赵六 |
+------+--------+
结果为2列,如果执行下面的语句它会报错:
update a_user set a_name = (select distinct a_id, b_name from b_user left join a_user on a_id = id_a);
ERROR 1241 (21000): Operand should contain 1 column(s)
那么怎么把上面的结果变为只包含b_name的一列呢?
(2)利用distinct按a_id剔除重复行后多了a_id列
这个也好解决,把子查询再嵌套一下就可以了:
select b_name from (select distinct a_id, b_name from b_user left join a_user on a_id = id_a) t;
好,再试下update语句
update a_user set a_name = (select b_name from (select distinct a_id, b_name from b_user left join a_user on a_id = id_a) t);
ERROR 1242 (21000): Subquery returns more than 1 row
可以看到上面又报了子查询结果与更新行数不一致的问题,奇怪,上面的子查询 select b_name from (select distinct a_id, b_name from b_user left join a_user on a_id = id_a) t; 结果是:
+--------+
| b_name |
+--------+
| 张三 |
| 李四 |
| 王五 |
| 赵六 |
+--------+
不是已经剔除了重复行了吗?
(3)子查询嵌套和sql语句执行顺序
分析下上面的问题:现在有两个子查询select语句,外层的select将内层的select作为数据来源进行查询,内层的select和外层的select单独执行时都可以返回预期的结果,那么为什么执行update时却出现了: ERROR 1242 (21000): Subquery returns more than 1 row ?
下面是我的猜测:update语句的执行是一行一行的,那么当更新第一条记录时,update会期望从select子查询中获取一条对应于第一条记录的数据,也就是update a_user set a_name = 值来源 where id_a = a_id;那么就需要加上where语句来限定:
update a_user set a_name = (select b_name from (select distinct a_id, b_name from b_user left join a_user on a_id = id_a) t where t.a_id = id_a);
这下就可以了,结果如下:
+------+--------+
| id_a | a_name |
+------+--------+
| 1 | 张三 |
| 2 | 李四 |
| 3 | 王五 |
| 4 | 赵六 |
+------+--------+
3,结果
先写到这儿吧,最后的语句是
update a_user set a_name = (select b_name from (select distinct a_id, b_name from b_user left join a_user on a_id = id_a) t where t.a_id = id_a);
说实话,心里还是没底。这里涉及到了sql嵌套查询、sql语句执行顺序、update语句执行过程等sql知识,总之,靠百度和自己误打误撞算是弄出了条sql,不过我只是在本地上测试了下,没有在生产环境下用,对于这条sql的执行效率啥的更是没有概念,先做个记录,以后再研究下。希望有专门搞数据库的同学能够指点下。
参考资料:
如何批量修改一列的值?把另一张表的某个字段对应的赋到这张表的某一字段中。
完
sql语句之表间字段值复制遇到的一些问题--基于mysql的更多相关文章
- Access sql语句创建表及字段类型
创建一张空表: Sql="Create TABLE [表名]" 创建一张有字段的表: Sql="Create TABLE [表名]([字段名1] MEMO NOT NUL ...
- Access sql语句创建表及字段类型(转)
http://www.cnblogs.com/hnyei/archive/2012/02/23/2364812.html 创建一张空表: Sql="Create TABLE [表名]&quo ...
- SQL语句添加删除修改字段及一些表与字段的基本操作
用SQL语句添加删除修改字段 1.增加字段 alter table docdsp add dspcode char(200)2.删除字段 ALTER TABLE table_NA ...
- 用SQL语句添加删除修改字段、一些表与字段的基本操作、数据库备份等
用SQL语句添加删除修改字段 1.增加字段 alter table docdsp add dspcode char(200) 2.删除字段 ALTER TABLE table_NAME DROP CO ...
- SQL语句 在一个表中插入新字段
SQL语句 在一个表中插入新字段: alter table 表名 add 字段名 字段类型 例: alter table OpenCourses add Audio varchar(50)alter ...
- SQL语句 删除表user 中字段name 内容重复的记录,
public class T01 { public static void main(String[] args) { int j=4; j=j+=j-=j*=j; System.out.printl ...
- SQL语句添加删除修改字段[sql server 2000/2005]
用SQL语句添加删除修改字段1.增加字段 alter table docdsp add dspcodechar(200)2.删除字段 ALTER TABLE table_NAME ...
- SQL语句添加删除修改字段
用SQL语句添加删除修改字段1.增加字段 alter table docdsp add dspcodechar(200)2.删除字段 ALTER TABLE table_NAME ...
- SQL语句之表操作
SQL语句系列 1.SQL语句之行操作 2.SQL语句之表操作 3.SQL语句之数据库操作 4.SQL语句之用户管理 写在前面 在上一篇博文里面我整理了“行”级别的操作,分别是“增(insert).删 ...
随机推荐
- OSGI企业应用开发(十二)OSGI Web应用开发(一)
前面文章中介绍了如何在OSGI应用中整合Spring和Mybatis框架,本篇文章开始介绍如何使用OSGI技术开发Web应用.对于传统的Java EE应用,应用中涉及到的Web元素无非就是Servle ...
- R中的空间数据分析
> library(sp) > library(maptools) > library(raster) > library(rgeos) > maxd3 = readAs ...
- mac 安装 mysql.tar.gz
解压目录到 MySQL 默认安装路径 /usr/local/mysql 下, /usr/local路径不存在时, 先 sudo mkdir /usr/local 创建. # 移动解压后的二进制包到安装 ...
- Innodb页面存储结构-2
上一篇<Innodb页面存储结构-1>介绍了Innodb页面存储的总体结构,本文会介绍页面的详细内容,主要包括页头.页尾和记录的详细格式. 学习数据结构时都说程序等于数据结构+算法,而在i ...
- MariaDB数据表操作实例
1. MariaDB 数据库操作实例 MariaDB>create database class; //创建class数据库 MariaDB>use class; MariaDB>c ...
- Asp连接Oracle (包含绿色版12.2客户端和ODBC驱动安装)
我能操作的终端电脑是一台linux系统可以上互联网 ,服务器在部署在独立的私网上,不方便上互联网.服务器是2008R2.安装vs不是很方便.其所linux下作开发不是不可以,java php mono ...
- python-ldap修改AD域用户密码(CA+SSL)
代码连接:https://github.com/raykuan/ldap-notes 使用python的ldap模块连接AD服务器,有两种方式: 非加密:con = ldap.initialize(' ...
- VC Debug和Release区别
https://msdn.microsoft.com/en-us/library/xz7ttk5s.aspx Optimizing Your Code Visual Studio 2015 The ...
- .net core 入坑经验 - 2、MVC Core之获取网站运行路径
这次是建立了asp.net mvc core项目,在controller中想获取网站在硬盘中的路径,找了一圈Server.MapPath() 已不存在,HttpContent也一样,经过查阅资料发现是 ...
- 彻底理解lib和dll
转自:http://www.cppblog.com/amazon/archive/2009/09/04/95318.html 两种库:一种是LIB包含了函数所在的DLL文件和文件中函数位置的信息(入口 ...