SQL语句之表的创建和使用

Posted cw旧巷

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL语句之表的创建和使用相关的知识,希望对你有一定的参考价值。

一、表的创建(DDL)

1.建表的语法格式

create table 表名(字段名1 数据类型,字段名2 数据类型,字段名3 数据类型);
表名建议以 t_ 开始,可读性强

创建一个学生表

包括学号、姓名、年龄、性别、手机号码、邮箱地址

create table t_student(
num int(13),
name varchar(255),
age int(3),
sex char(1),
phonenumber char(11),
email varchar(255)
);

2.mysql中的数据类型

(1)varchar(最长255)
可变长度的字符串,会根据实际的数据长度动态分配空间,节省空间。varchar(10),10表示最大可分配空间,会根据传过来的数据动态分配。
优点:节省空间
缺点:需要动态分配空间,速度慢
(2)char(最长255)
定长字符串,不管实际的数据长度是多少,分配固定长度的空间去存储数据,使用不恰当时,可能会导致空间的浪费
优点:不需要动态分配空间,速度快
缺点:使用不当时会导致空间浪费
(3)int(最长11)
数字中的整数型,等同于java的int
(4)bigint
数字中的长整型,等同于javal中的long
(5)float
单精度浮点型数据
(6)double
双精度浮点型数据
(7)date
短日期类型
(8)datetime
长日期类型
(9)clob
字符大对象,最多可以存储4G的字符串,超过255个字符的都要采用 clob 来存储
(10)blob
二进制大对象,专门用来存储图片、声音、视频等流媒体数据。往 blob 类型的字段上插入数据时,需要使用IO流。

3.删除表

(1)drop table 表名;,当这张表不存在时会报错
(2)drop table if exists 表名;,如果这张表存在,就删除,建议使用

二、在表中插入数据insert(DML)

1.insert

(1)insert into 表名(字段名1,字段名2,字段名3…) values(值1,值2,值3…);
字段名和值要一一对应(数量和数据类型)
(2)向学生表中插入数据
insert into t_student(num,name,age,sex,phonenumber,email) values(1001,‘jack’,21,‘m’,‘12312343234’,‘123456@qq.com’);

(3)insert语句但凡执行成功后必然会增加一条记录,没有给其他字段指定值的话,默认值是NULL

(4)在创建表时,可以用 default 给添加默认值,如下:
create table t_student(sex char(1) default ‘m’);

(5)insert语句中如果字段名要省略的话,要把所有的值都写上
insert into t_student values(2003,‘tom’,‘m’,123456,‘123453@qq.com’);

2.insert插入日期

(1)str_to_date:将字符串 varchar 类型转换成日期 date 类型,在 insert 中使用。
str_to_date(‘字符串日期’,‘日期格式’)
(2)date_format:将 date 类型转换成具有一定格式的 varchar 字符串类型,在 select 中使用。
date_format(日期类型数据,‘需要展示的格式’)
(3)mysql日期格式
%Y 年,%m 月,%d 日,%h 时,%i 分,%s 秒
(4)如果提供的日期字符串是 ‘%Y-%m-%d’ 这个格式,str_to_date 函数就不需要了

3.date和datetime区别

(1)date是短时期:只包括年月日,默认格式是:%Y-%m-d
(2)datetime是长日期:包括年月日时分秒,默认格式是:%Y-%m-d %h:%i:%s
(3)now(),获取系统的当前时间,年月日时分秒

三、修改(update)DML

1.语法格式

update 表名 set 字段名1=值1,字段名2=值2,字段名3=值3…where 条件;,注意:没有条件限制的话会导致所有的数据全部更新。
update t_student set name=‘tom’,age=22,sex=‘f’ where num=1002;

四、删除数据(delete)DML

1.语法格式

delete from 表名 where 条件;,没有条件的话,整张表都会被删除
delete from t_user where id=1;

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列,如果执行下面的语句它会报错:

1 update a_user set a_name = (select distinct a_id, b_name from b_user left join a_user on a_id = id_a);
2 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语句

1 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);
2 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语句之表的创建和使用的主要内容,如果未能解决你的问题,请参考以下文章

sql语句之表间字段值复制遇到的一些问题--基于mysql

MySQL语句SQL应用

数据库创建表的sql语句

MySQL必知应会-第21章-创建和操纵表

请问打开或创建表的sql语句是啥

ORACLE 创建表的SQL语句