日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

数据库杂谈(五)——关系数据库语言

發布時間:2023/12/9 数据库 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据库杂谈(五)——关系数据库语言 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 5 關系數據庫語言
    • 5.1 MySQL簡介
      • 5.1.1 MySQL的發展歷史
      • 5.1.2 數據庫的用戶接口
      • 5.1.3 SQL及其概念辨析
      • 5.1.4 SQL查詢語言的分類
    • 5.2 入手
      • 5.2.1 回顧——基本和虛表
      • 5.2.2 數據準備
      • 5.2.3 常用命令
      • 5.2.4 導入數據
      • 5.2.5 簡單的查詢
      • 5.2.6 條件查詢
        • 5.2.6.1 條件查詢格式
        • 5.6.2.1 Between and
        • 5.2.6.3 is null
        • 5.2.6.4 or
        • 5.2.6.5 and和or的優先級問題
        • 5.2.6.6 in
        • 5.2.6.7 like
      • 5.2.7 排序
    • 5.3 漸入
      • 5.3.1 分組函數
      • 5.3.2 單行處理函數
      • 5.3.3 回到分組函數
      • 5.3.4 分組
      • 5.3.5 多字段分組查詢
      • 5.3.6 部分limit
      • 5.3.7 小結
    • 5.4 連接查詢
      • 5.4.1 概述
      • 5.4.2 連接查詢分類
      • 5.4.3 連接查詢細講
        • 5.4.3.1 原理
        • 5.4.3.2 等值連接
        • 5.4.3.2 非等值連接
        • 5.4.3.3 自連接
        • 5.4.3.4 外連接
        • 5.4.3.5 全連接
        • 5.4.3.6 多張表做連接
      • 5.4.4 子查詢
        • 5.4.4.1 概述
        • 5.4.4.2 集合成員資格
        • 5.4.4.2 集合的比較
        • 5.4.4.3 from子查詢
      • 5.4.5 謂詞查詢
        • 5.4.5.1 some查詢
        • 5.4.5.2 all查詢
        • 5.4.5.3 空關系測試
        • 5.4.5.4 重復元組存在性測試
        • 5.4.5.5 with 子句
    • 5.5 集合運算
      • 5.5.1 并運算
      • 5.5.2 交運算
      • 5.5.3 差運算
      • 5.5.4 空運算
    • 5.6 表結構
      • 5.5.1 建表和刪表
      • 5.5.2 插入數據
      • 5.5.3 拷貝表
      • 5.5.4 修改表的數據
      • 5.5.5 刪除表中數據
      • 5.5.6 后話
    • 5.7 約束
      • 5.7.1 非空約束
      • 5.7.2 唯一性約束
      • 5.7.3 主鍵約束
      • 5.7.4 外鍵約束
    • 5.8 視圖
    • 5.9 數據庫數據的導入導出
    • 5.10 用戶管理
      • 5.10.1 用戶操作
      • 5.10.2 權限控制

5 關系數據庫語言

在這一小節中,我們將會首先使用MySQL進行我們的講解,而后如果有機會,我會簡單介紹一下SQLserver。

對于MySQL的下載和安裝可以前往MySQL官網進行下載。安裝過程可以參照Win10安裝MySQL詳細教程_蔚來不是夢的博客-CSDN博客_win10安裝mysql進行安裝。

5.1 MySQL簡介

5.1.1 MySQL的發展歷史

1986年發布了SQL-86

1989年發布了SQL-89

然后發布了92、99、03、06、08

在這里特別標明的1986和1989常作為軟件工程師考題而出現,望各位知悉。

5.1.2 數據庫的用戶接口

什么是數據庫的用戶接口?

用戶使用數據庫時對數據庫進行的操作,DBMS要想方設法滿足,其提供的命令和語言就叫用戶和數據庫的接口。DBMS提供多種用戶接口來針對不同的適用人群。其中接口包括:

  • 查詢語言
  • 圖形化工具(GUI)
  • APIs
  • 類庫

5.1.3 SQL及其概念辨析

SQL的概念可以歸結為以下幾點:

  • 結構化查詢語言,是一門標準通用的語言。標準的sql適合于所有的數據庫產品。
  • SQL屬于高級語言,只要能看得懂英語單詞的,寫出來的sql語句,可以讀懂什么意思。
  • SQL語句在執行的時候,實際上內部也會進行編譯,然后再執行sql(sql語句的編譯由DBMS完成。)
  • SQL是一個非過程化的查詢語言

而其和DB和DBMS的區別如下:

  • DB:DataBase(數據庫,數據庫實際上在硬盤上以文件的形式存在)

  • DBMS: DataBase Managemeng System(數據庫管理系統,常見的有:MySQL、Oracle、DB2、Sybase、sqlServer。。。)

5.1.4 SQL查詢語言的分類

SQL按其功能可以分為幾大部分:

  • DDL(數據定義語言):數據定義語言,用于定義、撤銷和修改數據模式,creat、drop、alter。
  • DQL(數據查詢語言):查詢語句,凡是select語句都是DQL。
  • DML(數據操縱語言):用于增刪改數據,insert、delete、update。
  • DCL(數據訪問權限控制語言):用于數據訪問權限的控制。grant授權,revoke撤銷權限。
  • TCL(事務控制):commit提交事務,rollback回滾事務。
  • embeddedSQL and dynamicSQL(嵌入式SQL和動態SQL):嵌入式和動態SQL。其作用是定義SQL語句如何嵌入到通用編程語言內部,如C、C++和java等。

5.2 入手

為了方便上手,我們不會先討論表是怎么創建的,而要先從最簡單卻又最復雜的查詢語句開始講起。但在此之前,我們需要弄懂一些概念,這些概念我們在前面已經簡要提到過,這里稍微回顧一下。

5.2.1 回顧——基本和虛表

我們在前面曾經談論過基表和虛表(視圖)。

基表是真真實實存在的,他的數據顯式地存儲在數據庫中,或者換一種說法就是,你當時存的時候什么樣基表就長什么樣。

而虛表是僅有邏輯定義,可以根據其定義從其他表(包括視圖)中導出,但不作為一個表顯式地存儲在數據庫中。換一種說法就是,比如你數據庫里面已經有個基表了,然后我通過某些要求過濾了一些條件,查詢出來的表就是虛表,虛表實際上不存在數據庫里,他只是通過一些計算和邏輯語言提取出來的。

