《partner4java 讲述MySQL》之第一步:基本语法

(导读:本章学习的内容主要是对数据表和保存数据的基本管理语法;数据库非常重要,有时候大部分j2ee工程师也叫做数据库开发工程师,项目中无非就是对数据CURD操作;本章的学习无非就是大量语法的记忆,所以,建议自己动手


数据库:
从本质上讲,数据库系统只不过是一套对大量信息进行管理的高效办法而已。(高效主要体现在:缩短信息记录的录入时间;缩短信息记录的检索时间;灵活的信息检索顺序;灵活的输出格式;信息记录能同时被多名员工使用;信息记录的远程访问和电子传输。)

关系数据库:
关系(relational,即RDBMS里的R)表示RDBMS是DBMS中的一种,这种DBMS的专长就是把分别存放在两个数据库表里的信息联系(即相互匹配)起来,而这种联系是通过查找两个数据库表的共同元素来实现的。
RDBMS的威力在于它能够很方便地抽取出数据表里的数据并把它们与其他相关数据库的信息结合起来,为那些无法单独利用单个数据表找到答案的问题提供答案。

管理系统(management system,即RDBMS里的MS)指的是用来对数据进行插入、检索、修改、删除等操作的软件。

数据库管理语言 -- SQL:
结构化查询语言,一种对关系数据库中的数据进行定义和操作的句法,为大多数关系数据库管理系统所支持的工业标准。
(SQL是今天的标准化数据库语言,在各种主流的数据库系统上都能使用。)

数据库的组织结构:
数据库 -- 就是一个用来存储信息的仓库,它们构造简单,遵守一定的规则:
·数据库里的数据集合都存放在数据 表(table) 里;
·数据库表由数据 行(row) 数据列(column) 构成;
·一个 数据行 就是数据表里的一条记录(record);
·记录可以包含多个信息项,数据库里的每一个数据列都对应一个信息项。

MySQL的体系结构:
MySQL采用的是客户/服务器体系结构。因此,当你使用MySQL的时候,你实际是在使用两个程序。
第一个程序是MySQL服务器程序,只的mysqld程序,它允许在存放这你的数据库的机器上。
它负责在网络上监听并处理来自客户的服务请求,根据这些请求去访问数据库的内容,再把有关信息回传给客户。
另一个程序就是MySQL的客户程序,它们负责连接到数据库服务器,并通过向服务器发出查询命令来告知它们需要哪些信息。

(安装就不再阐述,请查阅相关资料)


如何建立和断开与服务器的链接:
mysql -h host_name - p -u user_name
cmd窗口(以下都是基于cmd):
C:\Users\Administrator>mysql -h localhost -p -u root
Enter password: ******

第一个单词mysql是固定的,-h\-p\-u分别表示地址、密码、用户
(如果MySQL服务器就运行在同一台机器上,就可以省略-h选项)

退出:quit


执行SQL语句:
连接上服务器之后,你就可以发出SQL命令让服务器执行了。
先敲入有关命令,再在命令的末尾加入结束符“;”,表示语句结束,回车。

执行查询:
mysql> select now();
+---------------------+
| now()               |
+---------------------+
| 2012-11-14 14:07:28 |
+---------------------+
1 row in set (0.08 sec)

可以以";"或“\g”最为结束符;

mysql> select now()\g
+---------------------+
| now()               |
+---------------------+
| 2012-11-14 14:09:48 |
+---------------------+
1 row in set (0.00 sec)

也可以使用“\G”,竖直排列显示结果,每行一个值:
mysql> select now(),user(),version()\G
*************************** 1. row ***************************
    now(): 2012-11-14 14:12:47
   user(): root@localhost
version(): 5.5.27
1 row in set (0.03 sec)

可以敲入\c来清除(即取消)输入:
mysql> select now(),user()\c

now(),user(),version()这些被成为函数,类似于Java里的方法吧。
函数名不区分大小写,在函数名与它后面的货号中间不允许出现空格。

也可以把SQL脚本放入一个sql扩展名的文件中执行:
mysql> source  C:\Users\Administrator\Desktop\hello.sql
+---------------------+
| now()               |
+---------------------+
| 2012-11-14 14:21:07 |
+---------------------+
1 row in set (0.00 sec)
(这个文件的名字可以随便起。一般给它们加上一个“.sql”后缀以表明这个文件里存放的是SQL语句)


使用数据库的一般步骤:
(1)创建(初始化)一个数据库;
(2)在数据库里创建数据表;
(3)对数据表里的数据进行插入、检索、修改、删除等操作。



第一步:创建(初始化)一个数据库


查看现有数据库:
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| ibatis_test        |
| jforum             |
| mysql              |
| notbook            |
| performance_schema |
| spring-security    |
| spring_security    |
| test               |
+--------------------+
9 rows in set (0.00 sec)


创建数据库:
先用MySQL连接上服务器(这一步后面就不再强调了),在用一条CREATE DATABASE语句给出新建数据库的名字。
mysql> create database hello_world;
Query OK, 1 row affected (0.06 sec)
(只有创建了数据库,才能创建表,因为表是基于数据库进行管理的)


创建数据库后并不能直接使用,需要选择你要使用的数据库
mysql> use hello_world;
Database changed
(相当于选定一个当前操作的数据库)


查询当前选定的数据库:
mysql> select database();
+-------------+
| database()  |
+-------------+
| hello_world |
+-------------+


连接数据库时就指定默认数据库:
在连接后面机上数据库名字即可
C:\Users\Administrator>mysql -h localhost -p -u root hello_world
Enter password: ******


第二步:在数据库里创建数据表



创建数据表:
(数据表的场景就是保存了用户信息)
mysql> CREATE TABLE `user` (
    ->   `id` int(11) NOT NULL AUTO_INCREMENT,
    ->   `username` varchar(20) NOT NULL,
    ->   `birth` date DEFAULT NULL,
    ->   `age` int(11) DEFAULT NULL,
    ->   PRIMARY KEY (`id`)
    -> );


create table语句结构由:
数据表名字(user)、数据列的名字(username、birth等)、数据类型(varchar、date、int)和一些属性组成(NOT NULL等)。
前面部分“CREATE TABLE `user` ”为固定格式,`user`为指定表名;
所有数据列的定义在中括号内,每一个数据列用逗号(“,”)分隔;
每列数据列由名字、数据类型和一些属性构成(三者的顺序是固定的)。
(无论是数据库的名字、表的名字还是数据列的名字都是我们根绝场景自定义的)

user表用到了三种数据类型:varchar(n)、date和int(n)。

文本:
varchar[(n)]:最大长度为 n 个字节的可变长度且非 Unicode 的字符数据。n 必须是一个介于 1 和 8,000 之间的数值。存储大小为输入数据的字节的实际长度,而不是 n 个字节。所输入的数据字符长度可以为零。
如果存放长度比较一致的数据,可使用CHAR(n)。
char[(n)]:最大长度为 n 个字节的固定长度且非 Unicode 的字符数据。n 必须是一个介于 1 和 8,000 之间的数值。存储大小为 n 个字节。
当存放的字符串超过上面两种允许最大长度时,可使用TEXT。
text:服务器代码页中的可变长度非 Unicode 数据的最大长度为 231-1 (2,147,483,647) 个字符。当服务器代码页使用双字节字符时,存储量仍是 2,147,483,647 字节。存储大小可能小于 2,147,483,647 字节(取决于字符串)。

日期:
DATE:用来保存日期值。MySQL要求日期被表示为“CCYY-MM-DD”格式,其中CC、YY、MM、DD分别代表世纪、年份、月份和日期。
DATETIME:可以存放时分秒。显示宽度固定在19字符,格式为YYYY-MM-DD HH:MM:SS。如:2012/12/11 23:59:59
TIMESTAMP:TIMESTAMP列的显示格式与datetime列相同。
datetime以"YYYY-MM-DDHH:MM:SS"格式检索和显示datetime值。支持的范围为"1000-01-01 00:00:00"到"9999-12-31 23:59:59"
TIMESTAMP值不能早于1970或晚于2037。
TIME:保存时间。HH:MM:SS

数字:
bigint:从 -2^63 (-9223372036854775808) 到 2^63-1 (9223372036854775807) 的整型数据(所有数字)。存储大小为 8 个字节。
int:从 -2^31 (-2,147,483,648) 到 2^31 - 1 (2,147,483,647) 的整型数据(所有数字)。存储大小为 4 个字节。int 的 SQL-92 同义字为 integer。
smallint:从 -2^15 (-32,768) 到 2^15 - 1 (32,767) 的整型数据。存储大小为 2 个字节。
tinyint:从 0 到 255 的整型数据。存储大小为 1 字节。

NOT NULL:用于指定当前数据列存放的数据不能为NULL。(除非有为空的需求,不然都应该设置为NOT NULL)

AUTO_INCREMENT:这是MySQL里一个特殊的属性,它表示数据列里存放的是序列编号。但是这个编号一般不需要我们手工维护,当插入数据时,会自动为本行数据添加本数据列。添加规则一般为递增(+1)。

PRIMARY KEY (`id`):这个不属于数据列,是指定了本表的主键。一般为自动增长并且是非空 int类型的,主要用来保证数据行的唯一性和加快查询速度。


可以用以下方式查看表结构


mysql> describe user;
...
mysql> desc user;
...
mysql> explain user;
...
mysql> show columns from user;
...
mysql> show fields from user;
+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| id       | int(11)     | NO   | PRI | NULL    | auto_increment |
| username | varchar(20) | NO   |     | NULL    |                |
| birth    | date        | YES  |     | NULL    |                |
| age      | int(11)     | YES  |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+


查看本库有多少表:
mysql> show tables;
+-----------------------+
| Tables_in_hello_world |
+-----------------------+
| user                  |
+-----------------------+


删除表:
mysql> drop table if exists president;


在表中添加一列:
mysql> alter table user add column birth date;


第三步:对数据表里的数据进行插入、检索、修改、删除等操作


1、插入:利用insert语句添加数据


我们要学习三种插入方式


(在学习插入之前,你可以先记住一个查询的基本语法:select * from user;用于我们后面插入的结果查看;“select * from ”为固定格式,后面跟我们表名。)


(1)你可以一次性地列出全部数据列的值:
INSERT INTO table_name VALUES (value1,value2,...)
例如:
mysql> insert into user values (1,'hello','1988-02-01',24);
使用这个语法的时候,关键字values后面的括号里必须为数据表的全体数据列准备好对应的值,这些值的先后顺序也必须与各数据列在数据表里的存储先后顺序保持一致。
MySQL里的字符串或日期值必须放在单引号或双引号里才能被引用,放在单引号里更标准。

在一个AUTO_INCREMENT数据列里插入一个标识“无数据”的NULL值将使MySQL为这个数据列自动申城下一个序号:
mysql> insert into user values (NULL,'world','1988-02-01',24);

在MySQL中,可以用一条insert语句完成多条数据插入:
INSERT INTO table_name values(...),(....),...;
mysql> insert into user values (NULL,'world1','1988-02-01',24),(NULL,'world2','1988-02-01',24);
以中括号来标明没行数据。这样不仅省了代码量,而且能够提高执行效率。

(2)还可以直接对数据列进行赋值,先给出数据列的名字,再列出它的值:
INSERT INTO table_name (column_name1,column_name2,...) VALUES (value1,value2,...);
例如:
mysql> insert user (username,age) values ('hello1',32);
(没有指定的数据列,如果允许为空,会自动给予NULL。若存在没有指定的不可为空的字段(且表定义时没指定默认值),会报错)

mysql> insert user (age) values (21);
ERROR 1364 (HY000): Field 'username' doesn't have a default value

这种形式也可以一次插入多条数据。

(3)还可以包含col_name = value(而非values()列表)的set子句对数据列赋值:
INSERT INTO table_name SET column_name1 = value1,column_name2 = value2,...;
例如:
mysql> insert user set username = 'helloworld',age = 23;
若SET中没有指定,规则如VALUES。


2、检索信息:

我们将要学习检索的各种组合:
主要学习步骤为基本检索、条件检索、对检索排序、对检索结果指定数量、求值和命名、模糊查询、统计信息、关联查询


select语句允许以你需要的方式检索和显示数据表里的信息。
语法:
SELECT
从数据库中检索行,并允许从一个或多个表中选择一个或多个行或列。虽然 SELECT 语句的完整语法较复杂,但是其主要的子句可归纳如下:
SELECT select_list
[ INTO new_table ] 
FROM table_source 
[ WHERE search_condition ] 
[ GROUP BY group_by_expression ] 
[ HAVING search_condition ] 
[ ORDER BY order_expression [ ASC | DESC ] ] 


我们后面很大一部分内容是学习这个语法(中括号为可选部分)。


(1)基本检索:

把整个数据表的内容都显示出来:
mysql> select * from user;
+----+------------+------------+------+
| id | username   | birth      | age  |
+----+------------+------------+------+
|  1 | hello      | 1988-02-01 |   24 |
|  2 | world      | 1988-02-01 |   24 |
|  3 | world1     | 1988-02-01 |   24 |
|  4 | world2     | 1988-02-01 |   24 |
|  5 | hello1     | NULL       |   32 |
|  6 | helloworld | NULL       |   23 |
+----+------------+------------+------+
select -- 表示我们是一个查询语句;
* -- 表示我们查询所有字段,也可以以逗号分隔指定具体需要展示的数据列名称,如:mysql> select username,birth,age from user;
from -- 后跟表名。

from子句一般必不可少,但是如果你不需要给出数据表的名字,就不必把它写出来:
mysql> select 1+1,'hello world',version();
+-----+-------------+-----------+
| 1+1 | hello world | version() |
+-----+-------------+-----------+
|   2 | hello world | 5.5.27    |
+-----+-------------+-----------+
1 row in set (0.02 sec)


注意:
数据库和数据库的名字有可能会区分大小写,这取决于服务器主机上所使用的文件系统,但是也可以指定配置是否区分。


(2)条件检索

指定检索条件:
要想让select语句只把满足特定条件的记录检索出来,就必须给它加上一个where子句来设定数据行的检索条件。
(使用where,后面跟查询条件。我们这里的查询条件为一个相等判断。)
mysql> select * from user where age = 24;
+----+----------+------------+------+
| id | username | birth      | age  |
+----+----------+------------+------+
|  1 | hello    | 1988-02-01 |   24 |
|  2 | world    | 1988-02-01 |   24 |
|  3 | world1   | 1988-02-01 |   24 |
|  4 | world2   | 1988-02-01 |   24 |
+----+----------+------------+------+

也可以针对字符串进行查找。字符串的比较操作通常不区分字母的大小写:
mysql> select  * from user where username = 'hello';
+----+----------+------------+------+
| id | username | birth      | age  |
+----+----------+------------+------+
|  1 | hello    | 1988-02-01 |   24 |
+----+----------+------------+------+

还可以针对日期进行查找:
mysql> select * from user where birth > '1987-11-11';
+----+----------+------------+------+
| id | username | birth      | age  |
+----+----------+------------+------+
|  1 | hello    | 1988-02-01 |   24 |
|  2 | world    | 1988-02-01 |   24 |

甚至还能针对不同类型的值的组合进行查找:
mysql> select * from user where birth > '2012-11-11' and username = 'sas';
+----------+----------+------------+
| username | password | birth      |
+----------+----------+------------+
| sas      |     2342 | 2012-11-15 |
| sas      |     2342 | 2012-11-15 |
| sas      |     2342 | 2012-11-15 |
+----------+----------+------------+
3 rows in set (0.00 sec)

where子句里的表达式允许使用算术运算符、比较运算符和逻辑运算符,还允许使用括号。
你可使用常数、数据表的数据列和函数调用进行运算。
《partner4java 讲述MySQL》之第一步:基本语法_第1张图片

NULL值:
NULL是一个很特殊的值,它的含义是“无数据”或“未知数据”,所以不能用它与“有数据”的值进行运算或者比较。
mysql> select NULL < 0,NULL = 0,NULL <> 0,NULL >0;
+----------+----------+-----------+---------+
| NULL < 0 | NULL = 0 | NULL <> 0 | NULL >0 |
+----------+----------+-----------+---------+
|     NULL |     NULL |      NULL |    NULL |
+----------+----------+-----------+---------+
1 row in set (0.19 sec)

事实上,你甚至不能拿NULL值与它本身进行比较:
mysql> select NULL = NULL,NULL <> null;
+-------------+--------------+
| NULL = NULL | NULL <> null |
+-------------+--------------+
|        NULL |         NULL |
+-------------+--------------+
1 row in set (0.00 sec)

如果需要对NULL值进行查找,就必须使用一种特殊的语法。你不能使用=、<>或者!=来测试它们相等还是不相等,你必须使用IS NULL 或 IS NOT NULL来判断。
mysql> select * from user where age > 20 and birth = null;
Empty set (0.03 sec)

mysql> select * from user where age > 20 and birth is not null;
+----+----------+------------+------+
| id | username | birth      | age  |
+----+----------+------------+------+
|  1 | hello    | 1988-02-01 |   24 |
|  2 | world    | 1988-02-01 |   24 |
|  3 | world1   | 1988-02-01 |   24 |
|  4 | world2   | 1988-02-01 |   24 |
+----+----------+------------+------+

(3)对检索排序


如何对查询结果进行排序:


从服务器返回的数据行的先后顺序没有任何保证,除非你事先设定。
如果想让查询结果按你希望的先后顺序显示,就必须给查询命令增加一条ORDER BY 子句:
mysql> select * from user where birth is not null order by birth ;
+----------+----------+------------+
| username | password | birth      |
+----------+----------+------------+
| ee       |   143123 | 2012-10-01 |
| hello    |       12 | 2012-11-01 |
| world    |     2365 | 2012-11-10 |
+----------+----------+------------+
3 rows in set (0.08 sec)


order by子句的默认排序方式是升序排列。
在order by子句的数据列的名字的后面加上关键字asc 或 desc,就能使查询结果中的数据记录按指定数据列的升序或者降序排列。
mysql> select * from user where birth is not null order by birth desc;
+----------+----------+------------+
| username | password | birth      |
+----------+----------+------------+
| world    |     2365 | 2012-11-10 |
| hello    |       12 | 2012-11-01 |
| ee       |   143123 | 2012-10-01 |
+----------+----------+------------+
3 rows in set (0.00 sec)


可以对查询结果按多个数据列进行排序,而每一个数据列又都可以互不影响的分别按升序或降序进行排列。(规则是先按第一个规则进行排列,在第一个规则不被影响的前提下,再对进行第二个规则的排序)
mysql> select * from user where birth is not null order by birth desc,password asc;
+----------+----------+------------+
| username | password | birth      |
+----------+----------+------------+
| asdfad   |       22 | 2012-11-10 |
| world    |     2365 | 2012-11-10 |
| hello    |       12 | 2012-11-01 |
| ee       |   143123 | 2012-10-01 |
+----------+----------+------------+
4 rows in set (0.00 sec)


对于包含NULL值的数据行,如果设定按升序排列,它们将出现在查询结果的开头;如果设定按降序排序,它们将出现在查询结果的末尾。
mysql> select * from user order by birth desc,password asc;
+-----------+----------+------------+
| username  | password | birth      |
+-----------+----------+------------+
| asdfad    |       22 | 2012-11-10 |
| world     |     2365 | 2012-11-10 |
| hello     |       12 | 2012-11-01 |
| ee        |   143123 | 2012-10-01 |
| asdfadsfa |     NULL | NULL       |
| sad       |       22 | NULL       |
+-----------+----------+------------+
6 rows in set (0.00 sec)


如果你想让NULL值必须出现在查询结果的末尾,就必须额外添加一个排序数据列以区分NULL值和非NULL值。
mysql> select * from user order by birth desc,if(password is null,1,0), password asc;
+-----------+----------+------------+
| username  | password | birth      |
+-----------+----------+------------+
| asdfad    |       22 | 2012-11-10 |
| world     |     2365 | 2012-11-10 |
| hello     |       12 | 2012-11-01 |
| ee        |   143123 | 2012-10-01 |
| sad       |       22 | NULL       |
| asdsd     |    21121 | NULL       |
| asdfadsfa |     NULL | NULL       |
+-----------+----------+------------+
7 rows in set (0.00 sec)

if()函数的作用是对紧随其后的表达式(第一参数)进行求值,再根据表达式求值结果的真假返回它的第二个参数或第三个参数。


(4)对检索结果指定数量


如何限制查询结果中的数据行个数:
查询结果往往由很多个数据行构成,如果你只想看到其中的一小部分,可以给查询命令增加一条LIMIT子句。
MySQL允许给查询结果中的数据行个数设置一个上限,如前n个数据行,如果查询结果里的数据行超过了这个数字,就只显示前n个数据行。
mysql> select * from user limit 2;
+----------+----------+------------+
| username | password | birth      |
+----------+----------+------------+
| world    |     2365 | 2012-11-10 |
| hello    |       12 | 2012-11-01 |
+----------+----------+------------+
2 rows in set (0.00 sec)


limit还允许从查询结果的中间部分抽出一部分数据记录。
此时必须设置两个值,第一个值给出了要在查询结果的开头部分跳过的数据记录个数,第二个值则是需要返回的数据记录的个数。
select * from user limit 2,10;


如果想随机查询几条数据,可以联合使用LIMIT和ORDER BY RAND()子句:
mysql> select * from user order by rand() limit 2
+----------+----------+------------+
| username | password | birth      |
+----------+----------+------------+
| asdfad   |       22 | 2012-11-10 |
| world    |     2365 | 2012-11-10 |
+----------+----------+------------+
2 rows in set (0.14 sec)


(5)求值和命名

如何对输出的列进行求值和命名:
MySQL还允许把表达式的计算结果当做输出列的值,而不引用数据表。
mysql> select 18,format(sqrt(23+123),2);
+----+------------------------+
| 18 | format(sqrt(23+123),2) |
+----+------------------------+
| 18 | 12.08                  |
+----+------------------------+
1 row in set (0.08 sec)


数据表里的数据列名也可以用在表达式里:
mysql> select concat(username,' ',password) from user;
+-------------------------------+
| concat(username,' ',password) |
+-------------------------------+
| world 2365                    |
| hello 12                      |


可以利用as name短语给输出列另外取一个名字,我们把它成为输出列的别名(alias)。
mysql> select concat(username ,' ',password) as str from user;
+-------------+
| str         |
+-------------+
| world 2365  |
| hello 12    |

如果输出列的别名里包含空格符,就必须把它放到一组引号里:
mysql> select concat(username ,' ',password) as 'user content' from user;
+--------------+
| user content |
+--------------+
| world 2365   |
| hello 12     |
| ee 143123    |

as也可以省略:
mysql> select concat(username ,' ',password)  'user content' from user;
+--------------+
| user content |
+--------------+
| world 2365   |
| hello 12     |


与日期有关的问题:
在与MySQL里的日期打交道的时候,千万要记住年份总是出现在最前面,如"2012-10-10"。
比较:
mysql> select * from user where birth = '2012/11/10';
+----------+----------+------------+
| username | password | birth      |
+----------+----------+------------+
| world    |     2365 | 2012-11-10 |
| asdfad   |       22 | 2012-11-10 |
+----------+----------+------------+
2 rows in set (0.00 sec)


mysql> select * from user where birth <= '2012/11/10' and birth > '2012-01-01';
+----------+----------+------------+
| username | password | birth      |
+----------+----------+------------+
| world    |     2365 | 2012-11-10 |
| hello    |       12 | 2012-11-01 |
| ee       |   143123 | 2012-10-01 |
| asdfad   |       22 | 2012-11-10 |
+----------+----------+------------+
4 rows in set (0.00 sec)

(你可能发现上面两个分隔符都能正常工作)

日期中的年、月、日3部分可以用函数YEAR()、MONTH()、DAYOFMONTH()分别分离出来:

"今日出生的人":
mysql> select * from user where month(birth) = month(curdate()) and dayofmonth(birth) = dayofmonth(curdate());

如果你想知道两个日期值之间的时间间隔,可以使用TIMESTAMPDIFF()函数,第一个参数接受一个指定计算结果单位的参数:
mysql> select timestampdiff(DAY,birth,now()) from user;
+--------------------------------+
| timestampdiff(DAY,birth,now()) |
+--------------------------------+
|                              6 |

日期值的加减用DATE_ADD()或DATE_SUB()函数来完成,这两个函数的输入参数是一个日期值和一个时间间隔值,返回结果则是一个新日期值:
mysql> select date_add(now(), interval 500 day);
+-----------------------------------+
| date_add(now(), interval 500 day) |
+-----------------------------------+
| 2014-03-31 14:20:12               |
+-----------------------------------+
1 row in set (0.04 sec)


(6)模糊查询

模型匹配:
MySQL支持模型匹配操作,这使我们能够在没有给出精确比较值的情况下把有关的数据行查出来。
模型匹配需要使用特殊的操作符(LIKE 和 NOT LIKE),还需要你提供一个通配字符的字符串。“_”只能匹配一个字符,"%"能匹配任何一个字符序列(包括空序列在内)。
mysql> select * from user where username like 'a%';
+-----------+----------+------------+
| username  | password | birth      |
+-----------+----------+------------+
| asdfad    |       22 | 2012-11-10 |
| asdfadsfa |     NULL | NULL       |
| asdsd     |    21121 | NULL       |
+-----------+----------+------------+
3 rows in set (0.04 sec)

把由5个字母构成的名字找出来:
mysql> select * from user where username like '_____';
+----------+----------+------------+
| username | password | birth      |
+----------+----------+------------+
| world    |     2365 | 2012-11-10 |
| hello    |       12 | 2012-11-01 |
| asdsd    |    21121 | NULL       |
+----------+----------+------------+
3 rows in set (0.00 sec)

(7)统计信息


MySQL最有用的功能之一是它能够依据大量未经加工的数据生成多种统计汇总信息。


找出一组数据里到底有多少种不同的取值,可使用关键字DISTINCT:
DISTINCT跟在select和from之间,后面指定要统计的数据列名称。
mysql> select distinct birth from user;
+------------+
| birth      |
+------------+
| 2012-11-10 |
| 2012-11-01 |
| 2012-10-01 |
(当你select中出现多个字段时,往往结果就不会像你想象的那样输出;只能出现一次distinct统计关键字。)


count(*)的统计结果是被选中的数据行的总数,而COUNT(数据列名称)值则只统计全体非NULL的值的个数:
mysql> select count(*),count(username),count(birth) from user;
+----------+-----------------+--------------+
| count(*) | count(username) | count(birth) |
+----------+-----------------+--------------+
|        7 |               7 |            4 |
+----------+-----------------+--------------+
1 row in set (0.03 sec)
(可以使用多一个count;但是如果你的select出现了不为count的无修饰字段名,返回结果也不是你所想要的。)


count()和DISTINCT联合起来可以统计出查询结果里到底有多少种不同的非NULL值:
mysql> select count(distinct birth) from user
+-----------------------+
| count(distinct birth) |
+-----------------------+
|                     3 |


MySQL可以使用GROUP BY子句,把某数据列里的不同值分别出现过多少次的情况统计出来:
mysql> select count(*),birth from user group by birth ;
+----------+------------+
| count(*) | birth      |
+----------+------------+
|        3 | NULL       |
|        1 | 2012-10-01 |
|        1 | 2012-11-01 |
|        2 | 2012-11-10 |
+----------+------------+
4 rows in set (0.05 sec)


COUNT()函数还可以和ORDER BY 和 LIMIT 子句联合使用:
mysql> select count(*) cou,birth from user group by birth order by cou desc limit 2 ;
+-----+------------+
| cou | birth      |
+-----+------------+
|   3 | NULL       |
|   2 | 2012-11-10 |
+-----+------------+

如果不想利用LIMIT子句来限制查询结果中的个数,而只是想把与某个特定COUNT()值相对应的记录找出来,就需要使用HAVING子句。
HAVING子句和WHERE子句的相似之处是它们都是用来设定查询条件的,输出的行必须符合这些查询条件。
mysql> select * from user having birth is not null;
+----------+----------+------------+
| username | password | birth      |
+----------+----------+------------+
| world    |     2365 | 2012-11-10 |
| hello    |       12 | 2012-11-01 |
| ee       |   143123 | 2012-10-01 |
| asdfad   |       22 | 2012-11-10 |
+----------+----------+------------+
4 rows in set (0.04 sec)

HAVING子句与WHERE子句的不同之处是COUNT()之类的汇总函数的计算结果允许在HAVING子句里出现,不允许在where中出现:
mysql> select count(*) cou,birth from user group by birth having cou > 1;
+-----+------------+
| cou | birth      |
+-----+------------+
|   3 | NULL       |
|   2 | 2012-11-10 |
+-----+------------+
2 rows in set (0.00 sec)

除COUNT()以外,MySQL还有其他一些汇总函数。函数MIN()、MAX()、SUM()和AVG()能够得出某个数据列里的最小值、最大值、总和平均值。

(8)关联查询


到目前为止,我们查询出来的信息都来自一个数据表。
MySQL的能力其实远远不止如此。
前面说过RDBMS(关系型数据库)的威力在于它们能把一种东西与另一种东西关联起来,即能把来自多个数据表的信息结合在一起以解答单个数据表不足以解答的问题。


从多个数据表选取信息时,有一种方法叫做联结(join)。联结操作是通过把两个(或多个)数据表里的同类数据进行匹配而完成的。另一种方法就是将select语句嵌套在另一个select语句里。


嵌套查询:
只不过我们把一个查询的结果作为另一个查询的判断值。
mysql> select * from user where birth = (select max(birth) from user);
+----------+----------+------------+
| username | password | birth      |
+----------+----------+------------+
| world    |     2365 | 2012-11-10 |
| asdfad   |       22 | 2012-11-10 |



联结查询:
我们创建两张表:
老师表和学生表,学生表中多添加了一个班主任id字段,用于维护自己当前班主任。
CREATE TABLE `teacher` (
  `teacher_id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`teacher_id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `student` (
  `student_id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `head_teacher_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`student_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO `teacher` (`teacher_id`, `name`) VALUES 
  (1, 'Tom'),
  (2, 'Bom'),
  (3, 'Ting');
  
INSERT INTO `student` (`student_id`, `name`, `head_teacher_id`) VALUES 
  (1, 'King', 1),
  (2, 'Bai', 1),
  (3, 'Hum', 2),
  (4, 'Ling', NULL);


相等联接或内联接:
select column1,column2,... from table_name1 inner join table_name2 on table_name1.col_1 = table_name2.col_1;
mysql> select * from student inner join teacher on student.head_teacher_id = teacher.teacher_id;
+------------+------+-----------------+------------+------+
| student_id | name | head_teacher_id | teacher_id | name |
+------------+------+-----------------+------------+------+
|          1 | King |               1 |          1 | Tom  |
|          2 | Bai  |               1 |          1 | Tom  |
|          3 | Hum  |               2 |          2 | Bom  |
+------------+------+-----------------+------------+------+
与前面的不同:
1、在FROM子句里,我们列举了多个数据表的名字,因为我们要从多个数据表里检索信息,使用“inner join”前后添加了关联表名:
from orders inner join commodity
2、在ON子句里,我们给出了两个数据表的连接条件(也就是用于匹配的同类数据):
on orders.order_id = commodity.order_id


不借助inner join我们可以这样:
mysql> select * from student,teacher where student.head_teacher_id = teacher.teacher_id;


可以看到内联接只会返回匹配的数据:
内连接: 合并具有同一列的两个以上的表的行, 结果集中不包含一个表与另一个表不匹配的行。
外连接: 两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的行 ,这种连接称为左(或右) 外联接。
全连接:两个表在连接过程中除了返回满足连接条件的行以外还返回两个表中不满足条件的行。


LEFT JOIN将使MySQL为连接操作中的第一个数据表里的每一个中选数据行生成一个输出行。
还有RIGHT JOIN,是对第二个数据表里的每一个中选数据行生成一个输出行。


mysql中没有全连接,可以使用UNION:
mysql> select * from orders right join commodity on orders.order_id = commodity.order_id union select * from orders left join commodity on orders.order_id = commodity.order_id;


3、修改、删除

有时候,你需要修改或删除现有的数据行,这就需要用到DELETE 和 UPDATE 语句。
删除:
DELETE FROM table_name WHERE which rows to delete;


WHERE子句是可选的,它指定哪些数据行会被删除;如果没有WHERE子句,数据表里的全部行将被删除掉。
例如:
如果想删除user表里名字为“hello”的数据
mysql> delete from user where username = 'hello';
(如果不清楚某条DELETE语句到底会删掉哪些数据行,最好先把这条语句的WHERE子句放到一条SELECT语句里,看这条SELECT语句能查出哪些数据 -- 你如果用JDBC这么做不是很现实)

修改:
如果想修改现有行,就需要使用UPDATE语句,基本格式:
UPDATE table_name
set which columns to change
where which rows to update;

where子句也是可选的,如果没有指出where子句,就表示数据表里的每一条记录都需要修改。
mysql> update user set age = 33 where id = 2;

你可能感兴趣的:(《partner4java 讲述MySQL》之第一步:基本语法)