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).删 ...
随机推荐
- js 匿名函数立即执行问题
js立即执行函数写法理解 这篇真的写得很清楚了,不光括号可以将函数声明转换成函数表达式然后立即执行,!,+,-,=也都可以转换,但是可能会带来意外的结果,因此一般都用括号实现. 还有关于for (va ...
- hadoop在zookeeper上的高可用HA
(参考文章:https://www.linuxprobe.com/hadoop-high-available.html) 一.技术背景 影响HDFS集群不可用主要包括以下两种情况:一是NameNode ...
- 使用JNDI+连接池
配置context.xml,在META-INF下新建context.xml,内容如下 <?xml version="1.0" encoding="UTF-8&quo ...
- OpenCV 线条及形状
1.线条 # dst 相当于画板 dst=np.zeros((300,300,3),np.uint8) # #参1 图像 参2 起始点 参3 结束点 参4 颜色 line=cv2.line(dst,( ...
- IIS下众多网站,如何快速定位某站点日志在哪个文件夹?
windows2008,iis 多站点, 日志.应用程序池都是默认设置, 没有分开………… Logs目录里面有W3SVC43,W3SVC44,W3SVC45,W3SVC46.....等等日志文件夹. ...
- StretchBlt和StretchDIBits
StretchBlt:从源矩形中复制一个位图到目标矩形,必要时按目标设备设置的模式进行图像的拉伸或压缩,如果目标设备是窗口DC,则意味着在窗口绘制位图,大致的使用代码如下: void DrawImag ...
- JAVAEE——SSH项目实战01:SVN介绍、eclipse插件安装和使用方法
1 学习目标 1.掌握svn服务端.svn客户端.svn eclipse插件安装方法 2.掌握svn的基本使用方法 2 svn介绍 2.1 项目管理中的版本控制问题 通常软件开发由多人协作开发,如果对 ...
- GIT回推本地commit近期版本
一次意外吧,本地add并且commit之后拉了别人错误的代码下来,后来本地又需要进行编写测试,无奈只能回推到自己刚刚commit过的代码,但是git命令除了拉去提交等其他的不是很熟悉,在度娘之后也遇到 ...
- RBAC用户权限管理数据库设计【转载】
本文转载自:https://www.kancloud.cn/martist/ma_zhao_liu/374123 简单地说,一个用户拥有若干角色,每一个角色拥有若干权限.这样,就构造成“用户-角色-权 ...
- 【转】电脑运行命令CMD集锦
在win7系统里直接点开始,最左下面有个搜索框,在里面直接输CMD,回车就可以:或者win键+R键,出现对话框,输入CMD,回车就可以了: winver 检查Windows版本 wmimgmt.msc ...