當基表的模式修改時,通過定義適當的視圖,仍可以為用戶提供修改前的數據模式,避免修改應用程序,從而有利于提高數據的邏輯獨立性。也就是說,即使你基表改了,但是為了視圖還是和以前一樣,我們可以在基表的基礎上做一些其他的操作,使他改變操作后算出來的虛表和之前沒改的虛表一模一樣。

5.2.2 數據準備

在下面的練習中我們會用到大量的查詢操作,但這都是建立在數據庫中有表的基礎上,所以我們會提供數據先建立幾張表。

DROP TABLE IF EXISTS EMP; DROP TABLE IF EXISTS DEPT; DROP TABLE IF EXISTS SALGRADE;CREATE TABLE DEPT(DEPTNO int(2) not null ,DNAME VARCHAR(14) ,LOC VARCHAR(13),primary key (DEPTNO)); CREATE TABLE EMP(EMPNO int(4) not null ,ENAME VARCHAR(10),JOB VARCHAR(9),MGR INT(4),HIREDATE DATE DEFAULT NULL,SAL DOUBLE(7,2),COMM DOUBLE(7,2),primary key (EMPNO),DEPTNO INT(2) );CREATE TABLE SALGRADE( GRADE INT,LOSAL INT,HISAL INT );//插入數據 INSERT INTO DEPT ( DEPTNO, DNAME, LOC ) VALUES ( 10, 'ACCOUNTING', 'NEW YORK'); INSERT INTO DEPT ( DEPTNO, DNAME, LOC ) VALUES ( 20, 'RESEARCH', 'DALLAS'); INSERT INTO DEPT ( DEPTNO, DNAME, LOC ) VALUES ( 30, 'SALES', 'CHICAGO'); INSERT INTO DEPT ( DEPTNO, DNAME, LOC ) VALUES ( 40, 'OPERATIONS', 'BOSTON'); commit;INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7369, 'SMITH', 'CLERK', 7902, '1980-12-17' , 800, NULL, 20); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20' , 1600, 300, 30); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7521, 'WARD', 'SALESMAN', 7698, '1981-02-22' , 1250, 500, 30); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7566, 'JONES', 'MANAGER', 7839, '1981-04-02' , 2975, NULL, 20); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28' , 1250, 1400, 30); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01' , 2850, NULL, 30); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7782, 'CLARK', 'MANAGER', 7839, '1981-06-09' , 2450, NULL, 10); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7788, 'SCOTT', 'ANALYST', 7566, '1987-04-19' , 3000, NULL, 20); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7839, 'KING', 'PRESIDENT', NULL, '1981-11-17' , 5000, NULL, 10); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7844, 'TURNER', 'SALESMAN', 7698, '1981-09-08' , 1500, 0, 30); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7876, 'ADAMS', 'CLERK', 7788, '1987-05-23' , 1100, NULL, 20); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7900, 'JAMES', 'CLERK', 7698, '1981-12-03' , 950, NULL, 30); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7902, 'FORD', 'ANALYST', 7566, '1981-12-03' , 3000, NULL, 20); INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO ) VALUES ( 7934, 'MILLER', 'CLERK', 7782, '1982-01-23' , 1300, NULL, 10); commit;INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES ( 1, 700, 1200); INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES ( 2, 1201, 1400); INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES ( 3, 1401, 2000); INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES ( 4, 2001, 3000); INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES ( 5, 3001, 9999); commit;

在下面,我會教你如何導入這份數據。

需要注意的是,雖然SQL通用,但是建表語句有部分語法是不通用的,所以上面的表數據只適用于MySQL,如果將其導入SQLserver是會報錯的。

在下面的敘述中,我時常會交叉使用用術語字段和屬性,實際上兩個術語指的都是同一件事物。

5.2.3 常用命令

查看當前使用的是哪個數據庫?

select database();

查詢數據庫版本也可以使用

select version();

結束一條語句?

\c

退出mysql?

exit

查看創建表的語句

show create table emp;

5.2.4 導入數據

我們下面會將5.2.2中準備的數據導入MySQL里我們建立的數據庫。如果你是第一次學習,建議跟著我照做即可。

  • 第一步:登錄mysql數據庫管理系統。

  • 第二步:查看有哪些數據庫

    show databases;

    (這個不是sql語句,屬于MySQL命令)

  • 第三步:創建屬于我們自己的數據庫

    Create database bjpowernode;

    (這個不是sql語句,屬于MySQL命令)

  • 第四步:使用bjpowernode數據

    Use bjpowernode;

    (這個不是sql語句,屬于MySQL命令)

  • 第五步:查看當前使用的數據庫有哪些表?

    Show tables;
  • 第六步:初始化數據

    Mysql>source D:\MySQL\bjpowernode.sql(這里source后面跟的是上面sql文件的數據,如果你沒有該文件,建議你打開記事本把5.2.2中的sql復制進去然后重命名為bjpowernode.sql)

當我們使用source進行初始化數據庫后,此時數據庫中有三張表,我們可以使用show table進行查看。

mysql> show tables;
±----------------------+
| Tables_in_bjpowernode |
±----------------------+
| dept |
| emp |
| salgrade |
±----------------------+
3 rows in set (0.00 sec)

5.2.5 簡單的查詢

如果需要刪除一個數據庫

drop database bjpowernode;

如果需要查看一個表的結構

desc 表名

如desc dept;

±-------±------------±-----±----±--------±------+

| Field | Type | Null | Key | Default | Extra |

±-------±------------±-----±----±--------±------+

| DEPTNO | int(2) | NO | PRI | NULL | |(部門編號)

| DNAME | varchar(14) | YES | | NULL | |(部門名稱)

| LOC | varchar(13) | YES | | NULL | | (部門位置)

±-------±------------±-----±----±--------±------+

利用如下代碼可以查詢表中所有數據

select * from 表名

查詢表中數據的語法如下:

Select 字段名1,字段名2,字段名3,…from 表名;

這里需要注意的是,任何一條sql語句都以";"結尾并且sql語句不區分大小寫。在老版的Mysql中如果你一條sql語句不寫分號是會報錯的,但是新版不會報錯。為了養成良好的習慣,我們應該加分號。

比如我們想查看員工的年薪

select ename,sal*12 from emp;

需要注意的是,我們查詢的字段是可以進行運算的,比如上述的sql語句,我想查詢員工表中員工名和薪水,但是我要的是年薪,表中給的是月薪,這時只需要對月薪乘12即可。

