Mysql知识总结
mysql 登录命令:
mysql -uroot -pbank 这句话的意思是用root用户登录,密码是bank。
mysql -uroot -p bank 这句话的意思是用root用户登录,bank是进入后切换到bank这个数据库,此时按下回车会提示输入密码。进入后不用use bank 来切换到bank数据库,自动就是bank数据库。
mysql -uroot -pbank <=等价于=> mysql -u root -pbank 也就是说-uroot 等价于 -u root 。不论中间是否有空格隔开都一样。代表用root这个用户进行登录。
查看当前时间:
mysql> select now() from dual;
+---------------------+
| now() |
+---------------------+
| 2017-10-25 22:05:38 |
+---------------------+
1 row in set (0.03 sec)
mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2017-10-25 22:05:47 |
+---------------------+
1 row in set (0.00 sec)
之所以要使用from dual是为了兼容oracle数据库,如果只是MySQL的话,可以省略from dual;因为某些数据库服务器规定查询语句中必须包含from字句,并在其中至少指明一个表名。
MySQL字符型数据
字符型数据分为定长或者变长两类,不同点在于固定长度的字符串使用空格向右填充,以保证占用同样的字节数;变长字符串不需要向右填充,并且所有字节数可变。当定义一个字符串类型时,必须要指定能存放的字符串最大长度。例如,需要存储最大不超过20个字节的字符串,可以用下列方式:
char(20) /* fixed-length */
varchar(20) /* variable-length */
char最大可以设置为255个字节,varchar则可以最多保存65535个字节。要存储比65535更长的字符串则要使用文本类型了。
文本数据
如果需要存储的数据超过64KB(varchar的上限),就需要使用文本类型。
文本类型 最大能存储的字节数(B)
tinytext 255
text 65535
mediumtext 16777215
longtext 4294967295
观察可以发现,其实是用规律的,255 = 2^8 -1 ; 65535 = 2^16 -1 ; 16777215 = 2^24 -1 ; 4294967295 = 2^32 -1 ;
注意事项:
1.如果被装载到文本列中的数据超出了该类型的最大长度,数据会被截断。
2.在向文本列装载数据时,不会消除数据的尾部空格。而char类型会。
3.使用文本列进行排序、分组的时候,只会使用前1024个字符
4.这些不同的文本类型只是针对MySQL,sql Server对于大的字符型数据只提供text类型,而db2和oracle使用的数据类型是Clob。
5.现在MySQL允许varchar列最大容纳65535个字节了(在MysQL4中为255个字符),也就是和text一样大了,所以一般情况不会用到tinytext、text了,超过65535用mediumtext或者longtext;少于65535则使用varchar。
6.Oracle中,char能容纳2000个字节,varchar2能容纳4000个,sql Server中char和varchar都能容纳8000个字节。
MySQL中的浮点数
浮点数是用来表示实数的一种方法,它用 M(尾数) * B( 基数)的E(指数)次方来表示实数,相对于定点数来说,在长度一定的情况下,具有表示数据范围大的特点。但同时也存在误差问题。 浮点数有多种实现方法,计算机中浮点数的实现大都遵从 IEEE754 标准,IEEE754 规定了单精度浮点数和双精度浮点数两种规格:
单精度浮点数用4字节(32bit)表示浮点数,格式是: 1位符号位 8位表示指数 23位表示尾数
双精度浮点数用8字节(64bit)表示浮点数,格式是: 1位符号位 11位表示指数 52位表示尾数
IEEE754标准还对尾数的格式做了规范:d.dddddd...,小数点左面只有1位且不能为零,计算机内部是二进制,因此,尾数小数点左面部分总是1。显然,这个1可以省去,以提高尾数的精度。
下图是IEEE754的浮点数标准图:
由上图可知,单精度浮点数的尾数虽然只有23位,但是由于第一位一定是1,所以其实是用24bit表示的;
双精度浮点数的尾数虽然只有52位,但是由于第一位一定是1,所以其实是用53bit表示的;
IEEE754标准中,一个规格化32位的浮点数x的真值表示为:
其中尾数域表示的值是1.M。因为规格化的浮点数的尾数域最左位总是1,故这一位不予存储,而认为隐藏在小数点的左边。
8 位的阶码e指数为可以表达 0 到 255 之间的 256 个指数值。但是,指数可以为正数,也可以为负数。为了处理负指数的情况,实际的指数值按要求需要加上一个偏差(Bias)值作为保存在指数域中的值,单精度数的偏差值为 127;偏差的引入使得对于单精度数,实际可以表达的指数值的范围就变成 -127(0 - 偏差值127) 到 128 (255 - 偏差值127)之间(包含两端)。在本文中,最小指数和最大指数分别用 emin 和 emax 来表达。实际的指数值 -127(保存为全0)以及 +128(保存为全 1)保留用作特殊值的处理。
(1)最大正数
单精度浮点数最大正数值的符号位S=0,阶码E=254,指数e=254-127=127,尾数M=111 1111 1111 1111 1111 1111,其机器码为:0 11111110 111 1111 1111 1111 1111 1111。
那么最大正数值:
mysql> select utc_timestamp();
+---------------------+
| utc_timestamp() |
+---------------------+
| 2017-10-26 02:42:02 |
+---------------------+
1 row in set (0.02 sec)
可以看到返回的格式是YYYY-MM-DD HH:MI:SS。Sql Server可以用getutcdate()函数获取。
查看全局时区和会话时区
mysql> SELECT @@global.time_zone,@@session.time_zone;
+--------------------+---------------------+
| @@global.time_zone | @@session.time_zone |
+--------------------+---------------------+
| SYSTEM | SYSTEM |
+--------------------+---------------------+
1 row in set (0.00 sec)
mysql> select @@global.time_zone,@@session.time_zone;
+--------------------+---------------------+
| @@global.time_zone | @@session.time_zone |
+--------------------+---------------------+
| SYSTEM | +08:00 |
+--------------------+---------------------+
1 row in set (0.00 sec)
此时会话中显示的所有日期都符合北京时间。
如果需要向datetime或者timestamp列中添加一条2017年1月23日下午15:00的数据,可以使用下列的字符串:
‘2017-01-23 15:00:00’
'2017/01/23 15,00,00'
'2017,01,23 15,00,00'
'20170123150000'
以上的字符串都可以产生日期,但是会比较死板,必须要有固定的格式,缺一不可。
产生日期的函数
mysql> select date_add(current_timestamp(),interval 5 day);
+----------------------------------------------+
| date_add(current_timestamp(),interval 5 day) |
+----------------------------------------------+
| 2017-10-31 11:58:00 |
+----------------------------------------------+
1 row in set (0.00 sec)
#在现在的时间的基础上增加3小时25分钟0秒
mysql> select date_add(current_timestamp(),interval '3:25:00' hour_second);
+--------------------------------------------------------------+
| date_add(current_timestamp(),interval '3:25:00' hour_second) |
+--------------------------------------------------------------+
| 2017-10-26 15:23:53 |
+--------------------------------------------------------------+
1 row in set (0.00 sec)
#在现在的时间的基础上增加了1年12月
mysql> select date_add(current_timestamp(),interval '1-12' year_month);
+----------------------------------------------------------+
| date_add(current_timestamp(),interval '1-12' year_month) |
+----------------------------------------------------------+
| 2019-10-26 11:59:23 |
+----------------------------------------------------------+
1 row in set (0.00 sec)
mysql> select date_add(current_timestamp(),interval '5:10' minute_second);
+-------------------------------------------------------------+
| date_add(current_timestamp(),interval '5:10' minute_second) |
+-------------------------------------------------------------+
| 2017-10-26 12:07:59 |
+-------------------------------------------------------------+
1 row in set (0.02 sec)
常用的时间间隔类型表
间隔名称 描述
second 秒数
minute 分钟数
hour 小时数
day 天数
month 月份数
year 年份
minute_second 分钟数和秒数,中间用“:”隔开
hour_second 小时数、分钟数、秒数,中间用“:”隔开
year_month 年份和月份,中间用“-”隔开
2.last_day()函数
要获取当前时刻的月底是哪一天,可以使用last_day()函数,这个函数的作用就是简单地返回传入的日期的月末日期。
mysql> select last_day(current_timestamp());
+-------------------------------+
| last_day(current_timestamp()) |
+-------------------------------+
| 2017-10-31 |
+-------------------------------+
1 row in set (0.00 sec)
可以像上边一样传入datetime类型的值,也可以传入date的类型值,都一样会返回date类型的值。
3.convert_tz()函数
该函数能够将某个时区的datetime类型的值转化为另外一个时区的对应时间。在Oracle中,这个函数叫new_time()函数。
mysql> select convert_tz('2014-09-28','US/Eastern','UTC');
+---------------------------------------------+
| convert_tz('2014-09-28','US/Eastern','UTC') |
+---------------------------------------------+
| NULL |
+---------------------------------------------+
1 row in set (0.00 sec)
可以看到此时的返回值为null,是因为我的电脑上没有安装mysql的时区数据,就是说,系统现在不认识US/Eastern 这个地区,UTC地区也不认识。所以返回了一个空值。
4.dayname()函数
dayname()函数可以直接返回传入的日期那天是星期几。
mysql> select dayname('2008-09-18');
+-----------------------+
| dayname('2008-09-18') |
+-----------------------+
| Thursday |
+-----------------------+
1 row in set (0.00 sec)
比如上面的例子中,返回了2008年9月18日那天,是星期四。
除了dayname,还有monthname()函数,同理可以返回传入日期代表的月份的名称。比如下面的例子:
mysql> select monthname('2008-09-18');
+-------------------------+
| monthname('2008-09-18') |
+-------------------------+
| September |
+-------------------------+
1 row in set (0.00 sec)
很简单就能理解,不多说了。
5.extract()函数
该函数用于从日期或者时间中提取出某一部分内容。
mysql> select extract(hour_second from '2008-09-18 22:19:05');
+-------------------------------------------------+
| extract(hour_second from '2008-09-18 22:19:05') |
+-------------------------------------------------+
| 221905 |
+-------------------------------------------------+
1 row in set (0.02 sec)
mysql> select extract(year_month from '2008-09-18 22:19:05');
+------------------------------------------------+
| extract(year_month from '2008-09-18 22:19:05') |
+------------------------------------------------+
| 200809 |
+------------------------------------------------+
1 row in set (0.00 sec)
mysql> select extract(minute from '2008-09-18 22:19:05');
+--------------------------------------------+
| extract(minute from '2008-09-18 22:19:05') |
+--------------------------------------------+
| 19 |
+--------------------------------------------+
1 row in set (0.00 sec)
6.datediff()函数
该函数用于传入两个时间,求出他们之间的时间间隔。
比如
mysql> select datediff('2009-08-28','2009-08-24');
+-------------------------------------+
| datediff('2009-08-28','2009-08-24') |
+-------------------------------------+
| 4 |
+-------------------------------------+
1 row in set (0.00 sec)
可以看到该日期不包含最后一天,即24,25,26,27.不过,也有可能是25,26,27,28,总之是包含其中一天,不包含两天。
注意点:
datediff函数会忽略参数中的时间值,就算我把前一个日期设置为一天的最后一秒,后一个日期设置为一天的第一秒,也不会影响计算结果。
比如:
mysql> select datediff('2009-08-28 23:59:59','2009-08-24 00:00:01');
+-------------------------------------------------------+
| datediff('2009-08-28 23:59:59','2009-08-24 00:00:01') |
+-------------------------------------------------------+
| 4 |
+-------------------------------------------------------+
1 row in set (0.00 sec)
可以发现,该函数并没有关注时间,而是选择直接忽略了。
假如交换一下第一个参数和第二个参数的话,就会发现日期的值变成了负数。
MySQL的查询语句
1.select子句
query字句表
字句名称 使用目的
select 确定结果集中应该包含哪些列
from 指明所要提取数据的表,以及这些表示如何连接的
where 过滤掉不需要的数据
group by 用于对具有相同列值的行进行分组
having 过滤掉不需要的组
order by 按一个或多个列,对最后结构集中的行进行排序
从最简单的例子开始:
(1)选择一个 表中所有的数据
(2)选择其中的某一列或者多列
如果数据库限制了只能返回from字句后面各个表所包含的列,就显得相当乏味了。幸运的是,我们可以在select字句中加上一些“调料”,例如
1.字符,比如数字或字符串
2.表达式,比如transaction.amount*-1
3.调用内建函数,比如round(transaction.amount,2);
4.用户自定义的函数调用。
(4)展示对于刚才的Department表,在查询中添加一些调料,比如使用自定义的列名、字符、表达式、内建函数调用:
(5)调用更多的内建函数
可以看到三个内建函数分别返回不同的值,version代表的是数据库版本,user代表的是当前登录的用户名称,database代表的是现在正在使用的数据库的名称。
现在先在department表中先插入一个同名的公寓,插入语句和插入后结果如下:
(6)去除重复的行
如果此时只选择name列的话,会有四个值,但是有两个Loans重复的,我需要独一无二的,重复值不论出现多少次,我都只取一次,那么就需要使用到distinct关键字了。
注意此处使用的distinct,添加这个关键词对小数据量没啥影响,但是如果数据量大了之后,性能影响较大。原因是要产生无重复的结果集需要首先对数据排序,这对于大的结果集来说是相当耗时的。因此不要为了确保去除重复行而随意地使用distinct,而是应该先了解所使用的数据是否可能包含重复行,以减少对distinct的不必要的使用。
2.from子句
from子句定义了查询中所使用的表,以及连接这些表的方式。
当使用术语“表”时,往往想到的是实实在在存在的表格,就像上面的Department表。其实from子句后边不仅仅可以跟这种实体表(用create table创建),还可以从临时表(子查询返回的表)以及虚拟表(使用create view 子句所创建的视图)中返回数据。
(1)从子查询返回的表中查询数据
上图中会先执行括号中的select,然后会在内存中生成一个虚的表,这个虚的表叫d。然后再执行外层的select,从这个虚的表中选择相应的dept_id列和name列。
假如这个虚拟表在选择的时候给一个别名的话,外层也就只能通过这个别名来选择。比如:
可以看到,内部选择的时候,给dept_id出了个别名,叫做id,给name出了一个别名,叫做department_name。外层再选择的时候,就得通过这个新的别名去虚表d中选择了。
(2)从视图中返回数据
下面先定义一个查询Department表的视图,在Department表的基础上多了一列当前操作时候的时间,并将dept_id重命名为id,将name重命名为department_name。
然后从这个视图返回所有的数据:
可以发现,从视图选择数据成功了。
3. where子句
现在假如我有一个员工表,主要有4个字段,emp_id(员工id)、fname(姓)、lname(名字)、start_date(入职时间)。
让我们一起解决一些问题:
(1)如何获得员工id为99号的员工的所有信息?
(2)如何获得id 大于等于20,小于等于40的员工信息?(请用两种不同方式分别实现)
(3)如何获得11,45,99,124号员工的信息?(用两种方式实现)
(4)如何获得除了11,45,99,124号员工外,其他员工的信息?(用两种方式实现)
(5)如何获得入职时间在2011年10月1日前的,并且姓 ‘李’的所有员工?(用三种方式实现)
(6)如何获取所有emp_id的末尾为1的所有记录,比如emp_id为1,11,21,31.。。。101,121,。。。1001,1011,。。。。。(用三种方式来实现)
(7)如何获取101,111,121,131,141,151,161,171,181,191这几个员工的记录?(分别用通配和正则来实现)
上面的这些问题基本涵盖了where语句中的所有知识点,大家可以先试试看,按照题目的描述和括号中的条件来实现。
思考后,再查看下面的答案。
答案:
(1)select * from employee where emp_id = 99;
(2)select * from employee where emp_id between 20 and 40;
select * from employee where emp_id >=20 and emp_id <=40;
(3)select * from employee where emp_id = 11 or emp_id = 45 or emp_id = 99 or emp_id = 124;
select * from employee where emp_id in (11,45,99,124);
(4)select * from employee where emp_id !=11 and emp_id !=45 and emp_id != 99 and emp_id !=124;
select * from employee where emp_id not in (11,45,99,124);
(5)select * from employee where start_date<'2011-10-01' and fname = '李';
select * from (select * from employee where fname = '李' ) d where d.start_date < '2011-10-01';
select * from employee where emp_id in (select emp_id from employee where fname = '李' ) and start_date < '2011-10-01';
(6)select * from employee where emp_id like '%1';
select * from employee where emp_id regexp '.*1$';
select * from employee where right(emp_id,1) = 1;
(7)select * from employee where emp_id like '1_1;'
select * from employee where emp_id regexp '1.1';