mysql day01課堂筆記
1、什么是數據庫?什么是數據庫管理系統?什么是SQL?他們之間的關系是什么?
數據庫:
英文單詞DataBase,簡稱DB。按照一定格式存儲數據的一些文件的組合。
顧名思義:存儲數據的倉庫,實際上就是一堆文件。這些文件中存儲了
具有特定格式的數據。
數據庫管理系統:
DataBaseManagement,簡稱DBMS。
數據庫管理系統是專門用來管理數據庫中數據的,數據庫管理系統可以
對數據庫當中的數據進行增刪改查。
常見的數據庫管理系統:
MySQL、Oracle、MS SqlServer、DB2、sybase等....
SQL:結構化查詢語言
程序員需要學習SQL語句,程序員通過編寫SQL語句,然后DBMS負責執行SQL
語句,最終來完成數據庫中數據的增刪改查操作。
SQL是一套標准,程序員主要學習的就是SQL語句,這個SQL在mysql中可以使用,
同時在Oracle中也可以使用,在DB2中也可以使用。
三者之間的關系?
DBMS--執行--> SQL --操作--> DB
先安裝數據庫管理系統MySQL,然后學習SQL語句怎么寫,編寫SQL語句之后,DBMS
對SQL語句進行執行,最終來完成數據庫的數據管理。
2、安裝MySQL數據庫管理系統。
第一步:先安裝,選擇“經典版”
第二步:需要進行MySQL數據庫實例配置。
注意:一路下一步就行了!!!!!
需要注意的事項?
端口號:
端口號port是任何一個軟件/應用都會有的,端口號是應用的唯一代表。
端口號通常和IP地址在一塊,IP地址用來定位計算機的,端口號port
是用來定位計算機上某個服務的/某個應用的!
在同一台計算機上,端口號不能重復。具有唯一性。
mysql數據庫啟動的時候,這個服務占有的默認端口號是3306
這是大家都知道的事兒。記住。
字符編碼方式?
設置mysql數據庫的字符編碼方式為 UTF8
一定要注意:先選中第3個單選按鈕,然后再選擇utf8字符集。
服務名稱?
默認是:MySQL
不用改。
選擇配置環境變量path:
如果沒有選擇怎么辦?你可以手動配置
path=其它路徑;C:\Program Files (x86)\MySQL\MySQL Server 5.5\bin
mysql超級管理員用戶名不能改,一定是:root
你需要設置mysql數據庫超級管理員的密碼。
我們設置為123456
設置密碼的同時,可以激活root賬戶遠程訪問。
激活:表示root賬號可以在外地登錄。
不激活:表示root賬號只能在本機上使用。
我這里選擇激活了!
3、MySQL數據庫的完美卸載!
第一步:雙擊安裝包進行卸載刪除。
第二步:刪除目錄:
把C:\ProgramData下面的MySQL目錄干掉。
把C:\Program Files (x86)下面的MySQL目錄干掉。
這樣就卸載結束了!
4、看一下計算機上的服務,找一找MySQL的服務在哪里?
計算機-->右鍵-->管理-->服務和應用程序-->服務-->找mysql服務
MySQL的服務,默認是“啟動”的狀態,只有啟動了mysql才能用。
默認情況下是“自動”啟動,自動啟動表示下一次重啟操作系統的時候
自動啟動該服務。
可以在服務上點擊右鍵:
啟動
重啟服務
停止服務
...
還可以改變服務的默認配置:
服務上點擊右鍵,屬性,然后可以選擇啟動方式:
自動(延遲啟動)
自動
手動
禁用
5、在windows操作系統當中,怎么使用命令來啟動和關閉mysql服務呢?
語法:
net stop 服務名稱;
net start 服務名稱;
其它服務的啟停都可以采用以上的命令。
6、mysql安裝了,服務啟動了,怎么使用客戶端登錄mysql數據庫呢?
使用bin目錄下的mysql.exe命令來連接mysql數據庫服務器
本地登錄(顯示編寫密碼的形式):
C:\Users\Administrator>mysql -uroot -p123456
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.5.36 MySQL Community Server (GPL)
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
本地登錄(隱藏密碼的形式):
C:\Users\Administrator>mysql -uroot -p
Enter password: ******
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.5.36 MySQL Community Server (GPL)
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
7、mysql常用命令:
退出mysql :exit
查看mysql中有哪些數據庫?
show databases;
注意:以分號結尾,分號是英文的分號。
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
mysql默認自帶了4個數據庫。
怎么選擇使用某個數據庫呢?
mysql> use test;
Database changed
表示正在使用一個名字叫做test的數據庫。
怎么創建數據庫呢?
mysql> create database bjpowernode;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| bjpowernode |
| mysql |
| performance_schema |
| test |
+--------------------+
查看某個數據庫下有哪些表?
mysql> show tables;
注意:以上的命令不區分大小寫,都行。
查看mysql數據庫的版本號:
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.5.36 |
+-----------+
查看當前使用的是哪個數據庫?
mysql> select database();
+-------------+
| database() |
+-------------+
| bjpowernode |
+-------------+
mysql> show
-> databases
-> ;
+--------------------+
| Database |
+--------------------+
| information_schema |
| bjpowernode |
| mysql |
| performance_schema |
| test |
+--------------------+
注意:mysql是不見“;”不執行,“;”表示結束!
mysql> show
->
->
->
->
->
->
->
->
-> \c
mysql>
\c用來終止一條命令的輸入。
8、數據庫當中最基本的單元是表:table
什么是表table?為什么用表來存儲數據呢?
姓名 性別 年齡(列:字段)
---------------------------
張三 男 20 ------->行(記錄)
李四 女 21 ------->行(記錄)
王五 男 22 ------->行(記錄)
數據庫當中是以表格的形式表示數據的。
因為表比較直觀。
任何一張表都有行和列:
行(row):被稱為數據/記錄。
列(column):被稱為字段。
姓名字段、性別字段、年齡字段。
了解一下:
每一個字段都有:字段名、數據類型、約束等屬性。
字段名可以理解,是一個普通的名字,見名知意就行。
數據類型:字符串,數字,日期等,后期講。
約束:約束也有很多,其中一個叫做唯一性約束,
這種約束添加之后,該字段中的數據不能重復。
9、關於SQL語句的分類?
SQL語句有很多,最好進行分門別類,這樣更容易記憶。
分為:
DQL:
數據查詢語言(凡是帶有select關鍵字的都是查詢語句)
select...
DML:
數據操作語言(凡是對表當中的數據進行增刪改的都是DML)
insert delete update
insert 增
delete 刪
update 改
這個主要是操作表中的數據data。
DDL:
數據定義語言
凡是帶有create、drop、alter的都是DDL。
DDL主要操作的是表的結構。不是表中的數據。
create:新建,等同於增
drop:刪除
alter:修改
這個增刪改和DML不同,這個主要是對表結構進行操作。
TCL:
不是王牌電視。
是事務控制語言
包括:
事務提交:commit;
事務回滾:rollback;
DCL:
是數據控制語言。
例如:授權grant、撤銷權限revoke....
10、導入一下提前准備好的數據:
bjpowernode.sql 這個文件中是我提前為大家練習准備的數據庫表。
怎么將sql文件中的數據導入呢?
mysql> source D:\course\03-MySQL\document\bjpowernode.sql
注意:路徑中不要有中文!!!!
11、關於導入的這幾張表?
mysql> show tables;
+-----------------------+
| Tables_in_bjpowernode |
+-----------------------+
| dept |
| emp |
| salgrade |
+-----------------------+
dept是部門表
emp是員工表
salgrade 是工資等級表
怎么查看表中的數據呢?
select * from 表名; //統一執行這個SQL語句。
mysql> select * from emp; // 從emp表查詢所有數據。
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |
| 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 |
+-------+--------+-----------+------+------------+---------+---------+--------+
mysql> select * from dept;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
mysql> select * from salgrade;
+-------+-------+-------+
| GRADE | LOSAL | HISAL |
+-------+-------+-------+
| 1 | 700 | 1200 |
| 2 | 1201 | 1400 |
| 3 | 1401 | 2000 |
| 4 | 2001 | 3000 |
| 5 | 3001 | 9999 |
+-------+-------+-------+
12、不看表中的數據,只看表的結構,有一個命令:
desc 表名;
mysql> desc dept;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| DEPTNO | int(2) | NO | PRI | NULL | |部門編號
| DNAME | varchar(14) | YES | | NULL | |部門名字
| LOC | varchar(13) | YES | | NULL | |地理位置
+--------+-------------+------+-----+---------+-------+
mysql> desc emp;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| EMPNO | int(4) | NO | PRI | NULL | |員工編號
| ENAME | varchar(10) | YES | | NULL | |員工姓名
| JOB | varchar(9) | YES | | NULL | |工作崗位
| MGR | int(4) | YES | | NULL | |上級編號
| HIREDATE | date | YES | | NULL | |入職日期
| SAL | double(7,2) | YES | | NULL | |工資
| COMM | double(7,2) | YES | | NULL | |補助
| DEPTNO | int(2) | YES | | NULL | |部門編號
+----------+-------------+------+-----+---------+-------+
mysql> desc salgrade;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| GRADE | int(11) | YES | | NULL | |工資等級
| LOSAL | int(11) | YES | | NULL | |最低工資
| HISAL | int(11) | YES | | NULL | |最高工資
+-------+---------+------+-----+---------+-------+
describe縮寫為:desc
mysql> describe dept;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| DEPTNO | int(2) | NO | PRI | NULL | |
| DNAME | varchar(14) | YES | | NULL | |
| LOC | varchar(13) | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
13、簡單查詢
13.1、查詢一個字段?
select 字段名 from 表名;
其中要注意:
select和from都是關鍵字。
字段名和表名都是標識符。
強調:
對於SQL語句來說,是通用的,
所有的SQL語句以“;”結尾。
另外SQL語句不區分大小寫,都行。
查詢部門名字?
mysql> select dname from dept;
+------------+
| dname |
+------------+
| ACCOUNTING |
| RESEARCH |
| SALES |
| OPERATIONS |
+------------+
4 rows in set (0.00 sec)
mysql> SELECT DNAME FROM DEPT;
+------------+
| DNAME |
+------------+
| ACCOUNTING |
| RESEARCH |
| SALES |
| OPERATIONS |
+------------+
4 rows in set (0.00 sec)
13.2、查詢兩個字段,或者多個字段怎么辦?
使用逗號隔開“,”
查詢部門編號和部門名?
select deptno,dname from dept;
+--------+------------+
| deptno | dname |
+--------+------------+
| 10 | ACCOUNTING |
| 20 | RESEARCH |
| 30 | SALES |
| 40 | OPERATIONS |
+--------+------------+
13.3、查詢所有字段怎么辦?
第一種方式:可以把每個字段都寫上
select a,b,c,d,e,f... from tablename;
第二種方式:可以使用*
select * from dept;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
這種方式的缺點:
1、效率低
2、可讀性差。
在實際開發中不建議,可以自己玩沒問題。
你可以在DOS命令窗口中想快速的看一看全表數據可以采用這種方式。
13.4、給查詢的列起別名?
mysql> select deptno,dname as deptname from dept;
+--------+------------+
| deptno | deptname |
+--------+------------+
| 10 | ACCOUNTING |
| 20 | RESEARCH |
| 30 | SALES |
| 40 | OPERATIONS |
+--------+------------+
使用as關鍵字起別名。
注意:只是將顯示的查詢結果列名顯示為deptname,原表列名還是叫:dname
記住:select語句是永遠都不會進行修改操作的。(因為只負責查詢)
as關鍵字可以省略嗎?可以的
mysql> select deptno,dname deptname from dept;
假設起別名的時候,別名里面有空格,怎么辦?
mysql> select deptno,dname dept name from dept;
DBMS看到這樣的語句,進行SQL語句的編譯,不符合語法,編譯報錯。
怎么解決?
select deptno,dname 'dept name' from dept; //加單引號
select deptno,dname "dept name" from dept; //加雙引號
+--------+------------+
| deptno | dept name |
+--------+------------+
| 10 | ACCOUNTING |
| 20 | RESEARCH |
| 30 | SALES |
| 40 | OPERATIONS |
+--------+------------+
注意:在所有的數據庫當中,字符串統一使用單引號括起來,
單引號是標准,雙引號在oracle數據庫中用不了。但是在mysql
中可以使用。
再次強調:數據庫中的字符串都是采用單引號括起來。這是標准的。
雙引號不標准。
13.5、計算員工年薪?sal * 12
mysql> select ename,sal from emp;
+--------+---------+
| ename | sal |
+--------+---------+
| SMITH | 800.00 |
| ALLEN | 1600.00 |
| WARD | 1250.00 |
| JONES | 2975.00 |
| MARTIN | 1250.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
| TURNER | 1500.00 |
| ADAMS | 1100.00 |
| JAMES | 950.00 |
| FORD | 3000.00 |
| MILLER | 1300.00 |
+--------+---------+
mysql> select ename,sal*12 from emp; // 結論:字段可以使用數學表達式!
+--------+----------+
| ename | sal*12 |
+--------+----------+
| SMITH | 9600.00 |
| ALLEN | 19200.00 |
| WARD | 15000.00 |
| JONES | 35700.00 |
| MARTIN | 15000.00 |
| BLAKE | 34200.00 |
| CLARK | 29400.00 |
| SCOTT | 36000.00 |
| KING | 60000.00 |
| TURNER | 18000.00 |
| ADAMS | 13200.00 |
| JAMES | 11400.00 |
| FORD | 36000.00 |
| MILLER | 15600.00 |
+--------+----------+
mysql> select ename,sal*12 as yearsal from emp; //起別名
+--------+----------+
| ename | yearsal |
+--------+----------+
| SMITH | 9600.00 |
| ALLEN | 19200.00 |
| WARD | 15000.00 |
| JONES | 35700.00 |
| MARTIN | 15000.00 |
| BLAKE | 34200.00 |
| CLARK | 29400.00 |
| SCOTT | 36000.00 |
| KING | 60000.00 |
| TURNER | 18000.00 |
| ADAMS | 13200.00 |
| JAMES | 11400.00 |
| FORD | 36000.00 |
| MILLER | 15600.00 |
+--------+----------+
mysql> select ename,sal*12 as '年薪' from emp; //別名是中文,用單引號括起來。
+--------+----------+
| ename | 年薪 |
+--------+----------+
| SMITH | 9600.00 |
| ALLEN | 19200.00 |
| WARD | 15000.00 |
| JONES | 35700.00 |
| MARTIN | 15000.00 |
| BLAKE | 34200.00 |
| CLARK | 29400.00 |
| SCOTT | 36000.00 |
| KING | 60000.00 |
| TURNER | 18000.00 |
| ADAMS | 13200.00 |
| JAMES | 11400.00 |
| FORD | 36000.00 |
| MILLER | 15600.00 |
+--------+----------+
14、條件查詢
14.1、什么是條件查詢?
不是將表中所有數據都查出來。是查詢出來符合條件的。
語法格式:
select
字段1,字段2,字段3....
from
表名
where
條件;
14.2、都有哪些條件?
= 等於
查詢薪資等於800的員工姓名和編號?
select empno,ename from emp where sal = 800;
查詢SMITH的編號和薪資?
select empno,sal from emp where ename = 'SMITH'; //字符串使用單引號
<>或!= 不等於
查詢薪資不等於800的員工姓名和編號?
select empno,ename from emp where sal != 800;
select empno,ename from emp where sal <> 800; // 小於號和大於號組成的不等號
< 小於
查詢薪資小於2000的員工姓名和編號?
mysql> select empno,ename,sal from emp where sal < 2000;
+-------+--------+---------+
| empno | ename | sal |
+-------+--------+---------+
| 7369 | SMITH | 800.00 |
| 7499 | ALLEN | 1600.00 |
| 7521 | WARD | 1250.00 |
| 7654 | MARTIN | 1250.00 |
| 7844 | TURNER | 1500.00 |
| 7876 | ADAMS | 1100.00 |
| 7900 | JAMES | 950.00 |
| 7934 | MILLER | 1300.00 |
+-------+--------+---------+
<= 小於等於
查詢薪資小於等於3000的員工姓名和編號?
select empno,ename,sal from emp where sal <= 3000;
> 大於
查詢薪資大於3000的員工姓名和編號?
select empno,ename,sal from emp where sal > 3000;
>= 大於等於
查詢薪資大於等於3000的員工姓名和編號?
select empno,ename,sal from emp where sal >= 3000;
between … and …. 兩個值之間, 等同於 >= and <=
查詢薪資在2450和3000之間的員工信息?包括2450和3000
第一種方式:>= and <= (and是並且的意思。)
select empno,ename,sal from emp where sal >= 2450 and sal <= 3000;
+-------+-------+---------+
| empno | ename | sal |
+-------+-------+---------+
| 7566 | JONES | 2975.00 |
| 7698 | BLAKE | 2850.00 |
| 7782 | CLARK | 2450.00 |
| 7788 | SCOTT | 3000.00 |
| 7902 | FORD | 3000.00 |
+-------+-------+---------+
第二種方式:between … and …
select
empno,ename,sal
from
emp
where
sal between 2450 and 3000;
注意:
使用between and的時候,必須遵循左小右大。
between and是閉區間,包括兩端的值。
is null 為 null(is not null 不為空)
查詢哪些員工的津貼/補助為null?
mysql> select empno,ename,sal,comm from emp where comm = null;
Empty set (0.00 sec)
mysql> select empno,ename,sal,comm from emp where comm is null;
+-------+--------+---------+------+
| empno | ename | sal | comm |
+-------+--------+---------+------+
| 7369 | SMITH | 800.00 | NULL |
| 7566 | JONES | 2975.00 | NULL |
| 7698 | BLAKE | 2850.00 | NULL |
| 7782 | CLARK | 2450.00 | NULL |
| 7788 | SCOTT | 3000.00 | NULL |
| 7839 | KING | 5000.00 | NULL |
| 7876 | ADAMS | 1100.00 | NULL |
| 7900 | JAMES | 950.00 | NULL |
| 7902 | FORD | 3000.00 | NULL |
| 7934 | MILLER | 1300.00 | NULL |
+-------+--------+---------+------+
10 rows in set (0.00 sec)
注意:在數據庫當中null不能使用等號進行衡量。需要使用is null
因為數據庫中的null代表什么也沒有,它不是一個值,所以不能使用
等號衡量。
查詢哪些員工的津貼/補助不為null?
select empno,ename,sal,comm from emp where comm is not null;
+-------+--------+---------+---------+
| empno | ename | sal | comm |
+-------+--------+---------+---------+
| 7499 | ALLEN | 1600.00 | 300.00 |
| 7521 | WARD | 1250.00 | 500.00 |
| 7654 | MARTIN | 1250.00 | 1400.00 |
| 7844 | TURNER | 1500.00 | 0.00 |
+-------+--------+---------+---------+
and 並且
查詢工作崗位是MANAGER並且工資大於2500的員工信息?
select
empno,ename,job,sal
from
emp
where
job = 'MANAGER' and sal > 2500;
+-------+-------+---------+---------+
| empno | ename | job | sal |
+-------+-------+---------+---------+
| 7566 | JONES | MANAGER | 2975.00 |
| 7698 | BLAKE | MANAGER | 2850.00 |
+-------+-------+---------+---------+
or 或者
查詢工作崗位是MANAGER和SALESMAN的員工?
select empno,ename,job from emp where job = 'MANAGER';
select empno,ename,job from emp where job = 'SALESMAN';
select
empno,ename,job
from
emp
where
job = 'MANAGER' or job = 'SALESMAN';
+-------+--------+----------+
| empno | ename | job |
+-------+--------+----------+
| 7499 | ALLEN | SALESMAN |
| 7521 | WARD | SALESMAN |
| 7566 | JONES | MANAGER |
| 7654 | MARTIN | SALESMAN |
| 7698 | BLAKE | MANAGER |
| 7782 | CLARK | MANAGER |
| 7844 | TURNER | SALESMAN |
+-------+--------+----------+
and和or同時出現的話,有優先級問題嗎?
查詢工資大於2500,並且部門編號為10或20部門的員工?
select
*
from
emp
where
sal > 2500 and deptno = 10 or deptno = 20;
分析以上語句的問題?
and優先級比or高。
以上語句會先執行and,然后執行or。
以上這個語句表示什么含義?
找出工資大於2500並且部門編號為10的員工,或者20部門所有員工找出來。
select
*
from
emp
where
sal > 2500 and (deptno = 10 or deptno = 20);
and和or同時出現,and優先級較高。如果想讓or先執行,需要加“小括號”
以后在開發中,如果不確定優先級,就加小括號就行了。
in 包含,相當於多個 or (not in 不在這個范圍中)
查詢工作崗位是MANAGER和SALESMAN的員工?
select empno,ename,job from emp where job = 'MANAGER' or job = 'SALESMAN';
select empno,ename,job from emp where job in('MANAGER', 'SALESMAN');
+-------+--------+----------+
| empno | ename | job |
+-------+--------+----------+
| 7499 | ALLEN | SALESMAN |
| 7521 | WARD | SALESMAN |
| 7566 | JONES | MANAGER |
| 7654 | MARTIN | SALESMAN |
| 7698 | BLAKE | MANAGER |
| 7782 | CLARK | MANAGER |
| 7844 | TURNER | SALESMAN |
+-------+--------+----------+
注意:in不是一個區間。in后面跟的是具體的值。
查詢薪資是800和5000的員工信息?
select ename,sal from emp where sal = 800 or sal = 5000;
select ename,sal from emp where sal in(800, 5000); //這個不是表示800到5000都找出來。
+-------+---------+
| ename | sal |
+-------+---------+
| SMITH | 800.00 |
| KING | 5000.00 |
+-------+---------+
select ename,sal from emp where sal in(800, 5000, 3000);
// not in 表示不在這幾個值當中的數據。
select ename,sal from emp where sal not in(800, 5000, 3000);
+--------+---------+
| ename | sal |
+--------+---------+
| ALLEN | 1600.00 |
| WARD | 1250.00 |
| JONES | 2975.00 |
| MARTIN | 1250.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| TURNER | 1500.00 |
| ADAMS | 1100.00 |
| JAMES | 950.00 |
| MILLER | 1300.00 |
+--------+---------+
not 可以取非,主要用在 is 或 in 中
is null
is not null
in
not in
like
稱為模糊查詢,支持%或下划線匹配
%匹配任意多個字符
下划線:任意一個字符。
(%是一個特殊的符號,_ 也是一個特殊符號)
找出名字中含有O的?
mysql> select ename from emp where ename like '%O%';
+-------+
| ename |
+-------+
| JONES |
| SCOTT |
| FORD |
+-------+
找出名字以T結尾的?
select ename from emp where ename like '%T';
找出名字以K開始的?
select ename from emp where ename like 'K%';
找出第二個字每是A的?
select ename from emp where ename like '_A%';
找出第三個字母是R的?
select ename from emp where ename like '__R%';
t_student學生表
name字段
----------------------
zhangsan
lisi
wangwu
zhaoliu
jack_son
找出名字中有“_”的?
select name from t_student where name like '%_%'; //這樣不行。
mysql> select name from t_student where name like '%\_%'; // \轉義字符。
+----------+
| name |
+----------+
| jack_son |
+----------+
15、排序
15.1、查詢所有員工薪資,排序?
select
ename,sal
from
emp
order by
sal; // 默認是升序!!!
+--------+---------+
| ename | sal |
+--------+---------+
| SMITH | 800.00 |
| JAMES | 950.00 |
| ADAMS | 1100.00 |
| WARD | 1250.00 |
| MARTIN | 1250.00 |
| MILLER | 1300.00 |
| TURNER | 1500.00 |
| ALLEN | 1600.00 |
| CLARK | 2450.00 |
| BLAKE | 2850.00 |
| JONES | 2975.00 |
| FORD | 3000.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
+--------+---------+
15.2、怎么降序?
指定降序:
select
ename,sal
from
emp
order by
sal desc;
+--------+---------+
| ename | sal |
+--------+---------+
| KING | 5000.00 |
| SCOTT | 3000.00 |
| FORD | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| ALLEN | 1600.00 |
| TURNER | 1500.00 |
| MILLER | 1300.00 |
| MARTIN | 1250.00 |
| WARD | 1250.00 |
| ADAMS | 1100.00 |
| JAMES | 950.00 |
| SMITH | 800.00 |
+--------+---------+
指定升序?
select
ename,sal
from
emp
order by
sal asc;
+--------+---------+
| ename | sal |
+--------+---------+
| SMITH | 800.00 |
| JAMES | 950.00 |
| ADAMS | 1100.00 |
| WARD | 1250.00 |
| MARTIN | 1250.00 |
| MILLER | 1300.00 |
| TURNER | 1500.00 |
| ALLEN | 1600.00 |
| CLARK | 2450.00 |
| BLAKE | 2850.00 |
| JONES | 2975.00 |
| FORD | 3000.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
+--------+---------+
15.3、可以兩個字段排序嗎?或者說按照多個字段排序?
查詢員工名字和薪資,要求按照薪資升序,如果薪資一樣的話,
再按照名字升序排列。
select
ename,sal
from
emp
order by
sal asc, ename asc; // sal在前,起主導,只有sal相等的時候,才會考慮啟用ename排序。
+--------+---------+
| ename | sal |
+--------+---------+
| SMITH | 800.00 |
| JAMES | 950.00 |
| ADAMS | 1100.00 |
| MARTIN | 1250.00 |
| WARD | 1250.00 |
| MILLER | 1300.00 |
| TURNER | 1500.00 |
| ALLEN | 1600.00 |
| CLARK | 2450.00 |
| BLAKE | 2850.00 |
| JONES | 2975.00 |
| FORD | 3000.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
+--------+---------+
15.4、了解:根據字段的位置也可以排序
select ename,sal from emp order by 2; // 2表示第二列。第二列是sal
按照查詢結果的第2列sal排序。
了解一下,不建議在開發中這樣寫,因為不健壯。
因為列的順序很容易發生改變,列順序修改之后,2就廢了。
16、綜合一點的案例:
找出工資在1250到3000之間的員工信息,要求按照薪資降序排列。
select
ename,sal
from
emp
where
sal between 1250 and 3000
order by
sal desc;
+--------+---------+
| ename | sal |
+--------+---------+
| FORD | 3000.00 |
| SCOTT | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| ALLEN | 1600.00 |
| TURNER | 1500.00 |
| MILLER | 1300.00 |
| MARTIN | 1250.00 |
| WARD | 1250.00 |
+--------+---------+
關鍵字順序不能變:
select
...
from
...
where
...
order by
...
以上語句的執行順序必須掌握:
第一步:from
第二步:where
第三步:select
第四步:order by(排序總是在最后執行!)
17、數據處理函數
17.1、數據處理函數又被稱為單行處理函數
單行處理函數的特點:一個輸入對應一個輸出。
和單行處理函數相對的是:多行處理函數。(多行處理函數特點:多個輸入,對應1個輸出!)
17.2、單行處理函數常見的有哪些?
lower 轉換小寫
mysql> select lower(ename) as ename from emp;
+--------+
| ename |
+--------+
| smith |
| allen |
| ward |
| jones |
| martin |
| blake |
| clark |
| scott |
| king |
| turner |
| adams |
| james |
| ford |
| miller |
+--------+
14個輸入,最后還是14個輸出。這是單行處理函數的特點。
upper 轉換大寫
mysql> select * from t_student;
+----------+
| name |
+----------+
| zhangsan |
| lisi |
| wangwu |
| jack_son |
+----------+
mysql> select upper(name) as name from t_student;
+----------+
| name |
+----------+
| ZHANGSAN |
| LISI |
| WANGWU |
| JACK_SON |
+----------+
substr 取子串(substr( 被截取的字符串, 起始下標,截取的長度))
select substr(ename, 1, 1) as ename from emp;
注意:起始下標從1開始,沒有0.
找出員工名字第一個字母是A的員工信息?
第一種方式:模糊查詢
select ename from emp where ename like 'A%';
第二種方式:substr函數
select
ename
from
emp
where
substr(ename,1,1) = 'A';
首字母大寫?
select name from t_student;
select upper(substr(name,1,1)) from t_student;
select substr(name,2,length(name) - 1) from t_student;
select concat(upper(substr(name,1,1)),substr(name,2,length(name) - 1)) as result from t_student;
+----------+
| result |
+----------+
| Zhangsan |
| Lisi |
| Wangwu |
| Jack_son |
+----------+
concat函數進行字符串的拼接
select concat(empno,ename) from emp;
+---------------------+
| concat(empno,ename) |
+---------------------+
| 7369SMITH |
| 7499ALLEN |
| 7521WARD |
| 7566JONES |
| 7654MARTIN |
| 7698BLAKE |
| 7782CLARK |
| 7788SCOTT |
| 7839KING |
| 7844TURNER |
| 7876ADAMS |
| 7900JAMES |
| 7902FORD |
| 7934MILLER |
+---------------------+
length 取長度
select length(ename) enamelength from emp;
+-------------+
| enamelength |
+-------------+
| 5 |
| 5 |
| 4 |
| 5 |
| 6 |
| 5 |
| 5 |
| 5 |
| 4 |
| 6 |
| 5 |
| 5 |
| 4 |
| 6 |
+-------------+
trim 去空格
mysql> select * from emp where ename = ' KING';
Empty set (0.00 sec)
mysql> select * from emp where ename = trim(' KING');
+-------+-------+-----------+------+------------+---------+------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+-------+-----------+------+------------+---------+------+--------+
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
+-------+-------+-----------+------+------------+---------+------+--------+
str_to_date 將字符串轉換成日期
date_format 格式化日期
format 設置千分位
case..when..then..when..then..else..end
當員工的工作崗位是MANAGER的時候,工資上調10%,當工作崗位是SALESMAN的時候,工資上調50%,其它正常。
(注意:不修改數據庫,只是將查詢結果顯示為工資上調)
select
ename,
job,
sal as oldsal,
(case job when 'MANAGER' then sal*1.1 when 'SALESMAN' then sal*1.5 else sal end) as newsal
from
emp;
+--------+-----------+---------+---------+
| ename | job | oldsal | newsal |
+--------+-----------+---------+---------+
| SMITH | CLERK | 800.00 | 800.00 |
| ALLEN | SALESMAN | 1600.00 | 2400.00 |
| WARD | SALESMAN | 1250.00 | 1875.00 |
| JONES | MANAGER | 2975.00 | 3272.50 |
| MARTIN | SALESMAN | 1250.00 | 1875.00 |
| BLAKE | MANAGER | 2850.00 | 3135.00 |
| CLARK | MANAGER | 2450.00 | 2695.00 |
| SCOTT | ANALYST | 3000.00 | 3000.00 |
| KING | PRESIDENT | 5000.00 | 5000.00 |
| TURNER | SALESMAN | 1500.00 | 2250.00 |
| ADAMS | CLERK | 1100.00 | 1100.00 |
| JAMES | CLERK | 950.00 | 950.00 |
| FORD | ANALYST | 3000.00 | 3000.00 |
| MILLER | CLERK | 1300.00 | 1300.00 |
+--------+-----------+---------+---------+
round 四舍五入
select 字段 from 表名;
select ename from emp;
select 'abc' from emp; // select后面直接跟“字面量/字面值”
mysql> select 'abc' as bieming from emp;
+---------+
| bieming |
+---------+
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
+---------+
mysql> select abc from emp;
ERROR 1054 (42S22): Unknown column 'abc' in 'field list'
這樣肯定報錯,因為會把abc當做一個字段的名字,去emp表中找abc字段去了。
select 1000 as num from emp; // 1000 也是被當做一個字面量/字面值。
+------+
| num |
+------+
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
| 1000 |
+------+
結論:select后面可以跟某個表的字段名(可以等同看做變量名),也可以跟字面量/字面值(數據)。
select 21000 as num from dept;
+-------+
| num |
+-------+
| 21000 |
| 21000 |
| 21000 |
| 21000 |
+-------+
mysql> select round(1236.567, 0) as result from emp; //保留整數位。
+--------+
| result |
+--------+
| 1237 |
| 1237 |
| 1237 |
| 1237 |
| 1237 |
| 1237 |
| 1237 |
| 1237 |
| 1237 |
| 1237 |
| 1237 |
| 1237 |
| 1237 |
| 1237 |
+--------+
select round(1236.567, 1) as result from emp; //保留1個小數
select round(1236.567, 2) as result from emp; //保留2個小數
select round(1236.567, -1) as result from emp; // 保留到十位。
+--------+
| result |
+--------+
| 1240 |
| 1240 |
| 1240 |
| 1240 |
| 1240 |
| 1240 |
| 1240 |
| 1240 |
| 1240 |
| 1240 |
| 1240 |
| 1240 |
| 1240 |
| 1240 |
+--------+
select round(1236.567, -2) as result from emp;
+--------+
| result |
+--------+
| 1200 |
| 1200 |
| 1200 |
| 1200 |
| 1200 |
| 1200 |
| 1200 |
| 1200 |
| 1200 |
| 1200 |
| 1200 |
| 1200 |
| 1200 |
| 1200 |
+--------+
rand() 生成隨機數
mysql> select round(rand()*100,0) from emp; // 100以內的隨機數
+---------------------+
| round(rand()*100,0) |
+---------------------+
| 76 |
| 29 |
| 15 |
| 88 |
| 95 |
| 9 |
| 63 |
| 89 |
| 54 |
| 3 |
| 54 |
| 61 |
| 42 |
| 28 |
+---------------------+
ifnull 可以將 null 轉換成一個具體值
ifnull是空處理函數。專門處理空的。
在所有數據庫當中,只要有NULL參與的數學運算,最終結果就是NULL。
mysql> select ename, sal + comm as salcomm from emp;
+--------+---------+
| ename | salcomm |
+--------+---------+
| SMITH | NULL |
| ALLEN | 1900.00 |
| WARD | 1750.00 |
| JONES | NULL |
| MARTIN | 2650.00 |
| BLAKE | NULL |
| CLARK | NULL |
| SCOTT | NULL |
| KING | NULL |
| TURNER | 1500.00 |
| ADAMS | NULL |
| JAMES | NULL |
| FORD | NULL |
| MILLER | NULL |
+--------+---------+
計算每個員工的年薪?
年薪 = (月薪 + 月補助) * 12
select ename, (sal + comm) * 12 as yearsal from emp;
+--------+----------+
| ename | yearsal |
+--------+----------+
| SMITH | NULL |
| ALLEN | 22800.00 |
| WARD | 21000.00 |
| JONES | NULL |
| MARTIN | 31800.00 |
| BLAKE | NULL |
| CLARK | NULL |
| SCOTT | NULL |
| KING | NULL |
| TURNER | 18000.00 |
| ADAMS | NULL |
| JAMES | NULL |
| FORD | NULL |
| MILLER | NULL |
+--------+----------+
注意:NULL只要參與運算,最終結果一定是NULL。為了避免這個現象,需要使用ifnull函數。
ifnull函數用法:ifnull(數據, 被當做哪個值)
如果“數據”為NULL的時候,把這個數據結構當做哪個值。
補助為NULL的時候,將補助當做0
select ename, (sal + ifnull(comm, 0)) * 12 as yearsal from emp;
+--------+----------+
| ename | yearsal |
+--------+----------+
| SMITH | 9600.00 |
| ALLEN | 22800.00 |
| WARD | 21000.00 |
| JONES | 35700.00 |
| MARTIN | 31800.00 |
| BLAKE | 34200.00 |
| CLARK | 29400.00 |
| SCOTT | 36000.00 |
| KING | 60000.00 |
| TURNER | 18000.00 |
| ADAMS | 13200.00 |
| JAMES | 11400.00 |
| FORD | 36000.00 |
| MILLER | 15600.00 |
+--------+----------+
18、分組函數(多行處理函數)
多行處理函數的特點:輸入多行,最終輸出一行。
5個:
count 計數
sum 求和
avg 平均值
max 最大值
min 最小值
注意:
分組函數在使用的時候必須先進行分組,然后才能用。
如果你沒有對數據進行分組,整張表默認為一組。
找出最高工資?
mysql> select max(sal) from emp;
+----------+
| max(sal) |
+----------+
| 5000.00 |
+----------+
找出最低工資?
mysql> select min(sal) from emp;
+----------+
| min(sal) |
+----------+
| 800.00 |
+----------+
計算工資和:
mysql> select sum(sal) from emp;
+----------+
| sum(sal) |
+----------+
| 29025.00 |
+----------+
計算平均工資:
mysql> select avg(sal) from emp;
+-------------+
| avg(sal) |
+-------------+
| 2073.214286 |
+-------------+
14個工資全部加起來,然后除以14。
計算員工數量?
mysql> select count(ename) from emp;
+--------------+
| count(ename) |
+--------------+
| 14 |
+--------------+
分組函數在使用的時候需要注意哪些?
第一點:分組函數自動忽略NULL,你不需要提前對NULL進行處理。
mysql> select sum(comm) from emp;
+-----------+
| sum(comm) |
+-----------+
| 2200.00 |
+-----------+
mysql> select count(comm) from emp;
+-------------+
| count(comm) |
+-------------+
| 4 |
+-------------+
mysql> select avg(comm) from emp;
+------------+
| avg(comm) |
+------------+
| 550.000000 |
+------------+
第二點:分組函數中count(*)和count(具體字段)有什么區別?
mysql> select count(*) from emp;
+----------+
| count(*) |
+----------+
| 14 |
+----------+
mysql> select count(comm) from emp;
+-------------+
| count(comm) |
+-------------+
| 4 |
+-------------+
count(具體字段):表示統計該字段下所有不為NULL的元素的總數。
count(*):統計表當中的總行數。(只要有一行數據count則++)
因為每一行記錄不可能都為NULL,一行數據中有一列不為NULL,則這行數據就是有效的。
第三點:分組函數不能夠直接使用在where子句中。
找出比最低工資高的員工信息。
select ename,sal from emp where sal > min(sal);
表面上沒問題,運行一下?
ERROR 1111 (HY000): Invalid use of group function
?????????????????????????????????????????????????????????????????????
說完分組查詢(group by)之后就明白了了。
第四點:所有的分組函數可以組合起來一起用。
select sum(sal),min(sal),max(sal),avg(sal),count(*) from emp;
+----------+----------+----------+-------------+----------+
| sum(sal) | min(sal) | max(sal) | avg(sal) | count(*) |
+----------+----------+----------+-------------+----------+
| 29025.00 | 800.00 | 5000.00 | 2073.214286 | 14 |
+----------+----------+----------+-------------+----------+
19、分組查詢(非常重要:五顆星*****)
19.1、什么是分組查詢?
在實際的應用中,可能有這樣的需求,需要先進行分組,然后對每一組的數據進行操作。
這個時候我們需要使用分組查詢,怎么進行分組查詢呢?
select
...
from
...
group by
...
計算每個部門的工資和?
計算每個工作崗位的平均薪資?
找出每個工作崗位的最高薪資?
....
19.2、將之前的關鍵字全部組合在一起,來看一下他們的執行順序?
select
...
from
...
where
...
group by
...
order by
...
以上關鍵字的順序不能顛倒,需要記憶。
執行順序是什么?
1. from
2. where
3. group by
4. select
5. order by
為什么分組函數不能直接使用在where后面?
select ename,sal from emp where sal > min(sal);//報錯。
因為分組函數在使用的時候必須先分組之后才能使用。
where執行的時候,還沒有分組。所以where后面不能出現分組函數。
select sum(sal) from emp;
這個沒有分組,為啥sum()函數可以用呢?
因為select在group by之后執行。
19.3、找出每個工作崗位的工資和?
實現思路:按照工作崗位分組,然后對工資求和。
select
job,sum(sal)
from
emp
group by
job;
+-----------+----------+
| job | sum(sal) |
+-----------+----------+
| ANALYST | 6000.00 |
| CLERK | 4150.00 |
| MANAGER | 8275.00 |
| PRESIDENT | 5000.00 |
| SALESMAN | 5600.00 |
+-----------+----------+
以上這個語句的執行順序?
先從emp表中查詢數據。
根據job字段進行分組。
然后對每一組的數據進行sum(sal)
select ename,job,sum(sal) from emp group by job;
+-------+-----------+----------+
| ename | job | sum(sal) |
+-------+-----------+----------+
| SCOTT | ANALYST | 6000.00 |
| SMITH | CLERK | 4150.00 |
| JONES | MANAGER | 8275.00 |
| KING | PRESIDENT | 5000.00 |
| ALLEN | SALESMAN | 5600.00 |
+-------+-----------+----------+
以上語句在mysql中可以執行,但是毫無意義。
以上語句在oracle中執行報錯。
oracle的語法比mysql的語法嚴格。(mysql的語法相對來說松散一些!)
重點結論:
在一條select語句當中,如果有group by語句的話,
select后面只能跟:參加分組的字段,以及分組函數。
其它的一律不能跟。
19.4、找出每個部門的最高薪資
實現思路是什么?
按照部門編號分組,求每一組的最大值。
select后面添加ename字段沒有意義,另外oracle會報錯。
mysql> select ename,deptno,max(sal) from emp group by deptno;
+-------+--------+----------+
| ename | deptno | max(sal) |
+-------+--------+----------+
| CLARK | 10 | 5000.00 |
| SMITH | 20 | 3000.00 |
| ALLEN | 30 | 2850.00 |
+-------+--------+----------+
mysql> select deptno,max(sal) from emp group by deptno;
+--------+----------+
| deptno | max(sal) |
+--------+----------+
| 10 | 5000.00 |
| 20 | 3000.00 |
| 30 | 2850.00 |
+--------+----------+
19.5、找出“每個部門,不同工作崗位”的最高薪資?
+--------+-----------+---------+--------+
| ename | job | sal | deptno |
+--------+-----------+---------+--------+
| MILLER | CLERK | 1300.00 | 10 |
| KING | PRESIDENT | 5000.00 | 10 |
| CLARK | MANAGER | 2450.00 | 10 |
| FORD | ANALYST | 3000.00 | 20 |
| ADAMS | CLERK | 1100.00 | 20 |
| SCOTT | ANALYST | 3000.00 | 20 |
| JONES | MANAGER | 2975.00 | 20 |
| SMITH | CLERK | 800.00 | 20 |
| BLAKE | MANAGER | 2850.00 | 30 |
| MARTIN | SALESMAN | 1250.00 | 30 |
| ALLEN | SALESMAN | 1600.00 | 30 |
| TURNER | SALESMAN | 1500.00 | 30 |
| WARD | SALESMAN | 1250.00 | 30 |
| JAMES | CLERK | 950.00 | 30 |
+--------+-----------+---------+--------+
技巧:兩個字段聯合成1個字段看。(兩個字段聯合分組)
select
deptno, job, max(sal)
from
emp
group by
deptno, job;
+--------+-----------+----------+
| deptno | job | max(sal) |
+--------+-----------+----------+
| 10 | CLERK | 1300.00 |
| 10 | MANAGER | 2450.00 |
| 10 | PRESIDENT | 5000.00 |
| 20 | ANALYST | 3000.00 |
| 20 | CLERK | 1100.00 |
| 20 | MANAGER | 2975.00 |
| 30 | CLERK | 950.00 |
| 30 | MANAGER | 2850.00 |
| 30 | SALESMAN | 1600.00 |
+--------+-----------+----------+
19.6、使用having可以對分完組之后的數據進一步過濾。
having不能單獨使用,having不能代替where,having必須
和group by聯合使用。
找出每個部門最高薪資,要求顯示最高薪資大於3000的?
第一步:找出每個部門最高薪資
按照部門編號分組,求每一組最大值。
select deptno,max(sal) from emp group by deptno;
+--------+----------+
| deptno | max(sal) |
+--------+----------+
| 10 | 5000.00 |
| 20 | 3000.00 |
| 30 | 2850.00 |
+--------+----------+
第二步:要求顯示最高薪資大於3000
select
deptno,max(sal)
from
emp
group by
deptno
having
max(sal) > 3000;
+--------+----------+
| deptno | max(sal) |
+--------+----------+
| 10 | 5000.00 |
+--------+----------+
思考一個問題:以上的sql語句執行效率是不是低?
比較低,實際上可以這樣考慮:先將大於3000的都找出來,然后再分組。
select
deptno,max(sal)
from
emp
where
sal > 3000
group by
deptno;
+--------+----------+
| deptno | max(sal) |
+--------+----------+
| 10 | 5000.00 |
+--------+----------+
優化策略:
where和having,優先選擇where,where實在完成不了了,再選擇
having。
19.7、where沒辦法的????
找出每個部門平均薪資,要求顯示平均薪資高於2500的。
第一步:找出每個部門平均薪資
select deptno,avg(sal) from emp group by deptno;
+--------+-------------+
| deptno | avg(sal) |
+--------+-------------+
| 10 | 2916.666667 |
| 20 | 2175.000000 |
| 30 | 1566.666667 |
+--------+-------------+
第二步:要求顯示平均薪資高於2500的
select
deptno,avg(sal)
from
emp
group by
deptno
having
avg(sal) > 2500;
+--------+-------------+
| deptno | avg(sal) |
+--------+-------------+
| 10 | 2916.666667 |
+--------+-------------+
20、大總結(單表的查詢學完了)
select
...
from
...
where
...
group by
...
having
...
order by
...
以上關鍵字只能按照這個順序來,不能顛倒。
執行順序?
1. from
2. where
3. group by
4. having
5. select
6. order by
從某張表中查詢數據,
先經過where條件篩選出有價值的數據。
對這些有價值的數據進行分組。
分組之后可以使用having繼續篩選。
select查詢出來。
最后排序輸出!
找出每個崗位的平均薪資,要求顯示平均薪資大於1500的,除MANAGER崗位之外,
要求按照平均薪資降序排。
select
job, avg(sal) as avgsal
from
emp
where
job <> 'MANAGER'
group by
job
having
avg(sal) > 1500
order by
avgsal desc;
+-----------+-------------+
| job | avgsal |
+-----------+-------------+
| PRESIDENT | 5000.000000 |
| ANALYST | 3000.000000 |
+-----------+-------------+
mysql day02課堂筆記
1、把查詢結果去除重復記錄【distinct】
注意:原表數據不會被修改,只是查詢結果去重。
去重需要使用一個關鍵字:distinct
mysql> select distinct job from emp;
+-----------+
| job |
+-----------+
| CLERK |
| SALESMAN |
| MANAGER |
| ANALYST |
| PRESIDENT |
+-----------+
// 這樣編寫是錯誤的,語法錯誤。
// distinct只能出現在所有字段的最前方。
mysql> select ename,distinct job from emp;
// distinct出現在job,deptno兩個字段之前,表示兩個字段聯合起來去重。
mysql> select distinct job,deptno from emp;
+-----------+--------+
| job | deptno |
+-----------+--------+
| CLERK | 20 |
| SALESMAN | 30 |
| MANAGER | 20 |
| MANAGER | 30 |
| MANAGER | 10 |
| ANALYST | 20 |
| PRESIDENT | 10 |
| CLERK | 30 |
| CLERK | 10 |
+-----------+--------+
統計一下工作崗位的數量?
select count(distinct job) from emp;
+---------------------+
| count(distinct job) |
+---------------------+
| 5 |
+---------------------+
2、連接查詢
2.1、什么是連接查詢?
從一張表中單獨查詢,稱為單表查詢。
emp表和dept表聯合起來查詢數據,從emp表中取員工名字,從dept表中取部門名字。
這種跨表查詢,多張表聯合起來查詢數據,被稱為連接查詢。
2.2、連接查詢的分類?
根據語法的年代分類:
SQL92:1992年的時候出現的語法
SQL99:1999年的時候出現的語法
我們這里重點學習SQL99.(這個過程中簡單演示一個SQL92的例子)
根據表連接的方式分類:
內連接:
等值連接
非等值連接
自連接
外連接:
左外連接(左連接)
右外連接(右連接)
全連接(不講)
2.3、當兩張表進行連接查詢時,沒有任何條件的限制會發生什么現象?
案例:查詢每個員工所在部門名稱?
mysql> select ename,deptno from emp;
+--------+--------+
| ename | deptno |
+--------+--------+
| SMITH | 20 |
| ALLEN | 30 |
| WARD | 30 |
| JONES | 20 |
| MARTIN | 30 |
| BLAKE | 30 |
| CLARK | 10 |
| SCOTT | 20 |
| KING | 10 |
| TURNER | 30 |
| ADAMS | 20 |
| JAMES | 30 |
| FORD | 20 |
| MILLER | 10 |
+--------+--------+
mysql> select * from dept;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
兩張表連接沒有任何條件限制:
select ename,dname from emp, dept;
+--------+------------+
| ename | dname |
+--------+------------+
| SMITH | ACCOUNTING |
| SMITH | RESEARCH |
| SMITH | SALES |
| SMITH | OPERATIONS |
| ALLEN | ACCOUNTING |
| ALLEN | RESEARCH |
| ALLEN | SALES |
| ALLEN | OPERATIONS |
...
56 rows in set (0.00 sec)
14 * 4 = 56
當兩張表進行連接查詢,沒有任何條件限制的時候,最終查詢結果條數,是
兩張表條數的乘積,這種現象被稱為:笛卡爾積現象。(笛卡爾發現的,這是
一個數學現象。)
2.4、怎么避免笛卡爾積現象?
連接時加條件,滿足這個條件的記錄被篩選出來!
select
ename,dname
from
emp, dept
where
emp.deptno = dept.deptno;
select
emp.ename,dept.dname
from
emp, dept
where
emp.deptno = dept.deptno;
// 表起別名。很重要。效率問題。
select
e.ename,d.dname
from
emp e, dept d
where
e.deptno = d.deptno; //SQL92語法。
+--------+------------+
| ename | dname |
+--------+------------+
| CLARK | ACCOUNTING |
| KING | ACCOUNTING |
| MILLER | ACCOUNTING |
| SMITH | RESEARCH |
| JONES | RESEARCH |
| SCOTT | RESEARCH |
| ADAMS | RESEARCH |
| FORD | RESEARCH |
| ALLEN | SALES |
| WARD | SALES |
| MARTIN | SALES |
| BLAKE | SALES |
| TURNER | SALES |
| JAMES | SALES |
+--------+------------+
思考:最終查詢的結果條數是14條,但是匹配的過程中,匹配的次數減少了嗎?
還是56次,只不過進行了四選一。次數沒有減少。
注意:通過笛卡爾積現象得出,表的連接次數越多效率越低,盡量避免表的
連接次數。
2.5、內連接之等值連接。
案例:查詢每個員工所在部門名稱,顯示員工名和部門名?
emp e和dept d表進行連接。條件是:e.deptno = d.deptno
SQL92語法:
select
e.ename,d.dname
from
emp e, dept d
where
e.deptno = d.deptno;
sql92的缺點:結構不清晰,表的連接條件,和后期進一步篩選的條件,都放到了where后面。
SQL99語法:
select
e.ename,d.dname
from
emp e
join
dept d
on
e.deptno = d.deptno;
//inner可以省略(帶着inner可讀性更好!!!一眼就能看出來是內連接)
select
e.ename,d.dname
from
emp e
inner join
dept d
on
e.deptno = d.deptno; // 條件是等量關系,所以被稱為等值連接。
sql99優點:表連接的條件是獨立的,連接之后,如果還需要進一步篩選,再往后繼續添加where
SQL99語法:
select
...
from
a
join
b
on
a和b的連接條件
where
篩選條件
2.6、內連接之非等值連接
案例:找出每個員工的薪資等級,要求顯示員工名、薪資、薪資等級?
mysql> select * from emp; e
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
....
mysql> select * from salgrade; s
+-------+-------+-------+
| GRADE | LOSAL | HISAL |
+-------+-------+-------+
| 1 | 700 | 1200 |
| 2 | 1201 | 1400 |
| 3 | 1401 | 2000 |
| 4 | 2001 | 3000 |
| 5 | 3001 | 9999 |
+-------+-------+-------+
select
e.ename, e.sal, s.grade
from
emp e
join
salgrade s
on
e.sal between s.losal and s.hisal; // 條件不是一個等量關系,稱為非等值連接。
select
e.ename, e.sal, s.grade
from
emp e
inner join
salgrade s
on
e.sal between s.losal and s.hisal;
+--------+---------+-------+
| ename | sal | grade |
+--------+---------+-------+
| SMITH | 800.00 | 1 |
| ALLEN | 1600.00 | 3 |
| WARD | 1250.00 | 2 |
| JONES | 2975.00 | 4 |
| MARTIN | 1250.00 | 2 |
| BLAKE | 2850.00 | 4 |
| CLARK | 2450.00 | 4 |
| SCOTT | 3000.00 | 4 |
| KING | 5000.00 | 5 |
| TURNER | 1500.00 | 3 |
| ADAMS | 1100.00 | 1 |
| JAMES | 950.00 | 1 |
| FORD | 3000.00 | 4 |
| MILLER | 1300.00 | 2 |
+--------+---------+-------+
2.7、內連接之自連接
案例:查詢員工的上級領導,要求顯示員工名和對應的領導名?
mysql> select empno,ename,mgr from emp;
+-------+--------+------+
| empno | ename | mgr |
+-------+--------+------+
| 7369 | SMITH | 7902 |
| 7499 | ALLEN | 7698 |
| 7521 | WARD | 7698 |
| 7566 | JONES | 7839 |
| 7654 | MARTIN | 7698 |
| 7698 | BLAKE | 7839 |
| 7782 | CLARK | 7839 |
| 7788 | SCOTT | 7566 |
| 7839 | KING | NULL |
| 7844 | TURNER | 7698 |
| 7876 | ADAMS | 7788 |
| 7900 | JAMES | 7698 |
| 7902 | FORD | 7566 |
| 7934 | MILLER | 7782 |
+-------+--------+------+
技巧:一張表看成兩張表。
emp a 員工表
+-------+--------+------+
| empno | ename | mgr |
+-------+--------+------+
| 7369 | SMITH | 7902 |
| 7499 | ALLEN | 7698 |
| 7521 | WARD | 7698 |
| 7566 | JONES | 7839 |
| 7654 | MARTIN | 7698 |
| 7698 | BLAKE | 7839 |
| 7782 | CLARK | 7839 |
| 7788 | SCOTT | 7566 |
| 7839 | KING | NULL |
| 7844 | TURNER | 7698 |
| 7876 | ADAMS | 7788 |
| 7900 | JAMES | 7698 |
| 7902 | FORD | 7566 |
| 7934 | MILLER | 7782 |
+-------+--------+------+
emp b 領導表
+-------+--------+------+
| empno | ename | mgr |
+-------+--------+------+
| 7369 | SMITH | 7902 |
| 7499 | ALLEN | 7698 |
| 7521 | WARD | 7698 |
| 7566 | JONES | 7839 |
| 7654 | MARTIN | 7698 |
| 7698 | BLAKE | 7839 |
| 7782 | CLARK | 7839 |
| 7788 | SCOTT | 7566 |
| 7839 | KING | NULL |
| 7844 | TURNER | 7698 |
| 7876 | ADAMS | 7788 |
| 7900 | JAMES | 7698 |
| 7902 | FORD | 7566 |
| 7934 | MILLER | 7782 |
+-------+--------+------+
select
a.ename as '員工名', b.ename as '領導名'
from
emp a
join
emp b
on
a.mgr = b.empno; //員工的領導編號 = 領導的員工編號
+--------+--------+
| 員工名 | 領導名|
+--------+--------+
| SMITH | FORD |
| ALLEN | BLAKE |
| WARD | BLAKE |
| JONES | KING |
| MARTIN | BLAKE |
| BLAKE | KING |
| CLARK | KING |
| SCOTT | JONES |
| TURNER | BLAKE |
| ADAMS | SCOTT |
| JAMES | BLAKE |
| FORD | JONES |
| MILLER | CLARK |
+--------+--------+
13條記錄,沒有KING。《內連接》
以上就是內連接中的:自連接,技巧:一張表看做兩張表。
2.8、外連接
mysql> select * from emp; e
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |
| 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 |
+-------+--------+-----------+------+------------+---------+---------+--------+
mysql> select * from dept; d
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
內連接:(A和B連接,AB兩張表沒有主次關系。平等的。)
select
e.ename,d.dname
from
emp e
join
dept d
on
e.deptno = d.deptno; //內連接的特點:完成能夠匹配上這個條件的數據查詢出來。
+--------+------------+
| ename | dname |
+--------+------------+
| CLARK | ACCOUNTING |
| KING | ACCOUNTING |
| MILLER | ACCOUNTING |
| SMITH | RESEARCH |
| JONES | RESEARCH |
| SCOTT | RESEARCH |
| ADAMS | RESEARCH |
| FORD | RESEARCH |
| ALLEN | SALES |
| WARD | SALES |
| MARTIN | SALES |
| BLAKE | SALES |
| TURNER | SALES |
| JAMES | SALES |
+--------+------------+
外連接(右外連接):
select
e.ename,d.dname
from
emp e
right join
dept d
on
e.deptno = d.deptno;
// outer是可以省略的,帶着可讀性強。
select
e.ename,d.dname
from
emp e
right outer join
dept d
on
e.deptno = d.deptno;
right代表什么:表示將join關鍵字右邊的這張表看成主表,主要是為了將
這張表的數據全部查詢出來,捎帶着關聯查詢左邊的表。
在外連接當中,兩張表連接,產生了主次關系。
外連接(左外連接):
select
e.ename,d.dname
from
dept d
left join
emp e
on
e.deptno = d.deptno;
// outer是可以省略的,帶着可讀性強。
select
e.ename,d.dname
from
dept d
left outer join
emp e
on
e.deptno = d.deptno;
帶有right的是右外連接,又叫做右連接。
帶有left的是左外連接,又叫做左連接。
任何一個右連接都有左連接的寫法。
任何一個左連接都有右連接的寫法。
+--------+------------+
| ename | dname |
+--------+------------+
| CLARK | ACCOUNTING |
| KING | ACCOUNTING |
| MILLER | ACCOUNTING |
| SMITH | RESEARCH |
| JONES | RESEARCH |
| SCOTT | RESEARCH |
| ADAMS | RESEARCH |
| FORD | RESEARCH |
| ALLEN | SALES |
| WARD | SALES |
| MARTIN | SALES |
| BLAKE | SALES |
| TURNER | SALES |
| JAMES | SALES |
| NULL | OPERATIONS |
+--------+------------+
思考:外連接的查詢結果條數一定是 >= 內連接的查詢結果條數?
正確。
案例:查詢每個員工的上級領導,要求顯示所有員工的名字和領導名?
select
a.ename as '員工名', b.ename as '領導名'
from
emp a
left join
emp b
on
a.mgr = b.empno;
+--------+--------+
| 員工名 | 領導名 |
+--------+--------+
| SMITH | FORD |
| ALLEN | BLAKE |
| WARD | BLAKE |
| JONES | KING |
| MARTIN | BLAKE |
| BLAKE | KING |
| CLARK | KING |
| SCOTT | JONES |
| KING | NULL |
| TURNER | BLAKE |
| ADAMS | SCOTT |
| JAMES | BLAKE |
| FORD | JONES |
| MILLER | CLARK |
+--------+--------+
2.9、三張表,四張表怎么連接?
語法:
select
...
from
a
join
b
on
a和b的連接條件
join
c
on
a和c的連接條件
right join
d
on
a和d的連接條件
一條SQL中內連接和外連接可以混合。都可以出現!
案例:找出每個員工的部門名稱以及工資等級,
要求顯示員工名、部門名、薪資、薪資等級?
select
e.ename,e.sal,d.dname,s.grade
from
emp e
join
dept d
on
e.deptno = d.deptno
join
salgrade s
on
e.sal between s.losal and s.hisal;
+--------+---------+------------+-------+
| ename | sal | dname | grade |
+--------+---------+------------+-------+
| SMITH | 800.00 | RESEARCH | 1 |
| ALLEN | 1600.00 | SALES | 3 |
| WARD | 1250.00 | SALES | 2 |
| JONES | 2975.00 | RESEARCH | 4 |
| MARTIN | 1250.00 | SALES | 2 |
| BLAKE | 2850.00 | SALES | 4 |
| CLARK | 2450.00 | ACCOUNTING | 4 |
| SCOTT | 3000.00 | RESEARCH | 4 |
| KING | 5000.00 | ACCOUNTING | 5 |
| TURNER | 1500.00 | SALES | 3 |
| ADAMS | 1100.00 | RESEARCH | 1 |
| JAMES | 950.00 | SALES | 1 |
| FORD | 3000.00 | RESEARCH | 4 |
| MILLER | 1300.00 | ACCOUNTING | 2 |
+--------+---------+------------+-------+
案例:找出每個員工的部門名稱以及工資等級,還有上級領導,
要求顯示員工名、領導名、部門名、薪資、薪資等級?
select
e.ename,e.sal,d.dname,s.grade,l.ename
from
emp e
join
dept d
on
e.deptno = d.deptno
join
salgrade s
on
e.sal between s.losal and s.hisal
left join
emp l
on
e.mgr = l.empno;
+--------+---------+------------+-------+-------+
| ename | sal | dname | grade | ename |
+--------+---------+------------+-------+-------+
| SMITH | 800.00 | RESEARCH | 1 | FORD |
| ALLEN | 1600.00 | SALES | 3 | BLAKE |
| WARD | 1250.00 | SALES | 2 | BLAKE |
| JONES | 2975.00 | RESEARCH | 4 | KING |
| MARTIN | 1250.00 | SALES | 2 | BLAKE |
| BLAKE | 2850.00 | SALES | 4 | KING |
| CLARK | 2450.00 | ACCOUNTING | 4 | KING |
| SCOTT | 3000.00 | RESEARCH | 4 | JONES |
| KING | 5000.00 | ACCOUNTING | 5 | NULL |
| TURNER | 1500.00 | SALES | 3 | BLAKE |
| ADAMS | 1100.00 | RESEARCH | 1 | SCOTT |
| JAMES | 950.00 | SALES | 1 | BLAKE |
| FORD | 3000.00 | RESEARCH | 4 | JONES |
| MILLER | 1300.00 | ACCOUNTING | 2 | CLARK |
+--------+---------+------------+-------+-------+
3、子查詢?
3.1、什么是子查詢?
select語句中嵌套select語句,被嵌套的select語句稱為子查詢。
3.2、子查詢都可以出現在哪里呢?
select
..(select).
from
..(select).
where
..(select).
3.3、where子句中的子查詢
案例:找出比最低工資高的員工姓名和工資?
select
ename,sal
from
emp
where
sal > min(sal);
ERROR 1111 (HY000): Invalid use of group function
where子句中不能直接使用分組函數。
實現思路:
第一步:查詢最低工資是多少
select min(sal) from emp;
+----------+
| min(sal) |
+----------+
| 800.00 |
+----------+
第二步:找出>800的
select ename,sal from emp where sal > 800;
第三步:合並
select ename,sal from emp where sal > (select min(sal) from emp);
+--------+---------+
| ename | sal |
+--------+---------+
| ALLEN | 1600.00 |
| WARD | 1250.00 |
| JONES | 2975.00 |
| MARTIN | 1250.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
| TURNER | 1500.00 |
| ADAMS | 1100.00 |
| JAMES | 950.00 |
| FORD | 3000.00 |
| MILLER | 1300.00 |
+--------+---------+
3.4、from子句中的子查詢
注意:from后面的子查詢,可以將子查詢的查詢結果當做一張臨時表。(技巧)
案例:找出每個崗位的平均工資的薪資等級。
第一步:找出每個崗位的平均工資(按照崗位分組求平均值)
select job,avg(sal) from emp group by job;
+-----------+-------------+
| job | avgsal |
+-----------+-------------+
| ANALYST | 3000.000000 |
| CLERK | 1037.500000 |
| MANAGER | 2758.333333 |
| PRESIDENT | 5000.000000 |
| SALESMAN | 1400.000000 |
+-----------+-------------+t表
第二步:克服心理障礙,把以上的查詢結果就當做一張真實存在的表t。
mysql> select * from salgrade; s表
+-------+-------+-------+
| GRADE | LOSAL | HISAL |
+-------+-------+-------+
| 1 | 700 | 1200 |
| 2 | 1201 | 1400 |
| 3 | 1401 | 2000 |
| 4 | 2001 | 3000 |
| 5 | 3001 | 9999 |
+-------+-------+-------+
t表和s表進行表連接,條件:t表avg(sal) between s.losal and s.hisal;
select
t.*, s.grade
from
(select job,avg(sal) as avgsal from emp group by job) t
join
salgrade s
on
t.avgsal between s.losal and s.hisal;
+-----------+-------------+-------+
| job | avgsal | grade |
+-----------+-------------+-------+
| CLERK | 1037.500000 | 1 |
| SALESMAN | 1400.000000 | 2 |
| ANALYST | 3000.000000 | 4 |
| MANAGER | 2758.333333 | 4 |
| PRESIDENT | 5000.000000 | 5 |
+-----------+-------------+-------+
3.5、select后面出現的子查詢(這個內容不需要掌握,了解即可!!!)
案例:找出每個員工的部門名稱,要求顯示員工名,部門名?
select
e.ename,e.deptno,(select d.dname from dept d where e.deptno = d.deptno) as dname
from
emp e;
+--------+--------+------------+
| ename | deptno | dname |
+--------+--------+------------+
| SMITH | 20 | RESEARCH |
| ALLEN | 30 | SALES |
| WARD | 30 | SALES |
| JONES | 20 | RESEARCH |
| MARTIN | 30 | SALES |
| BLAKE | 30 | SALES |
| CLARK | 10 | ACCOUNTING |
| SCOTT | 20 | RESEARCH |
| KING | 10 | ACCOUNTING |
| TURNER | 30 | SALES |
| ADAMS | 20 | RESEARCH |
| JAMES | 30 | SALES |
| FORD | 20 | RESEARCH |
| MILLER | 10 | ACCOUNTING |
+--------+--------+------------+
//錯誤:ERROR 1242 (21000): Subquery returns more than 1 row
select
e.ename,e.deptno,(select dname from dept) as dname
from
emp e;
注意:對於select后面的子查詢來說,這個子查詢只能一次返回1條結果,
多於1條,就報錯了。!
4、union合並查詢結果集
案例:查詢工作崗位是MANAGER和SALESMAN的員工?
select ename,job from emp where job = 'MANAGER' or job = 'SALESMAN';
select ename,job from emp where job in('MANAGER','SALESMAN');
+--------+----------+
| ename | job |
+--------+----------+
| ALLEN | SALESMAN |
| WARD | SALESMAN |
| JONES | MANAGER |
| MARTIN | SALESMAN |
| BLAKE | MANAGER |
| CLARK | MANAGER |
| TURNER | SALESMAN |
+--------+----------+
select ename,job from emp where job = 'MANAGER'
union
select ename,job from emp where job = 'SALESMAN';
+--------+----------+
| ename | job |
+--------+----------+
| JONES | MANAGER |
| BLAKE | MANAGER |
| CLARK | MANAGER |
| ALLEN | SALESMAN |
| WARD | SALESMAN |
| MARTIN | SALESMAN |
| TURNER | SALESMAN |
+--------+----------+
union的效率要高一些。對於表連接來說,每連接一次新表,
則匹配的次數滿足笛卡爾積,成倍的翻。。。
但是union可以減少匹配的次數。在減少匹配次數的情況下,
還可以完成兩個結果集的拼接。
a 連接 b 連接 c
a 10條記錄
b 10條記錄
c 10條記錄
匹配次數是:1000
a 連接 b一個結果:10 * 10 --> 100次
a 連接 c一個結果:10 * 10 --> 100次
使用union的話是:100次 + 100次 = 200次。(union把乘法變成了加法運算)
union在使用的時候有注意事項嗎?
//錯誤的:union在進行結果集合並的時候,要求兩個結果集的列數相同。
select ename,job from emp where job = 'MANAGER'
union
select ename from emp where job = 'SALESMAN';
// MYSQL可以,oracle語法嚴格 ,不可以,報錯。要求:結果集合並時列和列的數據類型也要一致。
select ename,job from emp where job = 'MANAGER'
union
select ename,sal from emp where job = 'SALESMAN';
+--------+---------+
| ename | job |
+--------+---------+
| JONES | MANAGER |
| BLAKE | MANAGER |
| CLARK | MANAGER |
| ALLEN | 1600 |
| WARD | 1250 |
| MARTIN | 1250 |
| TURNER | 1500 |
+--------+---------+
5、limit(非常重要)
5.1、limit作用:將查詢結果集的一部分取出來。通常使用在分頁查詢當中。
百度默認:一頁顯示10條記錄。
分頁的作用是為了提高用戶的體驗,因為一次全部都查出來,用戶體驗差。
可以一頁一頁翻頁看。
5.2、limit怎么用呢?
完整用法:limit startIndex, length
startIndex是起始下標,length是長度。
起始下標從0開始。
缺省用法:limit 5; 這是取前5.
按照薪資降序,取出排名在前5名的員工?
select
ename,sal
from
emp
order by
sal desc
limit 5; //取前5
select
ename,sal
from
emp
order by
sal desc
limit 0,5;
+-------+---------+
| ename | sal |
+-------+---------+
| KING | 5000.00 |
| SCOTT | 3000.00 |
| FORD | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
+-------+---------+
5.3、注意:mysql當中limit在order by之后執行!!!!!!
5.4、取出工資排名在[3-5]名的員工?
select
ename,sal
from
emp
order by
sal desc
limit
2, 3;
2表示起始位置從下標2開始,就是第三條記錄。
3表示長度。
+-------+---------+
| ename | sal |
+-------+---------+
| FORD | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
+-------+---------+
5.5、取出工資排名在[5-9]名的員工?
select
ename,sal
from
emp
order by
sal desc
limit
4, 5;
+--------+---------+
| ename | sal |
+--------+---------+
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| ALLEN | 1600.00 |
| TURNER | 1500.00 |
| MILLER | 1300.00 |
+--------+---------+
5.6、分頁
每頁顯示3條記錄
第1頁:limit 0,3 [0 1 2]
第2頁:limit 3,3 [3 4 5]
第3頁:limit 6,3 [6 7 8]
第4頁:limit 9,3 [9 10 11]
每頁顯示pageSize條記錄
第pageNo頁:limit (pageNo - 1) * pageSize , pageSize
public static void main(String[] args){
// 用戶提交過來一個頁碼,以及每頁顯示的記錄條數
int pageNo = 5; //第5頁
int pageSize = 10; //每頁顯示10條
int startIndex = (pageNo - 1) * pageSize;
String sql = "select ...limit " + startIndex + ", " + pageSize;
}
記公式:
limit (pageNo-1)*pageSize , pageSize
6、關於DQL語句的大總結:
select
...
from
...
where
...
group by
...
having
...
order by
...
limit
...
執行順序?
1.from
2.where
3.group by
4.having
5.select
6.order by
7.limit..
7、表的創建(建表)
7.1、建表的語法格式:(建表屬於DDL語句,DDL包括:create drop alter)
create table 表名(字段名1 數據類型, 字段名2 數據類型, 字段名3 數據類型);
create table 表名(
字段名1 數據類型,
字段名2 數據類型,
字段名3 數據類型
);
表名:建議以t_ 或者 tbl_開始,可讀性強。見名知意。
字段名:見名知意。
表名和字段名都屬於標識符。
7.2、關於mysql中的數據類型?
很多數據類型,我們只需要掌握一些常見的數據類型即可。
varchar(最長255)
可變長度的字符串
比較智能,節省空間。
會根據實際的數據長度動態分配空間。
優點:節省空間
缺點:需要動態分配空間,速度慢。
char(最長255)
定長字符串
不管實際的數據長度是多少。
分配固定長度的空間去存儲數據。
使用不恰當的時候,可能會導致空間的浪費。
優點:不需要動態分配空間,速度快。
缺點:使用不當可能會導致空間的浪費。
varchar和char我們應該怎么選擇?
性別字段你選什么?因為性別是固定長度的字符串,所以選擇char。
姓名字段你選什么?每一個人的名字長度不同,所以選擇varchar。
int(最長11)
數字中的整數型。等同於java的int。
bigint
數字中的長整型。等同於java中的long。
float
單精度浮點型數據
double
雙精度浮點型數據
date
短日期類型
datetime
長日期類型
clob
字符大對象
最多可以存儲4G的字符串。
比如:存儲一篇文章,存儲一個說明。
超過255個字符的都要采用CLOB字符大對象來存儲。
Character Large OBject:CLOB
blob
二進制大對象
Binary Large OBject
專門用來存儲圖片、聲音、視頻等流媒體數據。
往BLOB類型的字段上插入數據的時候,例如插入一個圖片、視頻等,
你需要使用IO流才行。
t_movie 電影表(專門存儲電影信息的)
編號 名字 故事情節 上映日期 時長 海報 類型
no(bigint) name(varchar) history(clob) playtime(date) time(double) image(blob) type(char)
------------------------------------------------------------------------------------------------------------------
10000 哪吒 ........... 2019-10-11 2.5 .... '1'
10001 林正英之娘娘 ........... 2019-11-11 1.5 .... '2'
....
7.3、創建一個學生表?
學號、姓名、年齡、性別、郵箱地址
create table t_student(
no int,
name varchar(32),
sex char(1),
age int(3),
email varchar(255)
);
刪除表:
drop table t_student; // 當這張表不存在的時候會報錯!
// 如果這張表存在的話,刪除
drop table if exists t_student;
7.4、插入數據insert (DML)
語法格式:
insert into 表名(字段名1,字段名2,字段名3...) values(值1,值2,值3);
注意:字段名和值要一一對應。什么是一一對應?
數量要對應。數據類型要對應。
insert into t_student(no,name,sex,age,email) values(1,'zhangsan','m',20,'zhangsan@123.com');
insert into t_student(email,name,sex,age,no) values('lisi@123.com','lisi','f',20,2);
insert into t_student(no) values(3);
+------+----------+------+------+------------------+
| no | name | sex | age | email |
+------+----------+------+------+------------------+
| 1 | zhangsan | m | 20 | zhangsan@123.com |
| 2 | lisi | f | 20 | lisi@123.com |
| 3 | NULL | NULL | NULL | NULL |
+------+----------+------+------+------------------+
insert into t_student(name) values('wangwu');
+------+----------+------+------+------------------+
| no | name | sex | age | email |
+------+----------+------+------+------------------+
| 1 | zhangsan | m | 20 | zhangsan@123.com |
| 2 | lisi | f | 20 | lisi@123.com |
| 3 | NULL | NULL | NULL | NULL |
| NULL | wangwu | NULL | NULL | NULL |
+------+----------+------+------+------------------+
注意:insert語句但凡是執行成功了,那么必然會多一條記錄。
沒有給其它字段指定值的話,默認值是NULL。
drop table if exists t_student;
create table t_student(
no int,
name varchar(32),
sex char(1) default 'm',
age int(3),
email varchar(255)
);
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| no | int(11) | YES | | NULL | |
| name | varchar(32) | YES | | NULL | |
| sex | char(1) | YES | | m | |
| age | int(3) | YES | | NULL | |
| email | varchar(255) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
insert into t_student(no) values(1);
mysql> select * from t_student;
+------+------+------+------+-------+
| no | name | sex | age | email |
+------+------+------+------+-------+
| 1 | NULL | m | NULL | NULL |
+------+------+------+------+-------+
insert語句中的“字段名”可以省略嗎?可以
insert into t_student values(2); //錯誤的
// 注意:前面的字段名省略的話,等於都寫上了!所以值也要都寫上!
insert into t_student values(2, 'lisi', 'f', 20, 'lisi@123.com');
+------+------+------+------+--------------+
| no | name | sex | age | email |
+------+------+------+------+--------------+
| 1 | NULL | m | NULL | NULL |
| 2 | lisi | f | 20 | lisi@123.com |
+------+------+------+------+--------------+
7.5、insert插入日期
數字格式化:format
select ename,sal from emp;
+--------+---------+
| ename | sal |
+--------+---------+
| SMITH | 800.00 |
| ALLEN | 1600.00 |
| WARD | 1250.00 |
| JONES | 2975.00 |
| MARTIN | 1250.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
| TURNER | 1500.00 |
| ADAMS | 1100.00 |
| JAMES | 950.00 |
| FORD | 3000.00 |
| MILLER | 1300.00 |
+--------+---------+
格式化數字:format(數字, '格式')
select ename,format(sal, '$999,999') as sal from emp;
+--------+-------+
| ename | sal |
+--------+-------+
| SMITH | 800 |
| ALLEN | 1,600 |
| WARD | 1,250 |
| JONES | 2,975 |
| MARTIN | 1,250 |
| BLAKE | 2,850 |
| CLARK | 2,450 |
| SCOTT | 3,000 |
| KING | 5,000 |
| TURNER | 1,500 |
| ADAMS | 1,100 |
| JAMES | 950 |
| FORD | 3,000 |
| MILLER | 1,300 |
+--------+-------+
str_to_date:將字符串varchar類型轉換成date類型
date_format:將date類型轉換成具有一定格式的varchar字符串類型。
drop table if exists t_user;
create table t_user(
id int,
name varchar(32),
birth date // 生日也可以使用date日期類型
);
create table t_user(
id int,
name varchar(32),
birth char(10) // 生日可以使用字符串,沒問題。
);
生日:1990-10-11 (10個字符)
注意:數據庫中的有一條命名規范:
所有的標識符都是全部小寫,單詞和單詞之間使用下划線進行銜接。
mysql> desc t_user;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(32) | YES | | NULL | |
| birth | date | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
插入數據?
insert into t_user(id,name,birth) values(1, 'zhangsan', '01-10-1990'); // 1990年10月1日
出問題了:原因是類型不匹配。數據庫birth是date類型,這里給了一個字符串varchar。
怎么辦?可以使用str_to_date函數進行類型轉換。
str_to_date函數可以將字符串轉換成日期類型date?
語法格式:
str_to_date('字符串日期', '日期格式')
mysql的日期格式:
%Y 年
%m 月
%d 日
%h 時
%i 分
%s 秒
insert into t_user(id,name,birth) values(1, 'zhangsan', str_to_date('01-10-1990','%d-%m-%Y'));
str_to_date函數可以把字符串varchar轉換成日期date類型數據,
通常使用在插入insert方面,因為插入的時候需要一個日期類型的數據,
需要通過該函數將字符串轉換成date。
好消息?
如果你提供的日期字符串是這個格式,str_to_date函數就不需要了!!!
%Y-%m-%d
insert into t_user(id,name,birth) values(2, 'lisi', '1990-10-01');
查詢的時候可以以某個特定的日期格式展示嗎?
date_format
這個函數可以將日期類型轉換成特定格式的字符串。
select id,name,date_format(birth, '%m/%d/%Y') as birth from t_user;
+------+----------+------------+
| id | name | birth |
+------+----------+------------+
| 1 | zhangsan | 10/01/1990 |
| 2 | lisi | 10/01/1990 |
+------+----------+------------+
date_format函數怎么用?
date_format(日期類型數據, '日期格式')
這個函數通常使用在查詢日期方面。設置展示的日期格式。
mysql> select id,name,birth from t_user;
+------+----------+------------+
| id | name | birth |
+------+----------+------------+
| 1 | zhangsan | 1990-10-01 |
| 2 | lisi | 1990-10-01 |
+------+----------+------------+
以上的SQL語句實際上是進行了默認的日期格式化,
自動將數據庫中的date類型轉換成varchar類型。
並且采用的格式是mysql默認的日期格式:'%Y-%m-%d'
select id,name,date_format(birth,'%Y/%m/%d') as birth from t_user;
java中的日期格式?
yyyy-MM-dd HH:mm:ss SSS
7.6、date和datetime兩個類型的區別?
date是短日期:只包括年月日信息。
datetime是長日期:包括年月日時分秒信息。
drop table if exists t_user;
create table t_user(
id int,
name varchar(32),
birth date,
create_time datetime
);
id是整數
name是字符串
birth是短日期
create_time是這條記錄的創建時間:長日期類型
mysql短日期默認格式:%Y-%m-%d
mysql長日期默認格式:%Y-%m-%d %h:%i:%s
insert into t_user(id,name,birth,create_time) values(1,'zhangsan','1990-10-01','2020-03-18 15:49:50');
在mysql當中怎么獲取系統當前時間?
now() 函數,並且獲取的時間帶有:時分秒信息!!!!是datetime類型的。
insert into t_user(id,name,birth,create_time) values(2,'lisi','1991-10-01',now());
7.7、修改update(DML)
語法格式:
update 表名 set 字段名1=值1,字段名2=值2,字段名3=值3... where 條件;
注意:沒有條件限制會導致所有數據全部更新。
update t_user set name = 'jack', birth = '2000-10-11' where id = 2;
+------+----------+------------+---------------------+
| id | name | birth | create_time |
+------+----------+------------+---------------------+
| 1 | zhangsan | 1990-10-01 | 2020-03-18 15:49:50 |
| 2 | jack | 2000-10-11 | 2020-03-18 15:51:23 |
+------+----------+------------+---------------------+
update t_user set name = 'jack', birth = '2000-10-11', create_time = now() where id = 2;
更新所有?
update t_user set name = 'abc';
7.8、刪除數據 delete (DML)
語法格式?
delete from 表名 where 條件;
注意:沒有條件,整張表的數據會全部刪除!
delete from t_user where id = 2;
insert into t_user(id) values(2);
delete from t_user; // 刪除所有!
mysql day03課堂筆記
1、查詢每一個員工的所在部門名稱?要求顯示員工名和部門名。
mysql> select * from emp;
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |
| 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 |
+-------+--------+-----------+------+------------+---------+---------+--------+
mysql> select * from dept;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
從emp表中取ename,從dept表中取dname,沒有條件限制最終查詢結果是?
ENAME DNAME
SMITH ACCOUNTING 無效記錄
SMITH RESEARCH 有效記錄
SMITH SALES 無效記錄
SMITH OPERATIONS 無效記錄
ALLEN ACCOUNTING
ALLEN RESEARCH
ALLEN SALES
ALLEN OPERATIONS
.....
56條記錄。
加個條件是為了達到4選1,也是為了數據的有效性。
select
e.ename,d.dname
from
emp e
join
dept d
on
e.deptno = d.deptno;
加條件只是為了避免笛卡爾積現象,只是為了查詢出有效的組合記錄。
匹配的次數一次都沒有少,還是56次。
2、insert語句可以一次插入多條記錄嗎?【掌握】
可以的!
mysql> desc t_user;
+-------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(32) | YES | | NULL | |
| birth | date | YES | | NULL | |
| create_time | datetime | YES | | NULL | |
+-------------+-------------+------+-----+---------+-------+
一次可以插入多條記錄:
insert into t_user(id,name,birth,create_time) values
(1,'zs','1980-10-11',now()),
(2,'lisi','1981-10-11',now()),
(3,'wangwu','1982-10-11',now());
語法:insert into t_user(字段名1,字段名2) values(),(),(),();
mysql> select * from t_user;
+------+--------+------------+---------------------+
| id | name | birth | create_time |
+------+--------+------------+---------------------+
| 1 | zs | 1980-10-11 | 2020-03-19 09:37:01 |
| 2 | lisi | 1981-10-11 | 2020-03-19 09:37:01 |
| 3 | wangwu | 1982-10-11 | 2020-03-19 09:37:01 |
+------+--------+------------+---------------------+
3、快速創建表?【了解內容】
mysql> create table emp2 as select * from emp;
原理:
將一個查詢結果當做一張表新建!!!!!
這個可以完成表的快速復制!!!!
表創建出來,同時表中的數據也存在了!!!
create table mytable as select empno,ename from emp where job = 'MANAGER';
4、將查詢結果插入到一張表當中?insert相關的!!!【了解內容】
create table dept_bak as select * from dept;
mysql> select * from dept_bak;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
insert into dept_bak select * from dept; //很少用!
mysql> select * from dept_bak;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
5、快速刪除表中的數據?【truncate比較重要,必須掌握】
//刪除dept_bak表中的數據
delete from dept_bak; //這種刪除數據的方式比較慢。
mysql> select * from dept_bak;
Empty set (0.00 sec)
delete語句刪除數據的原理?(delete屬於DML語句!!!)
表中的數據被刪除了,但是這個數據在硬盤上的真實存儲空間不會被釋放!!!
這種刪除缺點是:刪除效率比較低。
這種刪除優點是:支持回滾,后悔了可以再恢復數據!!!
truncate語句刪除數據的原理?
這種刪除效率比較高,表被一次截斷,物理刪除。
這種刪除缺點:不支持回滾。
這種刪除優點:快速。
用法:truncate table dept_bak; (這種操作屬於DDL操作。)
大表非常大,上億條記錄????
刪除的時候,使用delete,也許需要執行1個小時才能刪除完!效率較低。
可以選擇使用truncate刪除表中的數據。只需要不到1秒鍾的時間就刪除結束。效率較高。
但是使用truncate之前,必須仔細詢問客戶是否真的要刪除,並警告刪除之后不可恢復!
truncate是刪除表中的數據,表還在!
刪除表操作?
drop table 表名; // 這不是刪除表中的數據,這是把表刪除。
6、對表結構的增刪改?
什么是對表結構的修改?
添加一個字段,刪除一個字段,修改一個字段!!!
對表結構的修改需要使用:alter
屬於DDL語句
DDL包括:create drop alter
第一:在實際的開發中,需求一旦確定之后,表一旦設計好之后,很少的
進行表結構的修改。因為開發進行中的時候,修改表結構,成本比較高。
修改表的結構,對應的java代碼就需要進行大量的修改。成本是比較高的。
這個責任應該由設計人員來承擔!
第二:由於修改表結構的操作很少,所以我們不需要掌握,如果有一天
真的要修改表結構,你可以使用工具!!!!
修改表結構的操作是不需要寫到java程序中的。實際上也不是java程序員的范疇。
7、約束(非常重要,五顆星*****)
7.1、什么是約束?
約束對應的英語單詞:constraint
在創建表的時候,我們可以給表中的字段加上一些約束,來保證這個表中數據的
完整性、有效性!!!
約束的作用就是為了保證:表中的數據有效!!
7.2、約束包括哪些?
非空約束:not null
唯一性約束: unique
主鍵約束: primary key (簡稱PK)
外鍵約束:foreign key(簡稱FK)
檢查約束:check(mysql不支持,oracle支持)
我們這里重點學習四個約束:
not null
unique
primary key
foreign key
7.3、非空約束:not null
非空約束not null約束的字段不能為NULL。
drop table if exists t_vip;
create table t_vip(
id int,
name varchar(255) not null // not null只有列級約束,沒有表級約束!
);
insert into t_vip(id,name) values(1,'zhangsan');
insert into t_vip(id,name) values(2,'lisi');
insert into t_vip(id) values(3);
ERROR 1364 (HY000): Field 'name' doesn't have a default value
小插曲:
xxxx.sql這種文件被稱為sql腳本文件。
sql腳本文件中編寫了大量的sql語句。
我們執行sql腳本文件的時候,該文件中所有的sql語句會全部執行!
批量的執行SQL語句,可以使用sql腳本文件。
在mysql當中怎么執行sql腳本呢?
mysql> source D:\course\03-MySQL\document\vip.sql
你在實際的工作中,第一天到了公司,項目經理會給你一個xxx.sql文件,
你執行這個腳本文件,你電腦上的數據庫數據就有了!
7.4、唯一性約束: unique
唯一性約束unique約束的字段不能重復,但是可以為NULL。
drop table if exists t_vip;
create table t_vip(
id int,
name varchar(255) unique,
email varchar(255)
);
insert into t_vip(id,name,email) values(1,'zhangsan','zhangsan@123.com');
insert into t_vip(id,name,email) values(2,'lisi','lisi@123.com');
insert into t_vip(id,name,email) values(3,'wangwu','wangwu@123.com');
select * from t_vip;
insert into t_vip(id,name,email) values(4,'wangwu','wangwu@sina.com');
ERROR 1062 (23000): Duplicate entry 'wangwu' for key 'name'
insert into t_vip(id) values(4);
insert into t_vip(id) values(5);
+------+----------+------------------+
| id | name | email |
+------+----------+------------------+
| 1 | zhangsan | zhangsan@123.com |
| 2 | lisi | lisi@123.com |
| 3 | wangwu | wangwu@123.com |
| 4 | NULL | NULL |
| 5 | NULL | NULL |
+------+----------+------------------+
name字段雖然被unique約束了,但是可以為NULL。
新需求:name和email兩個字段聯合起來具有唯一性!!!!
drop table if exists t_vip;
create table t_vip(
id int,
name varchar(255) unique, // 約束直接添加到列后面的,叫做列級約束。
email varchar(255) unique
);
這張表這樣創建是不符合我以上“新需求”的。
這樣創建表示:name具有唯一性,email具有唯一性。各自唯一。
以下這樣的數據是符合我“新需求”的。
但如果采用以上方式創建表的話,肯定創建失敗,因為'zhangsan'和'zhangsan'重復了。
insert into t_vip(id,name,email) values(1,'zhangsan','zhangsan@123.com');
insert into t_vip(id,name,email) values(2,'zhangsan','zhangsan@sina.com');
怎么創建這樣的表,才能符合新需求呢?
drop table if exists t_vip;
create table t_vip(
id int,
name varchar(255),
email varchar(255),
unique(name,email) // 約束沒有添加在列的后面,這種約束被稱為表級約束。
);
insert into t_vip(id,name,email) values(1,'zhangsan','zhangsan@123.com');
insert into t_vip(id,name,email) values(2,'zhangsan','zhangsan@sina.com');
select * from t_vip;
name和email兩個字段聯合起來唯一!!!
insert into t_vip(id,name,email) values(3,'zhangsan','zhangsan@sina.com');
ERROR 1062 (23000): Duplicate entry 'zhangsan-zhangsan@sina.com' for key 'name'
什么時候使用表級約束呢?
需要給多個字段聯合起來添加某一個約束的時候,需要使用表級約束。
unique 和not null可以聯合嗎?
drop table if exists t_vip;
create table t_vip(
id int,
name varchar(255) not null unique
);
mysql> desc t_vip;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(255) | NO | PRI | NULL | |
+-------+--------------+------+-----+---------+-------+
在mysql當中,如果一個字段同時被not null和unique約束的話,
該字段自動變成主鍵字段。(注意:oracle中不一樣!)
insert into t_vip(id,name) values(1,'zhangsan');
insert into t_vip(id,name) values(2,'zhangsan'); //錯誤了:name不能重復
insert into t_vip(id) values(2); //錯誤了:name不能為NULL。
7.5、主鍵約束(primary key,簡稱PK)非常重要五顆星*****
主鍵約束的相關術語?
主鍵約束:就是一種約束。
主鍵字段:該字段上添加了主鍵約束,這樣的字段叫做:主鍵字段
主鍵值:主鍵字段中的每一個值都叫做:主鍵值。
什么是主鍵?有啥用?
主鍵值是每一行記錄的唯一標識。
主鍵值是每一行記錄的身份證號!!!
記住:任何一張表都應該有主鍵,沒有主鍵,表無效!!
主鍵的特征:not null + unique(主鍵值不能是NULL,同時也不能重復!)
怎么給一張表添加主鍵約束呢?
drop table if exists t_vip;
// 1個字段做主鍵,叫做:單一主鍵
create table t_vip(
id int primary key, //列級約束
name varchar(255)
);
insert into t_vip(id,name) values(1,'zhangsan');
insert into t_vip(id,name) values(2,'lisi');
//錯誤:不能重復
insert into t_vip(id,name) values(2,'wangwu');
ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'
//錯誤:不能為NULL
insert into t_vip(name) values('zhaoliu');
ERROR 1364 (HY000): Field 'id' doesn't have a default value
可以這樣添加主鍵嗎,使用表級約束?
drop table if exists t_vip;
create table t_vip(
id int,
name varchar(255),
primary key(id) // 表級約束
);
insert into t_vip(id,name) values(1,'zhangsan');
//錯誤
insert into t_vip(id,name) values(1,'lisi');
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
表級約束主要是給多個字段聯合起來添加約束?
drop table if exists t_vip;
// id和name聯合起來做主鍵:復合主鍵!!!!
create table t_vip(
id int,
name varchar(255),
email varchar(255),
primary key(id,name)
);
insert into t_vip(id,name,email) values(1,'zhangsan','zhangsan@123.com');
insert into t_vip(id,name,email) values(1,'lisi','lisi@123.com');
//錯誤:不能重復
insert into t_vip(id,name,email) values(1,'lisi','lisi@123.com');
ERROR 1062 (23000): Duplicate entry '1-lisi' for key 'PRIMARY'
在實際開發中不建議使用:復合主鍵。建議使用單一主鍵!
因為主鍵值存在的意義就是這行記錄的身份證號,只要意義達到即可,單一主鍵可以做到。
復合主鍵比較復雜,不建議使用!!!
一個表中主鍵約束能加兩個嗎?
drop table if exists t_vip;
create table t_vip(
id int primary key,
name varchar(255) primary key
);
ERROR 1068 (42000): Multiple primary key defined
結論:一張表,主鍵約束只能添加1個。(主鍵只能有1個。)
主鍵值建議使用:
int
bigint
char
等類型。
不建議使用:varchar來做主鍵。主鍵值一般都是數字,一般都是定長的!
主鍵除了:單一主鍵和復合主鍵之外,還可以這樣進行分類?
自然主鍵:主鍵值是一個自然數,和業務沒關系。
業務主鍵:主鍵值和業務緊密關聯,例如拿銀行卡賬號做主鍵值。這就是業務主鍵!
在實際開發中使用業務主鍵多,還是使用自然主鍵多一些?
自然主鍵使用比較多,因為主鍵只要做到不重復就行,不需要有意義。
業務主鍵不好,因為主鍵一旦和業務掛鈎,那么當業務發生變動的時候,
可能會影響到主鍵值,所以業務主鍵不建議使用。盡量使用自然主鍵。
在mysql當中,有一種機制,可以幫助我們自動維護一個主鍵值?
drop table if exists t_vip;
create table t_vip(
id int primary key auto_increment, //auto_increment表示自增,從1開始,以1遞增!
name varchar(255)
);
insert into t_vip(name) values('zhangsan');
insert into t_vip(name) values('zhangsan');
insert into t_vip(name) values('zhangsan');
insert into t_vip(name) values('zhangsan');
insert into t_vip(name) values('zhangsan');
insert into t_vip(name) values('zhangsan');
insert into t_vip(name) values('zhangsan');
insert into t_vip(name) values('zhangsan');
select * from t_vip;
+----+----------+
| id | name |
+----+----------+
| 1 | zhangsan |
| 2 | zhangsan |
| 3 | zhangsan |
| 4 | zhangsan |
| 5 | zhangsan |
| 6 | zhangsan |
| 7 | zhangsan |
| 8 | zhangsan |
+----+----------+
7.6、外鍵約束(foreign key,簡稱FK)非常重要五顆星*****
外鍵約束涉及到的相關術語:
外鍵約束:一種約束(foreign key)
外鍵字段:該字段上添加了外鍵約束
外鍵值:外鍵字段當中的每一個值。
業務背景:
請設計數據庫表,來描述“班級和學生”的信息?
第一種方案:班級和學生存儲在一張表中???
t_student
no(pk) name classno classname
----------------------------------------------------------------------------------
1 jack 100 北京市大興區亦庄鎮第二中學高三1班
2 lucy 100 北京市大興區亦庄鎮第二中學高三1班
3 lilei 100 北京市大興區亦庄鎮第二中學高三1班
4 hanmeimei 100 北京市大興區亦庄鎮第二中學高三1班
5 zhangsan 101 北京市大興區亦庄鎮第二中學高三2班
6 lisi 101 北京市大興區亦庄鎮第二中學高三2班
7 wangwu 101 北京市大興區亦庄鎮第二中學高三2班
8 zhaoliu 101 北京市大興區亦庄鎮第二中學高三2班
分析以上方案的缺點:
數據冗余,空間浪費!!!!
這個設計是比較失敗的!
第二種方案:班級一張表、學生一張表??
t_class 班級表
classno(pk) classname
------------------------------------------------------
100 北京市大興區亦庄鎮第二中學高三1班
101 北京市大興區亦庄鎮第二中學高三1班
t_student 學生表
no(pk) name cno(FK引用t_class這張表的classno)
----------------------------------------------------------------
1 jack 100
2 lucy 100
3 lilei 100
4 hanmeimei 100
5 zhangsan 101
6 lisi 101
7 wangwu 101
8 zhaoliu 101
當cno字段沒有任何約束的時候,可能會導致數據無效。可能出現一個102,但是102班級不存在。
所以為了保證cno字段中的值都是100和101,需要給cno字段添加外鍵約束。
那么:cno字段就是外鍵字段。cno字段中的每一個值都是外鍵值。
注意:
t_class是父表
t_student是子表
刪除表的順序?
先刪子,再刪父。
創建表的順序?
先創建父,再創建子。
刪除數據的順序?
先刪子,再刪父。
插入數據的順序?
先插入父,再插入子。
思考:子表中的外鍵引用的父表中的某個字段,被引用的這個字段必須是主鍵嗎?
不一定是主鍵,但至少具有unique約束。
測試:外鍵可以為NULL嗎?
外鍵值可以為NULL。
8、存儲引擎(了解內容)
8.1、什么是存儲引擎,有什么用呢?
存儲引擎是MySQL中特有的一個術語,其它數據庫中沒有。(Oracle中有,但是不叫這個名字)
存儲引擎這個名字高端大氣上檔次。
實際上存儲引擎是一個表存儲/組織數據的方式。
不同的存儲引擎,表存儲數據的方式不同。
8.2、怎么給表添加/指定“存儲引擎”呢?
show create table t_student;
可以在建表的時候給表指定存儲引擎。
CREATE TABLE `t_student` (
`no` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`cno` int(11) DEFAULT NULL,
PRIMARY KEY (`no`),
KEY `cno` (`cno`),
CONSTRAINT `t_student_ibfk_1` FOREIGN KEY (`cno`) REFERENCES `t_class` (`classno`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8
在建表的時候可以在最后小括號的")"的右邊使用:
ENGINE來指定存儲引擎。
CHARSET來指定這張表的字符編碼方式。
結論:
mysql默認的存儲引擎是:InnoDB
mysql默認的字符編碼方式是:utf8
建表時指定存儲引擎,以及字符編碼方式。
create table t_product(
id int primary key,
name varchar(255)
)engine=InnoDB default charset=gbk;
8.3、怎么查看mysql支持哪些存儲引擎呢?
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.5.36 |
+-----------+
命令: show engines \G
*************************** 1. row ***************************
Engine: FEDERATED
Support: NO
Comment: Federated MySQL storage engine
Transactions: NULL
XA: NULL
Savepoints: NULL
*************************** 2. row ***************************
Engine: MRG_MYISAM
Support: YES
Comment: Collection of identical MyISAM tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 3. row ***************************
Engine: MyISAM
Support: YES
Comment: MyISAM storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 4. row ***************************
Engine: BLACKHOLE
Support: YES
Comment: /dev/null storage engine (anything you write to it disappears
Transactions: NO
XA: NO
Savepoints: NO
*************************** 5. row ***************************
Engine: CSV
Support: YES
Comment: CSV storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 6. row ***************************
Engine: MEMORY
Support: YES
Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 7. row ***************************
Engine: ARCHIVE
Support: YES
Comment: Archive storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 8. row ***************************
Engine: InnoDB
Support: DEFAULT
Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
XA: YES
Savepoints: YES
*************************** 9. row ***************************
Engine: PERFORMANCE_SCHEMA
Support: YES
Comment: Performance Schema
Transactions: NO
XA: NO
Savepoints: NO
mysql支持九大存儲引擎,當前5.5.36支持8個。版本不同支持情況不同。
8.4、關於mysql常用的存儲引擎介紹一下
MyISAM存儲引擎?
它管理的表具有以下特征:
使用三個文件表示每個表:
格式文件 — 存儲表結構的定義(mytable.frm)
數據文件 — 存儲表行的內容(mytable.MYD)
索引文件 — 存儲表上索引(mytable.MYI):索引是一本書的目錄,縮小掃描范圍,提高查詢效率的一種機制。
可被轉換為壓縮、只讀表來節省空間
提示一下:
對於一張表來說,只要是主鍵,
或者加有unique約束的字段上會自動創建索引。
MyISAM存儲引擎特點:
可被轉換為壓縮、只讀表來節省空間
這是這種存儲引擎的優勢!!!!
MyISAM不支持事務機制,安全性低。
InnoDB存儲引擎?
這是mysql默認的存儲引擎,同時也是一個重量級的存儲引擎。
InnoDB支持事務,支持數據庫崩潰后自動恢復機制。
InnoDB存儲引擎最主要的特點是:非常安全。
它管理的表具有下列主要特征:
– 每個 InnoDB 表在數據庫目錄中以.frm 格式文件表示
– InnoDB 表空間 tablespace 被用於存儲表的內容(表空間是一個邏輯名稱。表空間存儲數據+索引。)
– 提供一組用來記錄事務性活動的日志文件
– 用 COMMIT(提交)、SAVEPOINT 及ROLLBACK(回滾)支持事務處理
– 提供全 ACID 兼容
– 在 MySQL 服務器崩潰后提供自動恢復
– 多版本(MVCC)和行級鎖定
– 支持外鍵及引用的完整性,包括級聯刪除和更新
InnoDB最大的特點就是支持事務:
以保證數據的安全。效率不是很高,並且也不能壓縮,不能轉換為只讀,
不能很好的節省存儲空間。
MEMORY存儲引擎?
使用 MEMORY 存儲引擎的表,其數據存儲在內存中,且行的長度固定,
這兩個特點使得 MEMORY 存儲引擎非常快。
MEMORY 存儲引擎管理的表具有下列特征:
– 在數據庫目錄內,每個表均以.frm 格式的文件表示。
– 表數據及索引被存儲在內存中。(目的就是快,查詢快!)
– 表級鎖機制。
– 不能包含 TEXT 或 BLOB 字段。
MEMORY 存儲引擎以前被稱為HEAP 引擎。
MEMORY引擎優點:查詢效率是最高的。不需要和硬盤交互。
MEMORY引擎缺點:不安全,關機之后數據消失。因為數據和索引都是在內存當中。
9、事務(重點:五顆星*****,必須理解,必須掌握)
9.1、什么是事務?
一個事務其實就是一個完整的業務邏輯。
是一個最小的工作單元。不可再分。
什么是一個完整的業務邏輯?
假設轉賬,從A賬戶向B賬戶中轉賬10000.
將A賬戶的錢減去10000(update語句)
將B賬戶的錢加上10000(update語句)
這就是一個完整的業務邏輯。
以上的操作是一個最小的工作單元,要么同時成功,要么同時失敗,不可再分。
這兩個update語句要求必須同時成功或者同時失敗,這樣才能保證錢是正確的。
9.2、只有DML語句才會有事務這一說,其它語句和事務無關!!!
insert
delete
update
只有以上的三個語句和事務有關系,其它都沒有關系。
因為 只有以上的三個語句是數據庫表中數據進行增、刪、改的。
只要你的操作一旦涉及到數據的增、刪、改,那么就一定要考慮安全問題。
數據安全第一位!!!
9.3、假設所有的業務,只要一條DML語句就能完成,還有必要存在事務機制嗎?
正是因為做某件事的時候,需要多條DML語句共同聯合起來才能完成,
所以需要事務的存在。如果任何一件復雜的事兒都能一條DML語句搞定,
那么事務則沒有存在的價值了。
到底什么是事務呢?
說到底,說到本質上,一個事務其實就是多條DML語句同時成功,或者同時失敗!
事務:就是批量的DML語句同時成功,或者同時失敗!
9.4、事務是怎么做到多條DML語句同時成功和同時失敗的呢?
InnoDB存儲引擎:提供一組用來記錄事務性活動的日志文件
事務開啟了:
insert
insert
insert
delete
update
update
update
事務結束了!
在事務的執行過程中,每一條DML的操作都會記錄到“事務性活動的日志文件”中。
在事務的執行過程中,我們可以提交事務,也可以回滾事務。
提交事務?
清空事務性活動的日志文件,將數據全部徹底持久化到數據庫表中。
提交事務標志着,事務的結束。並且是一種全部成功的結束。
回滾事務?
將之前所有的DML操作全部撤銷,並且清空事務性活動的日志文件
回滾事務標志着,事務的結束。並且是一種全部失敗的結束。
9.5、怎么提交事務,怎么回滾事務?
提交事務:commit; 語句
回滾事務:rollback; 語句(回滾永遠都是只能回滾到上一次的提交點!)
事務對應的英語單詞是:transaction
測試一下,在mysql當中默認的事務行為是怎樣的?
mysql默認情況下是支持自動提交事務的。(自動提交)
什么是自動提交?
每執行一條DML語句,則提交一次!
這種自動提交實際上是不符合我們的開發習慣,因為一個業務
通常是需要多條DML語句共同執行才能完成的,為了保證數據
的安全,必須要求同時成功之后再提交,所以不能執行一條
就提交一條。
怎么將mysql的自動提交機制關閉掉呢?
先執行這個命令:start transaction;
演示事務:
---------------------------------回滾事務----------------------------------------
mysql> use bjpowernode;
Database changed
mysql> select * from dept_bak;
Empty set (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into dept_bak values(10,'abc', 'tj');
Query OK, 1 row affected (0.00 sec)
mysql> insert into dept_bak values(10,'abc', 'tj');
Query OK, 1 row affected (0.00 sec)
mysql> select * from dept_bak;
+--------+-------+------+
| DEPTNO | DNAME | LOC |
+--------+-------+------+
| 10 | abc | tj |
| 10 | abc | tj |
+--------+-------+------+
2 rows in set (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from dept_bak;
Empty set (0.00 sec)
---------------------------------提交事務----------------------------------------
mysql> use bjpowernode;
Database changed
mysql> select * from dept_bak;
+--------+-------+------+
| DEPTNO | DNAME | LOC |
+--------+-------+------+
| 10 | abc | bj |
+--------+-------+------+
1 row in set (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into dept_bak values(20,'abc
Query OK, 1 row affected (0.00 sec)
mysql> insert into dept_bak values(20,'abc
Query OK, 1 row affected (0.00 sec)
mysql> insert into dept_bak values(20,'abc
Query OK, 1 row affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
mysql> select * from dept_bak;
+--------+-------+------+
| DEPTNO | DNAME | LOC |
+--------+-------+------+
| 10 | abc | bj |
| 20 | abc | tj |
| 20 | abc | tj |
| 20 | abc | tj |
+--------+-------+------+
4 rows in set (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from dept_bak;
+--------+-------+------+
| DEPTNO | DNAME | LOC |
+--------+-------+------+
| 10 | abc | bj |
| 20 | abc | tj |
| 20 | abc | tj |
| 20 | abc | tj |
+--------+-------+------+
4 rows in set (0.00 sec)
9.6、事務包括4個特性?
A:原子性
說明事務是最小的工作單元。不可再分。
C:一致性
所有事務要求,在同一個事務當中,所有操作必須同時成功,或者同時失敗,
以保證數據的一致性。
I:隔離性
A事務和B事務之間具有一定的隔離。
教室A和教室B之間有一道牆,這道牆就是隔離性。
A事務在操作一張表的時候,另一個事務B也操作這張表會那樣???
D:持久性
事務最終結束的一個保障。事務提交,就相當於將沒有保存到硬盤上的數據
保存到硬盤上!
9.7、重點研究一下事務的隔離性!!!
A教室和B教室中間有一道牆,這道牆可以很厚,也可以很薄。這就是事務的隔離級別。
這道牆越厚,表示隔離級別就越高。
事務和事務之間的隔離級別有哪些呢?4個級別
讀未提交:read uncommitted(最低的隔離級別)《沒有提交就讀到了》
什么是讀未提交?
事務A可以讀取到事務B未提交的數據。
這種隔離級別存在的問題就是:
臟讀現象!(Dirty Read)
我們稱讀到了臟數據。
這種隔離級別一般都是理論上的,大多數的數據庫隔離級別都是二檔起步!
讀已提交:read committed《提交之后才能讀到》
什么是讀已提交?
事務A只能讀取到事務B提交之后的數據。
這種隔離級別解決了什么問題?
解決了臟讀的現象。
這種隔離級別存在什么問題?
不可重復讀取數據。
什么是不可重復讀取數據呢?
在事務開啟之后,第一次讀到的數據是3條,當前事務還沒有
結束,可能第二次再讀取的時候,讀到的數據是4條,3不等於4
稱為不可重復讀取。
這種隔離級別是比較真實的數據,每一次讀到的數據是絕對的真實。
oracle數據庫默認的隔離級別是:read committed
可重復讀:repeatable read《提交之后也讀不到,永遠讀取的都是剛開啟事務時的數據》
什么是可重復讀取?
事務A開啟之后,不管是多久,每一次在事務A中讀取到的數據
都是一致的。即使事務B將數據已經修改,並且提交了,事務A
讀取到的數據還是沒有發生改變,這就是可重復讀。
可重復讀解決了什么問題?
解決了不可重復讀取數據。
可重復讀存在的問題是什么?
可以會出現幻影讀。
每一次讀取到的數據都是幻象。不夠真實!
早晨9點開始開啟了事務,只要事務不結束,到晚上9點,讀到的數據還是那樣!
讀到的是假象。不夠絕對的真實。
mysql中默認的事務隔離級別就是這個!!!!!!!!!!!
序列化/串行化:serializable(最高的隔離級別)
這是最高隔離級別,效率最低。解決了所有的問題。
這種隔離級別表示事務排隊,不能並發!
synchronized,線程同步(事務同步)
每一次讀取到的數據都是最真實的,並且效率是最低的。
9.8、驗證各種隔離級別
查看隔離級別:SELECT @@tx_isolation
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
mysql默認的隔離級別
被測試的表t_user
驗證:read uncommited
mysql> set global transaction isolation level read uncommitted;
事務A 事務B
use bjpowernode;
use bjpowernode;
start transaction;
select * from t_user;
start transaction;
insert into t_user values('zhangsan');
select * from t_user;
驗證:read commited
mysql> set global transaction isolation level read committed;
事務A 事務B
use bjpowernode;
use bjpowernode;
start transaction;
start transaction;
select * from t_user;
insert into t_user values('zhangsan');
select * from t_user;
commit;
select * from t_user;
驗證:repeatable read
mysql> set global transaction isolation level repeatable read;
事務A 事務B
use bjpowernode;
use bjpowernode;
start transaction;
start transaction;
select * from t_user;
insert into t_user values('lisi');
insert into t_user values('wangwu');
commit;
select * from t_user;
驗證:serializable
mysql> set global transaction isolation level serializable;
事務A 事務B
use bjpowernode;
use bjpowernode;
start transaction;
start transaction;
select * from t_user;
insert into t_user values('abc');
select * from t_user;
mysql day04課堂筆記
1、索引(index)
1.1、什么是索引?
索引是在數據庫表的字段上添加的,是為了提高查詢效率存在的一種機制。
一張表的一個字段可以添加一個索引,當然,多個字段聯合起來也可以添加索引。
索引相當於一本書的目錄,是為了縮小掃描范圍而存在的一種機制。
對於一本字典來說,查找某個漢字有兩種方式:
第一種方式:一頁一頁挨着找,直到找到為止,這種查找方式屬於全字典掃描。
效率比較低。
第二種方式:先通過目錄(索引)去定位一個大概的位置,然后直接定位到這個
位置,做局域性掃描,縮小掃描的范圍,快速的查找。這種查找方式屬於通過
索引檢索,效率較高。
t_user
id(idIndex) name(nameIndex) email(emailIndex) address (emailAddressIndex)
----------------------------------------------------------------------------------
1 zhangsan...
2 lisi
3 wangwu
4 zhaoliu
5 hanmeimei
6 jack
select * from t_user where name = 'jack';
以上的這條SQL語句會去name字段上掃描,為什么?
因為查詢條件是:name='jack'
如果name字段上沒有添加索引(目錄),或者說沒有給name字段創建索引,
MySQL會進行全掃描,會將name字段上的每一個值都比對一遍。效率比較低。
MySQL在查詢方面主要就是兩種方式:
第一種方式:全表掃描
第二種方式:根據索引檢索。
注意:
在實際中,漢語字典前面的目錄是排序的,按照a b c d e f....排序,
為什么排序呢?因為只有排序了才會有區間查找這一說!(縮小掃描范圍
其實就是掃描某個區間罷了!)
在mysql數據庫當中索引也是需要排序的,並且這個所以的排序和TreeSet
數據結構相同。TreeSet(TreeMap)底層是一個自平衡的二叉樹!在mysql
當中索引是一個B-Tree數據結構。
遵循左小又大原則存放。采用中序遍歷方式遍歷取數據。
1.2、索引的實現原理?
假設有一張用戶表:t_user
id(PK) name 每一行記錄在硬盤上都有物理存儲編號
----------------------------------------------------------------------------------
100 zhangsan 0x1111
120 lisi 0x2222
99 wangwu 0x8888
88 zhaoliu 0x9999
101 jack 0x6666
55 lucy 0x5555
130 tom 0x7777
提醒1:在任何數據庫當中主鍵上都會自動添加索引對象,id字段上自動有索引,
因為id是PK。另外在mysql當中,一個字段上如果有unique約束的話,也會自動
創建索引對象。
提醒2:在任何數據庫當中,任何一張表的任何一條記錄在硬盤存儲上都有
一個硬盤的物理存儲編號。
提醒3:在mysql當中,索引是一個單獨的對象,不同的存儲引擎以不同的形式
存在,在MyISAM存儲引擎中,索引存儲在一個.MYI文件中。在InnoDB存儲引擎中
索引存儲在一個邏輯名稱叫做tablespace的當中。在MEMORY存儲引擎當中索引
被存儲在內存當中。不管索引存儲在哪里,索引在mysql當中都是一個樹的形式
存在。(自平衡二叉樹:B-Tree)
1.3、在mysql當中,主鍵上,以及unique字段上都會自動添加索引的!!!!
什么條件下,我們會考慮給字段添加索引呢?
條件1:數據量龐大(到底有多么龐大算龐大,這個需要測試,因為每一個硬件環境不同)
條件2:該字段經常出現在where的后面,以條件的形式存在,也就是說這個字段總是被掃描。
條件3:該字段很少的DML(insert delete update)操作。(因為DML之后,索引需要重新排序。)
建議不要隨意添加索引,因為索引也是需要維護的,太多的話反而會降低系統的性能。
建議通過主鍵查詢,建議通過unique約束的字段進行查詢,效率是比較高的。
1.4、索引怎么創建?怎么刪除?語法是什么?
創建索引:
mysql> create index emp_ename_index on emp(ename);
給emp表的ename字段添加索引,起名:emp_ename_index
刪除索引:
mysql> drop index emp_ename_index on emp;
將emp表上的emp_ename_index索引對象刪除。
1.5、在mysql當中,怎么查看一個SQL語句是否使用了索引進行檢索?
mysql> explain select * from emp where ename = 'KING';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | emp | ALL | NULL | NULL | NULL | NULL | 14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
掃描14條記錄:說明沒有使用索引。type=ALL
mysql> create index emp_ename_index on emp(ename);
mysql> explain select * from emp where ename = 'KING';
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------------+
| 1 | SIMPLE | emp | ref | emp_ename_index | emp_ename_index | 33 | const | 1 | Using where |
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------------+
1.6、索引有失效的時候,什么時候索引失效呢?
失效的第1種情況:
select * from emp where ename like '%T';
ename上即使添加了索引,也不會走索引,為什么?
原因是因為模糊匹配當中以“%”開頭了!
盡量避免模糊查詢的時候以“%”開始。
這是一種優化的手段/策略。
mysql> explain select * from emp where ename like '%T';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | emp | ALL | NULL | NULL | NULL | NULL | 14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
失效的第2種情況:
使用or的時候會失效,如果使用or那么要求or兩邊的條件字段都要有
索引,才會走索引,如果其中一邊有一個字段沒有索引,那么另一個
字段上的索引也會實現。所以這就是為什么不建議使用or的原因。
mysql> explain select * from emp where ename = 'KING' or job = 'MANAGER';
+----+-------------+-------+------+-----------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-----------------+------+---------+------+------+-------------+
| 1 | SIMPLE | emp | ALL | emp_ename_index | NULL | NULL | NULL | 14 | Using where |
+----+-------------+-------+------+-----------------+------+---------+------+------+-------------+
失效的第3種情況:
使用復合索引的時候,沒有使用左側的列查找,索引失效
什么是復合索引?
兩個字段,或者更多的字段聯合起來添加一個索引,叫做復合索引。
create index emp_job_sal_index on emp(job,sal);
mysql> explain select * from emp where job = 'MANAGER';
+----+-------------+-------+------+-------------------+-------------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-------------------+-------------------+---------+-------+------+-------------+
| 1 | SIMPLE | emp | ref | emp_job_sal_index | emp_job_sal_index | 30 | const | 3 | Using where |
+----+-------------+-------+------+-------------------+-------------------+---------+-------+------+-------------+
mysql> explain select * from emp where sal = 800;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | emp | ALL | NULL | NULL | NULL | NULL | 14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
失效的第4種情況:
在where當中索引列參加了運算,索引失效。
mysql> create index emp_sal_index on emp(sal);
explain select * from emp where sal = 800;
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
| 1 | SIMPLE | emp | ref | emp_sal_index | emp_sal_index | 9 | const | 1 | Using where |
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
mysql> explain select * from emp where sal+1 = 800;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | emp | ALL | NULL | NULL | NULL | NULL | 14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
失效的第5種情況:
在where當中索引列使用了函數
explain select * from emp where lower(ename) = 'smith';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | emp | ALL | NULL | NULL | NULL | NULL | 14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
失效的第6...
失效的第7...
1.7、索引是各種數據庫進行優化的重要手段。優化的時候優先考慮的因素就是索引。
索引在數據庫當中分了很多類?
單一索引:一個字段上添加索引。
復合索引:兩個字段或者更多的字段上添加索引。
主鍵索引:主鍵上添加索引。
唯一性索引:具有unique約束的字段上添加索引。
.....
注意:唯一性比較弱的字段上添加索引用處不大。
2、視圖(view)
2.1、什么是視圖?
view:站在不同的角度去看待同一份數據。
2.2、怎么創建視圖對象?怎么刪除視圖對象?
表復制:
mysql> create table dept2 as select * from dept;
dept2表中的數據:
mysql> select * from dept2;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
創建視圖對象:
create view dept2_view as select * from dept2;
刪除視圖對象:
drop view dept2_view;
注意:只有DQL語句才能以view的形式創建。
create view view_name as 這里的語句必須是DQL語句;
2.3、用視圖做什么?
我們可以面向視圖對象進行增刪改查,對視圖對象的增刪改查,會導致
原表被操作!(視圖的特點:通過對視圖的操作,會影響到原表數據。)
//面向視圖查詢
select * from dept2_view;
// 面向視圖插入
insert into dept2_view(deptno,dname,loc) values(60,'SALES', 'BEIJING');
// 查詢原表數據
mysql> select * from dept2;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
| 60 | SALES | BEIJING |
+--------+------------+----------+
// 面向視圖刪除
mysql> delete from dept2_view;
// 查詢原表數據
mysql> select * from dept2;
Empty set (0.00 sec)
// 創建視圖對象
create view
emp_dept_view
as
select
e.ename,e.sal,d.dname
from
emp e
join
dept d
on
e.deptno = d.deptno;
// 查詢視圖對象
mysql> select * from emp_dept_view;
+--------+---------+------------+
| ename | sal | dname |
+--------+---------+------------+
| CLARK | 2450.00 | ACCOUNTING |
| KING | 5000.00 | ACCOUNTING |
| MILLER | 1300.00 | ACCOUNTING |
| SMITH | 800.00 | RESEARCH |
| JONES | 2975.00 | RESEARCH |
| SCOTT | 3000.00 | RESEARCH |
| ADAMS | 1100.00 | RESEARCH |
| FORD | 3000.00 | RESEARCH |
| ALLEN | 1600.00 | SALES |
| WARD | 1250.00 | SALES |
| MARTIN | 1250.00 | SALES |
| BLAKE | 2850.00 | SALES |
| TURNER | 1500.00 | SALES |
| JAMES | 950.00 | SALES |
+--------+---------+------------+
// 面向視圖更新
update emp_dept_view set sal = 1000 where dname = 'ACCOUNTING';
// 原表數據被更新
mysql> select * from emp;
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 1000.00 | NULL | 10 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 1000.00 | NULL | 10 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |
| 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1000.00 | NULL | 10 |
+-------+--------+-----------+------+------------+---------+---------+--------+
2.4、視圖對象在實際開發中到底有什么用?《方便,簡化開發,利於維護》
create view
emp_dept_view
as
select
e.ename,e.sal,d.dname
from
emp e
join
dept d
on
e.deptno = d.deptno;
假設有一條非常復雜的SQL語句,而這條SQL語句需要在不同的位置上反復使用。
每一次使用這個sql語句的時候都需要重新編寫,很長,很麻煩,怎么辦?
可以把這條復雜的SQL語句以視圖對象的形式新建。
在需要編寫這條SQL語句的位置直接使用視圖對象,可以大大簡化開發。
並且利於后期的維護,因為修改的時候也只需要修改一個位置就行,只需要
修改視圖對象所映射的SQL語句。
我們以后面向視圖開發的時候,使用視圖的時候可以像使用table一樣。
可以對視圖進行增刪改查等操作。視圖不是在內存當中,視圖對象也是
存儲在硬盤上的,不會消失。
再提醒一下:
視圖對應的語句只能是DQL語句。
但是視圖對象創建完成之后,可以對視圖進行增刪改查等操作。
小插曲:
增刪改查,又叫做:CRUD。
CRUD是在公司中程序員之間溝通的術語。一般我們很少說增刪改查。
一般都說CRUD。
C:Create(增)
R:Retrive(查:檢索)
U:Update(改)
D:Delete(刪)
3、DBA常用命令?
重點掌握:
數據的導入和導出(數據的備份)
其它命令了解一下即可。(這個培訓日志文檔留着,以后忘了,可以打開文檔復制粘貼。)
數據導出?
注意:在windows的dos命令窗口中:
mysqldump bjpowernode>D:\bjpowernode.sql -uroot -p123456
可以導出指定的表嗎?
mysqldump bjpowernode emp>D:\bjpowernode.sql -uroot -p123456
數據導入?
注意:需要先登錄到mysql數據庫服務器上。
然后創建數據庫:create database bjpowernode;
使用數據庫:use bjpowernode
然后初始化數據庫:source D:\bjpowernode.sql
4、數據庫設計三范式
4.1、什么是數據庫設計范式?
數據庫表的設計依據。教你怎么進行數據庫表的設計。
4.2、數據庫設計范式共有?
3個。
第一范式:要求任何一張表必須有主鍵,每一個字段原子性不可再分。
第二范式:建立在第一范式的基礎之上,要求所有非主鍵字段完全依賴主鍵,
不要產生部分依賴。
第三范式:建立在第二范式的基礎之上,要求所有非主鍵字段直接依賴主鍵,
不要產生傳遞依賴。
聲明:三范式是面試官經常問的,所以一定要熟記在心!
設計數據庫表的時候,按照以上的范式進行,可以避免表中數據的冗余,空間的浪費。
4.3、第一范式
最核心,最重要的范式,所有表的設計都需要滿足。
必須有主鍵,並且每一個字段都是原子性不可再分。
學生編號 學生姓名 聯系方式
------------------------------------------
1001 張三 zs@gmail.com,1359999999
1002 李四 ls@gmail.com,13699999999
1001 王五 ww@163.net,13488888888
以上是學生表,滿足第一范式嗎?
不滿足,第一:沒有主鍵。第二:聯系方式可以分為郵箱地址和電話
學生編號(pk) 學生姓名 郵箱地址 聯系電話
----------------------------------------------------
1001 張三 zs@gmail.com 1359999999
1002 李四 ls@gmail.com 13699999999
1003 王五 ww@163.net 13488888888
4.4、第二范式:
建立在第一范式的基礎之上,
要求所有非主鍵字段必須完全依賴主鍵,不要產生部分依賴。
學生編號 學生姓名 教師編號 教師姓名
----------------------------------------------------
1001 張三 001 王老師
1002 李四 002 趙老師
1003 王五 001 王老師
1001 張三 002 趙老師
這張表描述了學生和老師的關系:(1個學生可能有多個老師,1個老師有多個學生)
這是非常典型的:多對多關系!
分析以上的表是否滿足第一范式?
不滿足第一范式。
怎么滿足第一范式呢?修改
學生編號+教師編號(pk) 學生姓名 教師姓名
----------------------------------------------------
1001 001 張三 王老師
1002 002 李四 趙老師
1003 001 王五 王老師
1001 002 張三 趙老師
學生編號 教師編號,兩個字段聯合做主鍵,復合主鍵(PK: 學生編號+教師編號)
經過修改之后,以上的表滿足了第一范式。但是滿足第二范式嗎?
不滿足,“張三”依賴1001,“王老師”依賴001,顯然產生了部分依賴。
產生部分依賴有什么缺點?
數據冗余了。空間浪費了。“張三”重復了,“王老師”重復了。
為了讓以上的表滿足第二范式,你需要這樣設計:
使用三張表來表示多對多的關系!!!!
學生表
學生編號(pk) 學生名字
------------------------------------
1001 張三
1002 李四
1003 王五
教師表
教師編號(pk) 教師姓名
--------------------------------------
001 王老師
002 趙老師
學生教師關系表
id(pk) 學生編號(fk) 教師編號(fk)
------------------------------------------------------
1 1001 001
2 1002 002
3 1003 001
4 1001 002
背口訣:
多對多怎么設計?
多對多,三張表,關系表兩個外鍵!!!!!!!!!!!!!!!
4.5、第三范式
第三范式建立在第二范式的基礎之上
要求所有非主鍵字典必須直接依賴主鍵,不要產生傳遞依賴。
學生編號(PK) 學生姓名 班級編號 班級名稱
---------------------------------------------------------
1001 張三 01 一年一班
1002 李四 02 一年二班
1003 王五 03 一年三班
1004 趙六 03 一年三班
以上表的設計是描述:班級和學生的關系。很顯然是1對多關系!
一個教室中有多個學生。
分析以上表是否滿足第一范式?
滿足第一范式,有主鍵。
分析以上表是否滿足第二范式?
滿足第二范式,因為主鍵不是復合主鍵,沒有產生部分依賴。主鍵是單一主鍵。
分析以上表是否滿足第三范式?
第三范式要求:不要產生傳遞依賴!
一年一班依賴01,01依賴1001,產生了傳遞依賴。
不符合第三范式的要求。產生了數據的冗余。
那么應該怎么設計一對多呢?
班級表:一
班級編號(pk) 班級名稱
----------------------------------------
01 一年一班
02 一年二班
03 一年三班
學生表:多
學生編號(PK) 學生姓名 班級編號(fk)
-------------------------------------------
1001 張三 01
1002 李四 02
1003 王五 03
1004 趙六 03
背口訣:
一對多,兩張表,多的表加外鍵!!!!!!!!!!!!
4.6、總結表的設計?
一對多:
一對多,兩張表,多的表加外鍵!!!!!!!!!!!!
多對多:
多對多,三張表,關系表兩個外鍵!!!!!!!!!!!!!!!
一對一:
一對一放到一張表中不就行了嗎?為啥還要拆分表?
在實際的開發中,可能存在一張表字段太多,太龐大。這個時候要拆分表。
一對一怎么設計?
沒有拆分表之前:一張表
t_user
id login_name login_pwd real_name email address........
---------------------------------------------------------------------------
1 zhangsan 123 張三 zhangsan@xxx
2 lisi 123 李四 lisi@xxx
...
這種龐大的表建議拆分為兩張:
t_login 登錄信息表
id(pk) login_name login_pwd
---------------------------------
1 zhangsan 123
2 lisi 123
t_user 用戶詳細信息表
id(pk) real_name email address........ login_id(fk+unique)
-----------------------------------------------------------------------------------------
100 張三 zhangsan@xxx 1
200 李四 lisi@xxx 2
口訣:一對一,外鍵唯一!!!!!!!!!!
4.7、囑咐一句話:
數據庫設計三范式是理論上的。
實踐和理論有的時候有偏差。
最終的目的都是為了滿足客戶的需求,有的時候會拿冗余換執行速度。
因為在sql當中,表和表之間連接次數越多,效率越低。(笛卡爾積)
有的時候可能會存在冗余,但是為了減少表的連接次數,這樣做也是合理的,
並且對於開發人員來說,sql語句的編寫難度也會降低。
面試的時候把這句話說上:他就不會認為你是初級程序員了!