對于上面的查詢,我們發現查詢得出的表中年薪的字段是sal* 12。如果對sal*12難受,我們可以重命名

select ename,sal*12 as yearsal from emp;

這里的as是可以省略的。

如果想起中文名也可以

select ename,sal*12 as "年薪" from emp;

需要注意的是,這里用中文單引號和雙引號都可以,但是建議單引號,因為單引號其他數據庫也通用,不然你這里的數據庫可以用其他不能用就會導致很尷尬。

如果要查詢所有的字段,即查看整張表的數據。

select*from emp;

在實際開發中是不推薦使用*的,因為如果一張表的屬性非常多,會導致查出來的數據非常多,這在實際開發中查詢的時候效率十分低下。

對于查詢出來的結果有些可能會重復,此時我們可以用distinct去重

select distinct job from emp;

需要注意的是,distinct關鍵字必須放在所有字段的最前面,因為如果處于中間會導致去重不對等,如

select ename,distinct job from emp;

以上的sql語句是錯誤的,為什么?因為job是去重了,但是ename沒有去重,導致兩條屬性值結果不一樣多。

distinct出現在最前面表示后面的字段聯合起來去重。

如果你想顯式地指明你需要保留重復元組,可以使用all關鍵字,但是保留重復元組是默認的,所以我們在使用中將不會使用all關鍵字。

5.2.6 條件查詢

5.2.6.1 條件查詢格式

條件查詢語法格式如下:

Select 字段,字段…… From 表名 Where 條件;

例如查詢員工表中工資待遇為5000的員工姓名

select ename from emp where sal = 5000 ;

例如想要查看員工名為smith的工資

select sal from emp where ename = 'smith';

不只是中文要加單引號,只要是字符串都要加單引號,不知道是不是字符串可以用desc去查詢表的結構。

如果想要找出工資高于3000的員工

select ename from emp where sal>3000;

如果想要找出工資不等于3000的員工

select ename from emp where sal <> 3000;

如果你學過一些編程語言,也可以用以下的方式:

select ename from emp where sal != 3000;

5.6.2.1 Between and

如果想要找出工資在1100和3000之間的員工,包括1100和3000,可以如下

select ename from emp where sal >=1100 and sal<=3000;

也可以如下

select ename from emp where sal between 1100 and 3000;

這里要注意下,between必須左小右大,并且所劃的區間是閉區間。

Between and 除了可以使用在數字方面之外,還可以使用在字符串方面。

select ename from emp where ename between 'A' and 'D';

這里要注意的是,字符串用between and 取頭字母二十四字母區間,而且所劃區間左閉右開。

5.2.6.3 is null

如果想要找出哪些人沒有津貼,可以如下

select ename,sal,comm from emp where comm is null;

需要注意的是,在sql中NULL不是0,不是一個值,而是代表沒有這個數據,為空。

如果想要找出哪些人的津貼不為空,可以如下

select ename,sal,comm from emp where comm is not null;

5.2.6.4 or

如果想要找出工作崗位是MANAGER和SALESMAN的員工,可以如下

select ename,job from emp where job = 'MAnager' or job ='salesman';

5.2.6.5 and和or的優先級問題

如果我們想要找出薪資大于1000的并且部門編號是20或30部門的員工。可以如下:

select ename,sal,deptno from emp where sal>1000 and deptno=20 or deptno = 30;

這里觀察下表發現,有一項數據出了問題。

±-------±--------±-------+
| ename | sal | deptno |
±-------±--------±-------+
| ALLEN | 1600.00 | 30 |
| WARD | 1250.00 | 30 |
| JONES | 2975.00 | 20 |
| MARTIN | 1250.00 | 30 |
| BLAKE | 2850.00 | 30 |
| SCOTT | 3000.00 | 20 |
| TURNER | 1500.00 | 30 |
| ADAMS | 1100.00 | 20 |
| JAMES | 950.00 | 30 |
| FORD | 3000.00 | 20 |
±-------±--------±-------+

這說明and的運算優先級大于or運算優先級,在實際運用中并不需要記住這些優先級,不確定的優先級直接加小括號括起來先運算即可。即如下所示

mysql> select ename,sal,deptno from emp where sal>1000 and (deptno=20 or deptno = 30);

5.2.6.6 in

在前面我們曾經這樣:找出工作崗位是MANAGER和SALESMAN的員工,當時我們使用的是or。當然,我們可以使用in來解決

select ename,job from emp where job in ('SALESMAN','MANAGER');

需要注意的是,這里in后面的是值集,不是區間。

5.2.6.7 like

找出員工表中員工名字含有o的,可以如下:

select ename from emp where ename like '%o%';

在這里我們需要注意的是,在模糊查詢中需要掌握兩個特殊的符號,一個是%一個是_,%代表匹配任意多個字符, _代表匹配一個字符。

如果我們想要找到名字中第二個字母是A的,可以如下:

select ename from emp where ename like '_a%';

如果要找出名字中有下劃線的,為了避免使用下劃線時被誤判為想要使用匹配字符功能,我們可以在其前面加上轉義字符\。

這里要有個關于數據類型的模糊查詢問題,對于char和varchar,其模糊查詢出來的結果可以有點不一樣。

varchar是可變的,也就是說模糊查詢查的結果就是我們想要的結果;而對于char來說,一旦你設char里容納4個字節而只存放3個字節,那么其余空間將會全部空格補齊。也就是說,用like去查"l_%",那么“ _ ”所匹配的很有可能是空格。

舉個比較簡單的例子,如果我們使用char(3)來存放"劉云"這個名字,那么"like劉_ _"是可以把"云"后面所在的空格也查出來的,也就是說,使用char(3)存放劉云而使用like劉 _ _查詢,是可以把劉云這個結果查出來的。

5.2.7 排序

對于排序,我們先給出一個例子:按照工資排序,找出員工名和薪資。

select ename,sal from emp order by sal;

也就是說,關鍵詞order by后跟想要排序的屬性。但是根據上述給出的sql語句可知,其對sal的排序是一個升序排列。

在排序中,若order by [屬性名] [排序方式]中的排序方式未給出,那么其默認升序。如果需要手動指定升序可以使用asc,而指定降序可以使用desc。

如果我們要按照工資的升序降序排列,當工資相同的時候再按照名字的升序排列。如下所示:

select ename,sal from emp order by sal desc,ename asc;

需要注意的是,這里有必要說一下各個關鍵詞的執行順序:

mysql> select-> 字段 3-> from-> 表名 1-> where-> 條件 2-> order by 4

5.3 漸入

5.3.1 分組函數

SQL中提供了五個固有的聚集函數,分別是:

  • count 計數

  • sum 求和

  • avg 平均值

  • max 最大值

  • min 最小值

需要注意的是,sum和avg的輸入必須是數字值集,而其他函數可以作用在非數字值集上。

在有些書上,也把分組函數叫做聚集函數,其作用是以一個值集作為輸入,返回單個值的函數。而且他還有例外一個名字,叫多行處理函數。多行處理函數的特點就是:輸入多行,最終輸出一行。

既然有多行處理函數,肯定也有一個單行處理函數,也就是,先找到一行,處理一行,然后再繼續下一行。

這么說可能有點模糊,我們在下面的例子中會詳細體會。

我們如果要對津貼做一個統計,我們可以這么干:

select count(comm) from emp;

查出來的結果你試試就知道是4,也就是說,count具有的計數并不是和sum一樣的計算總和的功能,而是統計一個關系中符合條件元組的個數。并且在這里例子中,分組函數是自動忽略NULL的。

我們時常用count來計算一個關系中所有元組的個數,如下所示:

select count(*) from emp;

5.3.2 單行處理函數

單行處理函數和分組函數是相對的,其輸入一行處理一行。對于數據為空的位置來說,如果空數據參與運算,那么算出來的一切結果都會為空。

為此,如果我們想改變這種情況,我們可以用單行處理函數ifnull()來解決,ifnull又叫空處理函數,是單行處理函數的一種,它的作用是把某個字段中所有為null的位置填上自己指定的默認值。

select ename,ifnull(comm,0) as comm from emp;

5.3.3 回到分組函數

分組函數有一個需要注意的點是,我們不能在where關鍵字后跟分組函數,如我們想找出工資高于平均工資的員工:

select avg(sal) from emp where sal>avg(sal);ERROR 1111 (HY000): Invalid use of group function

上面的SQL語句是錯誤的。導致這個的原因實際上是因為在使用分組函數的時候,實際上SQL是先where后分組再分組函數,分組實際上和分組函數沒有啥關系,分組的關鍵字是group by。一般來說分組后才會使用分組函數。

換言之,順序來解釋就是:

select 5 from 1 where 2 group by 3 having 4 order by 6

你可以理解為分組函數的順序是3.5。:happy:

那回到上述問題,我們如何在避免分組函數跟在where后的情況下解決找出工資高于平均工資的員工這個問題?

這時候我們可以使用嵌套子查詢,即n個sql語句可以合成一句來寫。在這里我們先簡單介紹體會一下:

select ename,sal from emp where sal>(select avg(sal) from emp ) ;

5.3.4 分組

既然前面說到group by關鍵字,這一小節肯定是要著重介紹了,與group by一同出場的還有having關鍵字。

前面我們說過,where的執行順序優先于group by,那么當where篩選條件后得出的新關系拿來用group by分組得出新關系2,如果我們想再次做篩選該如何呢?這時候就需要使用having關鍵字了。having關鍵字的作用就是對分組之后的數據進行二次過濾。

如果我們不僅希望分組函數作用于單個元組集上,而且希望將其作用到一組元組集上,用group by這個關鍵字就可以實現。group by用于構造分組,它可以對一個關系中屬性值相同的元組分于一個組中。

要體會group by和having兩者的用處,請隨我看下面的例題:

我們如果要找出每個工作崗位的最高薪資:

select job, max(sal) from emp group by job;

試想,如果在對工資取一個最大數的情況下,如果沒有分組,job該取什么值和這個Max(sal)對應呢?如果對Job分組,那么job就會分成:

job
CLERK
SALESMAN
MANAGER
ANALYST
PRESIDENT

分組完成后會在每個小組中,取一個最大的sal來填入max(sal)的位置。

jobmax(sal)
ANALYST3000.00
CLERK1300.00
MANAGER2975.00
PRESIDENT5000.00
SALESMAN1600.00

這也是為什么分組函數常常聯合使用且名為分組函數的緣故,任何一個分組函數都是在group by語句執行結束之后才會執行的。當一條sql語句沒有group by的話,整張表的數據會自成一組。

你可以理解為:

select avg(sal) from emp; = select avg(sal) from emp group by;

5.3.5 多字段分組查詢

對于多個屬性同時分組,一定要注意一件事:出現在select語句中的但沒有被分組的屬性只能出現在group by。換句話說任何沒有出現在group by子句中的屬性如果出現在select子句中的話,只能出現于分組函數內部。下面我們拿一個十分簡單的例子來說明:

如果我們要找出每個工作崗位的最高工資:

select max(sal),job from emp group by job; #yes select ename,max(sal),job from emp group by job; #no

很明顯,第一條是對的,因為第二條的ename出現在select卻沒有出現在group by中,這就意味著sal通過分組函數分組了,job通過group by關鍵字分組了,就只有ename沒有分組。

以上第二條SQL語句在Oracle數據庫中無法執行,執行報錯。

在SQLserver數據庫總無法執行,執行報錯,報錯提示屬性沒有被聚集。

在Mysql數據庫中可以執行,但是執行結果矛盾。

如果我們想要多個字段分組,我們可以在group by中填上需要分組的屬性,如下面的例子一樣:我們需要找出不同崗位的最高薪資。

select deptno,job,max(sal)fromempgroup bydeptno,job;

5.3.6 部分limit

limit用于分頁查詢,其為MySQL數據庫特有的關鍵字,其他數據庫中沒有,需要注意的是,Oracle中有一個相同的機制,叫做rownum。

limit用于選取集合中的部分數據,它的語法機制為[結果集] limit startIndex , length。其中startIndex表示起始位置,從0開始,length表示取幾個。

讓我們用一個例子來講述上面的知識點:我們想要找出工資排名在第4到第9的員工,我們可以采用下面的方式:

select ename,sal from emp order by sal desc limit 3,6;

5.3.7 小結

在原則上,如果可以在where中過濾的數據,盡量在where中過濾,效率較高。having的過濾是專門對分組之后的數據進行過濾的。這一塊部分實際上涉及到查詢優化的相關知識,在后面,我們會繼續深入探討查詢優化的相關知識。

5.4 連接查詢

5.4.1 概述

在上面的小節中,我們一直都是在對一張表對查詢,可在實際開發中,一個業務一般對應多張表,比如學生和班級,是不可能讓你在一張表查的如此開心的。

有些同學會感覺到疑惑,既然多表聯查如此麻煩,那我們把學生和班級的數據都統一在一張表上不就可以了嗎?但事實是,這涉及到關系數據庫的規范化,如果把數據全部集中在一張表上,那就會造成大量的冗余,比如學生表中的學生都是在一個班上,那么如果兩表合一,就會造成一張表上出現多次同個班級的情況。

5.4.2 連接查詢分類

連接查詢根據年代來劃分可以分為兩種,其中我們普遍在學習的應該是SQL92版本的,而SQL99的版本就比較新穎,語法也比較簡潔明了。

另一種劃分方式是根據連接方式來劃分,如下所示:

  • 內連接
    • 等值連接
    • 非等值連接
    • 自連接
  • 外連接
    • 左外連接(左連接)
    • 右外連接(右連接)
  • 全連接(很少見)

5.4.3 連接查詢細講

5.4.3.1 原理

在SQL中的連接查詢原理和關系代數中的連接查詢原理實際上是一回事,也就是說,同樣是使用加了限制的笛卡爾積。需要注意的是,使用連接查詢看似查詢條數少于笛卡爾積,但是實際上它是先根據多表多笛卡爾積后再篩選符合條件的,所以實際上查詢時間是不會減少的。

5.4.3.2 等值連接

這些術語看似很嚇人,實際上很簡單,就是根據某某條件相等來做連接。需要注意的是,現在在企業中很少有人會用老版的SQL92寫法,而是采用新式SQL99寫法。下面讓我們看看兩者區別如何:

如果我們要找出每一個員工的部門名稱,要求顯示員工名和部門名。采用SQL92寫法如下:

select ENAME ,DNAME from emp e,dept d where e.deptno = d.deptno;

SQL92之所以舍棄,官方的說辭是,where里面寫的是表連接的條件,不是過濾條件,條件結構不清晰。

而在SQL99里,我們這么寫:

select e.ENAME,d.DNAME from emp e (inner) join dept d on e.DEPTNO = d.DEPTNO;

其中inner可寫可不寫,寫出來的好處是協同開發的伙伴能夠看出是內連接,可讀性好。相比于SQL92,SQL99的SQL語法結構更加清晰一些:表的連接條件和where過濾條件分離了。

5.4.3.2 非等值連接

內連接中的非等值連接最大的特點就是:連接條件中的關系是非等量關系。如我們想要找每個員工所處工資等級,并且顯示對應名字和工資。

select e.ename,e.sal,s.grade from emp e join salgrade s on e.sal between s.LOSAL and s.HISAL

所謂的非等值連接,無非就是連接的條件從等價條件轉為非等價條件。

5.4.3.3 自連接

所謂的自連接,就是把自己的一張關系看成兩張,自己連接自己的關系。以題為例:如果我們找出每個員工的上級領導,要求顯示員工名和對應的領導名。【備注:mgr經理,empno工號】

select e.ename "員工名",e2.ename "老板名" from emp e join emp e2 on e.mgr = e2.empno;

5.4.3.4 外連接

在講述完自連接的同時,我們引入了外連接。假設A和B表進行連接,使用內連接的話,凡是A表和B表能夠匹配上的記錄查詢,就是內連接,AB兩張表實際上并沒有主副之分,兩張表是平等的。

而對于外連接,假設A和B表進行連接,使用外連接的話,AB兩張表中一張表是主表,一張表是副表,主要查詢主表匯總的數據,稍等著查詢副表,當副表中的數據沒有和主表中的數據匹配上,副表自動模擬出NULL與之匹配。

外連接主要分為左外連接和右外連接,分別對應左邊的表是主表和右邊的表是主表。而對于左連接和右連接,實際上是相對的,主要看你兩張表哪張放左哪張放右。

讓我們看一下實際的例子:如果我們需要找出每個員工的上級領導,相對于上個例子,我們還要找出最頂級的上司。

由于在上個例子中我們使用的是內連接的方式,所以最上級的領導實際上是不存在的,既然不存在,就匹配不到自己的上級的,既然匹配不出來,那么他對應連接出來的元組是不顯示的。而對于外連接來說,指定員工表作為主表,那么主表的所有元組都會存在于連接的結果中,即使某條元組匹配不到另一張表中對應的元組,它也會用NULL補上。

回到本題的例子,我們可以用左外連接來解決這個問題:

select e.ename "員工名",e2.ename "老板名" from emp e leftoutjoin emp e2 on e.mgr = e2.empno;

5.4.3.5 全連接

對于全連接來說,不僅在開發中即為罕見,在考試中也幾乎不考查,所以我們這里就不做過多講解了。

5.4.3.6 多張表做連接

在使用SQL99的寫法對兩張表做連接時,我們使用的是from 表一 join 表二 on 條件這種寫法,那如果我們要多張表連接呢?我們可以使用A join B join C ... on 條件。其表示的意思是:A表和B表先進行表連接,連接之后A表繼續和C表進行連接。

5.4.4 子查詢

5.4.4.1 概述

SQL中提供嵌套子查詢機制,子查詢是嵌套在另一個查詢中的select-from-where表達式。子查詢嵌套在where子句中,通常用于對集合的成員資格、集合的比較以及集合的基數進行檢查。

上面的表述可以寫為如下形式:

select(select)from(select)where(select)

5.4.4.2 集合成員資格

SQL允許測試元組在關系中的成員資格。在前面的學習中,我們使用in來檢測元組是否為集合中的成員,集合是由select子句產生的一組值構成的,連接詞not in則測試元組是否不是集合中的成員。

讓我們用一個例子來體會這里要講的知識:我們需要找出等于平均薪資的員工信息。在3.3中,我們初次體會到了嵌套子查詢,對于本題來說,實際上就是在測試集合成員資格,我們可以把這個題目歸為以下步驟:

  • 找出員工的平均薪資
  • 找出等于平均薪資的員工
  • 也就是說,我們在找出員工的平均薪資后,用in來判斷所求員工的薪資是否等于符合平均薪資。

    select * from emp where sal = (select avg(sal) from emp); //寫法一 select * from emp where sal in (select avg(sal) from emp);//寫法二

    同樣地,我們也可以用not in來完成找出不等于平均薪資的員工信息。

    5.4.4.2 集合的比較

    集合的比較比較典型的例子是3.3的例子,這里就不再細講了。在這里,我們使用的是where子查詢,意在比對兩個集合。

    select * from emp where sal > (select avg(sal) from emp);

    5.4.4.3 from子查詢

    from子查詢實際上是進行一個套娃的過程,也就是通過某種查詢查詢出一個大表,再從這個大表中進行查詢。

    比較具體的例子是:我們要找出每個部門的平均薪水的薪資等級。

    首先我們可以先按部門編號分組,這樣的話得到是每個部門的平均薪水。

    select deptno,avg(sal) avgsal from emp group by deptno;

    然后我們再將上面查詢出來的大表當做臨時表,讓其和salgrade表做連接,條件是其每個部門平均薪水處于每個薪資等級最高薪水和最低薪水之間。

    select t.*,s.grade from (select DEPTNO ,avg(sal) as avgsal from emp group by DEPTNO) t join salgrade s on t.avgsal between s.LOSAL and s.HISAL;

    5.4.5 謂詞查詢

    謂詞查詢實際上都是應用于集合的比較,通常對應至少、至多等術語。其中集合的獲取可以使用前面講過的子查詢。

    5.4.5.1 some查詢

    some意為至少比某一個如何,如果我們要查詢某某至少比集合內的某一個要大,可以使用>some [集合]來表示。

    在SQL中關鍵詞any同義于some,只不過在早期的版本中僅允許使用ant,后來的版本為了避免和英語中的any一詞在語義上的混淆,又添加了一個可選擇的關鍵詞some。

    5.4.5.2 all查詢

    all意味所有,如果我們要查詢某某比集合內所有的要大,可以使用> all [集合]來表示。

    5.4.5.3 空關系測試

    SQL除了上面兩個謂詞,還可以使用exists來測試子查詢的結果中是否存在所需元組。如果我們要查詢某某存在集合,可以使用exists [集合]來表示。如我們要查找工資為800且名字為史密斯的工作人員信息,我們可以:

    select * from emp where sal = 800 and exists (select * from emp where ename = "SMITH");

    同樣地,如果我們想要表示某某不存在所需集合,可以用not exists [集合]表示。

    從上面的exists來看,其還可以用于且(和)運算。

    5.4.5.4 重復元組存在性測試

    SQL提供一個布爾函數,用于測試在一個子查詢的結果中是否存在重復元組。如果作為參數的子查詢結果中沒有重復的元組,unique將返回true值。

    5.4.5.5 with 子句

    with子句用于建立臨時表,相比于from子查詢,其語法結構更加清晰明了,如:查找銷售員崗位且名字為SIMTH的工作人員信息。

    with SALESMAN as (select * from emp where JOB = "CLERK") select * from emp where ENAME = "SMITH";

    需要注意的是,為臨時表指定名字時,格式并非原名 as 重命名,而是重命名 as 查詢所得表。

    5.5 集合運算

    SQL作用在關系上的union,intersect和except運算對應我們高中數學集合論中學習的∪、∩、?∪、∩、-?運算,在SQL中,這些集合運算都是會對運算結果做自動去重。通過對下面例子的學習,我們能夠更加深入地去了解。

    5.5.1 并運算

    我們都知道,并對應邏輯運算中的或,當我們的題意中有或的字眼時,我們就要考慮使用并運算,其語法規則為集合1 union 集合2如:查找工資為800或者1300的員工名以及工資信息。

    select ename,sal from emp where sal = 800 union select ename,sal from emp where sal = 1300;

    5.5.2 交運算

    交對應邏輯運算的和(且),當我們的題意中有和或者且的字眼時就要考慮用交運算。其語法規則為集合1 intersect 集合2。如:查找工資為800且職位為clerk的員工信息。

    (select * from emp where sal = 800) intersect (select * from emp where job = clerk);

    需要注意的是,在MySQL中是不支持intersect的,由前面所學的知識可知,以上的題目完全可以轉化為以下形式:

    select * from emp where sal = 800 and job = clerk);

    不僅MySQL不支持intersect,現在很多DBMS基本上都不支持。在MySQL中實際上如果真想使用交運算,可以使用過我們在5.4.5.3中學到的exists關鍵字,如本題我們還可以寫為:

    select * from emp where sal = 800 and exists (select * from emp where job = "clerk");

    在前面我們說過,集合運算會對結果自動去重,如果你想不讓其去重,可以使用intersect all。

    5.5.3 差運算

    差對應中文語義中的在...但不在...,其語法規則為集合1 except 集合2如:查找工資為800但職位不是銷售員(SALESMAN)的員工信息。

    select * from emp where sal = 800 except select * from emp where job = salsman;

    同樣地,上面的except在MySQL中同樣不支持,由前面所學知識可知,以上的題目完全可以轉化為以下形式:

    select * from emp where sal = 800 and job!="salesman";

    如果在Oracle,其使用關鍵字minus來代替except。如果想保留所有重復,可以使用except all來代替except。

    5.5.4 空運算

    對于某個值和空值做運算,其實際上是無法運算的,所以為了解決這個問題,除了true和false之外我們引入第三個邏輯值unknown。

    對于and運算來說:true和unknown的結果是unknown,false和unknown結果是false,unknown and unknown結果是unknown。

    對于or來說:true和true or unknown的結果是true,false or unknown結果是unknown,unknown or unknown結果是unknown。

    對于not來說:not unknown的結果是unknown。

    對于SQL來說,我們可以使用關鍵詞null來測試控制,如:查找名為史密斯且其提成為空的員工信息。

    select * from emp where ENAME = "SMITH" and COMM is null

    5.6 表結構

    5.5.1 建表和刪表

    如果我們需要建一個表,我們可以使用如下形式:

    create table 表名(字段名 1 數據類型,字段名 2 數據類型,字段名 3 數據類型,<完整性約束1><完整性約束2>...);

    對于MySQL中字段的數據類型常見的有:

    int整數型(java中的int)
    bigint長整型(java中的long)
    float浮點型(java中的 float double)
    char定長字符串(String)
    varchar可變長字符串(StringBuffer/StringBuilder)
    data日期類型(對應java中的java.sql.data類型)
    BLOB二進制大對象(存儲圖片、視頻等流媒體信息)binary large object(對應java的object)
    CLOB字符大對象(存儲較大文本,比如,可以存儲4G的字符串。)character large object(對應java的object)

    其中容易混淆的兩個數據類型當然是char和varchar了,在5.2.6.7中我們曾經談過此事。他們兩個的區別在于,假如我指定char(6),那么不管我輸入啥字符,只要不超6個空間,它都是給6個空間,但是如果是varchar(6),他是一種智能的類型,能判斷你輸入的字符是占多少個空間(前提是不超6),并且分配對應字符的空間。

    varchar不是一定要使用的,像生日,性別的這種數據字段不發生改變的時候,是定長的,那我們就采用char。而當一個字段的數據長度不確定的時候,例如:簡介、姓名等都是采用varchar。

    在前面的學習中,我們時常發現存儲的數據常常是一些整數啊字符串啊之類的結構化數據,實際上表中數據是可以放一些非結構化的數據比如視頻音樂等。假設有個電影表t_movie

    idname(varchar)playtime(data/char)haibao(BLOB)history(CLOB)
    1 2 3蜘蛛俠 … …

    一般來說,我們不會直接將視頻放到表里面,而是將硬盤里面的路徑放到表里。而圖片就可能會放到表里。

    說完上面的知識點,讓我們來簡單創建一個表吧!如果我們要創建一個學生表,學生信息包括:學號、姓名、性別、班級編號、生日

    • 學號:bigint

    • 姓名:varchar

    • 性別:char

    • 班級編號:int

    • 生日:char

    使用SQL語句我們可以這么創建:

    create table t_student(no bigint,name varchar(255),sex char(1),classno varchar(255),birth char(10));

    創建表的時候可以指定表為NULL時的默認值,如:

    create table t_student(no bigint,name varchar(255),sex char(1) default 1,classno varchar(255),birth char(10));

    如果我們要刪除這個表,可以使用drop table if exists 表名來刪除。

    5.5.2 插入數據

    我們現在需要對這個空表插入幾個數據,插入數據的語法格式為:

    insert into 表名(字段名1,字段名2,字段名3..)values(1,值2,值3)

    需要注意的是:這里要求字段的數量和值的數量相同,并且數據類型要對應相同。

    我們來對上一小節創建的空表添加數據吧!如下所示:

    insert into t_student(no,name,sex,classno,birth)values(1,'BaKa愛','1','gaosan1ban','1950-10-12');

    MySQL為我們提供了簡寫方式:字段名和值能對得上就行,比如表中no字段對應1,你可以寫成:

    insert into t_student(name,sex,classno,birth,no)values('zhangsan','1','gaosan1ban','1950-10-12',2);

    如果表中有(學號、姓名、性別、班級編號、生日)五個字段,如果你只插入一個字段和值,那么其他字段的值為空。

    insert into t_student(name) values('喬峰');

    當一條insert語句執行成功之后,表格當中必然會多一行記錄。即使多的這一行記錄當中某些字段是NULL,后期也無法再執行insert語句插入數據了,只能使用update進行更新。

    也就是說,insert的最小操作單位是元組,不是屬性。

    特別地,如果你寫插入語句,不寫字段名,那么后面的值必須寫滿表所有的字段,一個都不能漏。比如說表中有(學號、姓名、性別、班級編號、生日)五個字段,那么你可以寫:

    insert into t_student values(1,'zhangsan','1','gaosan1ban','1950-10-12');

    字段可以省略不寫,但是后面的value對數量和順序都有要求。

    當然我們也可以多行添加,如:

    insert into t_student(name,sex,classno,birth,no) values ('BaKa愛','1','gaosan1ban','1950-10-12',2), ('喬峰','2','gaosan1ban','1955-09-28',4);

    5.5.3 拷貝表

    如果我們想要把查詢的結果作為一張新表置于數據庫,我們可以使用語法create table 表名 as select 語句來完成這個工作。如:

    create table emp1 as select * from emp;

    這個語法是不是和使用格式with 表名 as 查詢結果來創建臨時表有點相似呢?

    如果我們想要把查詢結果插入另一張表,我們可以使用格式insert into 表名 查詢結果,如:

    insert into dept1 select * from dept;

    5.5.4 修改表的數據

    我們前面說過insert的最小操作單位是元組,也就是說元組一旦插入元組中的屬性就無法修改,如若想修改,就要使用本小節的update關鍵字。其語法格式為:

    update 表名 set 字段名1 =1,字段名2 =2where 條件;

    其中where條件是必須的,否則這條更新語句會根據你修改的東西將表中所有修改的屬性全部更新。如:我們要將前面小節中創建的表中高三二班的字段值改為高三三班。

    update t_student set classno = 'gaosan3ban' where no = 1;

    5.5.5 刪除表中數據

    刪除表中數據的語法格式為:delete from 表名 where 條件,需要注意的是where條件也是必須的,否則表中數據將全被刪除,但是表依然存在。即:數據庫存留一張空表。

    如果需要刪除表我們可以使用5.5.1中講述的drop table if exists 表名進行刪除,需要注意的是此時被刪除的表是可以通過日志回滾來尋回被刪除的表的,如果需要永久刪除表可以使用truncate table 表名。

    5.5.6 后話

    在實際開發中,對于表中的結構去修改實際情況發生概率是很低的,除非在建表的時候你沒有考慮好,而且就算真的結構安排不合理,我們也是可以用工具完成即可。修改表的結構,實際上就是對之前的設計進行了否定。并且在修改表結構的時候,其SQL語句不會出現在java代碼當中。

    5.7 約束

    在5.5.1中我們談論的創建表的格式問題,當時我們并沒有深究完整性約束,只是簡單創建了一張表,那么什么是完整性約束呢?

    在創建表的時候,可以給表的字段添加相應的約束,添加約束的目的是為了保證表中數據的合法性、有效性、完整性。比如登錄QQ賬號,你總不可能密碼為空就能登錄吧?你總不可能QQ賬號是英文的吧?

    讓我們引出下面要敘述的一些約束:

    • 非空約束(not null):結束的字段不能為NULL
    • 唯一約束(unique):約束的字段不能重復
    • 主鍵約束(primary key):約束的字段不能為NULL,也不能重復(簡稱PK)
    • 外鍵約束(foreign key):約束的字段不能為NULL,也不能重復(簡稱FK)
    • 檢查約束(check):控制屬性域

    以上的約束在大多數數據庫是支持的,但是需要注意的是MySQL是沒有check約束的。

    對于約束,我們可以在指定單個字段擁有該約束,也可以指定全局約束。

    5.7.1 非空約束

    我們對單個屬性加上非空約束,用一個例子來說明:

    create table t_user(id int,username varchar(255) not null, //對用戶名采用了非空約束password varchar(255));

    這時候如果插入語句寫了:

    insert into t_user(id,password) values(1,'123');

    那么其會報錯:

    ERROR 1364 (HY000): Field 'username' doesn't have a default value

    5.7.2 唯一性約束

    唯一約束修飾的字段具有唯一性,不能重復,但可以為NULL。因為NULL不是值。如下面為例,我們需要給某字段添加唯一性約束:

    create table t_user(id int,username varchar(255) unique //指定用戶名唯一 );

    當然,我們可以全局指定約束,即所有字段都擁有該約束:

    create table t_user(id int,usercode varchar(255),username varchar(255),unique(usercode,username));

    unique()指的是聯合起來不能重復。也就是新添加的元組要滿足usercode和username和以前添加過的元組不會重復。這種約束我們也叫表級約束。需要注意的是,對于大多數約束來說都擁有表級約束的功能,而非空約束沒有表級約束。

    5.7.3 主鍵約束

    如果我們要指定某個字段作為主鍵,我們只需在其后面添加primary key即可,如:

    drop table if exists t_user;create table t_user(id int primary key,username varchar(255),email varchar(255));

    id是主鍵,因為添加了主鍵約束,主鍵字段中的數據不能為NULL,也不能重復。

    在數據庫雜談(二)中我們談過,一個關系數據庫的表必須要有主鍵,且主鍵具有唯一性和非空性。主鍵充當表中元組的唯一標識,可用于找任何一條元組。

    在實際開發中,主鍵的性質決定了主鍵擁有兩大分類:自然主鍵和業務主鍵。

    • 自然主鍵:主鍵值最好就是一個和業務沒有任何關系的自然數。

    • 業務主鍵:主鍵值和系統的業務掛鉤,比如:銀行卡卡號,身份證號碼(不推薦用)

    上述兩種主鍵中我們并不推薦使用業務主鍵,因為一旦業務改變,主鍵也隨之丟失,舉個例子,銀行卡號報廢,主鍵消失,整條元組也會消失。

    我們可以利用MySQL提供的功能來添加自然主鍵。

    drop table if exists t_user;create table t_user(id int primary key auto_increment, //指定id為自然主鍵username varchar(255));

    當指定id字段為自然主鍵時,MySQL會自動維護一個從1開始遞增的數字作為主鍵值。如下所示:

    mysql> select * from t_user;+----+----------+| id | username |+----+----------+| 1 | a || 2 | b || 3 | c || 4 | d || 5 | e |+----+----------+

    當然,其他DBMS也提供相似的機制,如Oracle當中提供了一個自增機制,叫做序列(sequence),但是我們為了照顧初學者這里不做過多講解。

    5.7.4 外鍵約束

    如果要對某個屬性添加外鍵約束,只需在全局添加foreign key關鍵字即可,如:

    drop table if exists t_student;drop table if exists t_class;create table t_class(cno int,cname varchar(255),primary key(cno));create table t_student(sno int,sname varchar(255),classno int,foreign key(classno) references t_class(cno)//指定classno為外鍵,其對應t_class表中的cno);

    指定外鍵約束后,t_student中的classno字段引用t_class表中的cno字段,此時t_student表叫做子表,t_class表叫做父表。由于classno對cno產生依賴,在對表做操作的時候就有嚴格要求了:

    • 刪除數據的時候,先刪除子表,再刪除父表。

    • 添加數據的時候,先添加父表,再添加子表。

    • 創建表的時候,先創建父表,再創建子表。

    • 刪除表的時候,先刪除子表,再刪除父表。

    5.8 視圖

    我們在這一章的最開始就提到了基表和虛表的概念,實際上視圖就是虛表,視圖是從一個或幾個基本表(或視圖)中導出的虛擬的表。在系統的數據字典中僅存放了視圖的定義,不存放視圖對應的數據。

    數據字典后面我們會做講解,別急。

    那知道了視圖的概念,我們如何創建視圖呢?

    //創建視圖 create view myview as select empno,ename from emp;//刪除視圖 drop view myview;

    既然視圖叫做虛表,那就意味著視圖本質上也是一張表,虛表作為基表的映射。如果我們對虛表進行操作,那么是會反映到基表上的。視圖可以隱蔽表中的實現細節。保密級別較高的系統,數據庫只對外提供相關的視圖,java程序員只對視圖對象進行CRUD。視圖實際上創建后是不會數據冗余的,即不會在硬盤上創建一份視圖。他的原理實際上是查詢改寫。

    5.9 數據庫數據的導入導出

    誒,有些人想說我想把寫的SQL語句全部導出來,要等下拷貝去公司用,那么可以使用下面兩個操作。

    這一小節針對的是程序員而非學生,如果是為了應付考試無需理會該小節。

    導入整個數據庫

    在window的dos命令窗口中執行: mysqldump 數據庫名稱>導出路徑\完整文件名 -u用戶名名稱 -p密碼

    導出指定庫下的某個表

    在window的dos命令窗口中執行: mysqldump 數據庫名稱 表名>導出路徑\完整文件名 -u用戶名名稱 -p密碼

    5.10 用戶管理

    5.10.1 用戶操作

    這一部分實際上作為考試很少考察,但還是需要知道,以防丟分

    查詢用戶

    use mysql select * from user;

    創建用戶

    create user '用戶名'@'主機名' identified by '密碼';

    修改用戶密碼

    alter user '用戶名'@'主機名' identified with mysql_native_password by '新密碼';

    刪除用戶

    drop user '用戶名'@'主機名';

    5.10.2 權限控制

    常見權限表

    權限說明
    all,all privieges所有權限
    select查詢數據
    insert插入數據
    update修改數據
    delete刪除數據
    alter修改表
    drop刪除數據庫/表/視圖
    create創建數據庫/表

    查詢權限

    show grants for '用戶名'@'主機名';

    授予權限

    grant 權限列表 on 數據庫名 表名 to '用戶名'@'主機名';

    撤銷權限

    revoke 權限列表 on 數據庫名.表名 from '用戶名'@'主機名';

    多個權限之間,使用逗號分割;

    授權時,數據庫名和表名可以使用*進行通配,代表所有;

    總結

    以上是生活随笔為你收集整理的数据库杂谈(五)——关系数据库语言的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。