1. 程式人生 > >約束條件 ,表與表之間的關系 和多表聯合查詢***

約束條件 ,表與表之間的關系 和多表聯合查詢***

特點 左連接 min 想要 關系型數據庫 高效 行數據 人的 單行

一.約束條件
為了確保數據的完整性 可以給列加上約束條件
完整性的分類:
1.實體完整性
2.域完整性
3.引用完整性
1.實體完整性
實體:即表中的一行(一條)記錄 代表一個實體 entity
實體完整性的作用:標識每一行數據不重復
約束類型:
1.1 主鍵約束(primary key)
1.2 唯一約束(unique)
1.3 自動增長列(auto_increment)
1.1 主鍵約束
每一個表中要有一個主鍵(可以是一列 也可以是多列組成)
特點: 數據唯一 且不能為null

第一種添加方式 在創建表的同時 直接添加主鍵約束
create table 表名(
列名1 列值1 primary key,
列名2 列值2,
....
列名n 列值n
)
第二種添加方式 後期補充主鍵約束
create table 表名(
列名1 列值1,
列名2 列值2,
....
列名n 列值n
)
alter table 表名 add primary key(列名1);

聯合主鍵 (由多個列組成的主鍵)
create table 表名(
列名1 列值1,
列名2 列值2,
....
列名n 列值n,
primary key(列名1,列名2);
)
刪除主鍵約束
alter table 表名 drop primary key;
1.2 唯一約束
特點:數據不能重復 值可以為null
第一種添加方式 在建表的時候添加
create table 表名(
列名1 列值1 約束條件,
列名2 列值2 unique,
....
)
第二種創建方式 後期追加
alter table 表名 add unique(列名);
1.3 自動增長列
mysql --> auto_increment


sqlserver --> idenitiy
oracle --> sequence
特點:
1.設置自動增長的時候 列只能是整型
2.當有行被刪除 自增會繼續自增 在刪除行的基礎上+1
2.域完整性
域完整性的作用:限制此單元格的數據正確 不對照此列的其他單元格
域代表當前單元格
域完整性約束:
數據類型 非空約束(not null) 默認值約束(default)
2.1 數據類型約束
2.2 非空約束
not null
alter table 表名 modify 字段名 字段類型 not null;
2.3 默認值約束
default
第一種添加方式 創建表時添加
create table 表名(
列名1 列值1 約束,
列名2 列值2 約束 default 默認值,
....
列名n 列值n
)
第二種添加方式 後期追加
alter table 表名 alter 列名 set default 默認值;
3.引用完整性
外鍵約束 foreign key

用來約束 表與表之間的關系
建立外鍵關系 首先 明確 主從關系
外鍵一定是在從表中創建 從而找到與主表之間的關系
例:
主表 : 部門表 學生表
從表 : 員工表 分數表
外鍵必須要滿足的條件:
1.至少涉及到兩張表
2.建立外鍵關系 對應列具有相似的數據類型
3.必須建立索引 主鍵 和 外鍵
註意:外鍵是可以有重復的 也可以有空值
創建外鍵的兩種方式
第一種 在創建表的時候 添加外鍵
constraint 外鍵關系名 foreign key(從表的字段) references 主表名(主表的字段)

constraint 外鍵關系名 可以不寫 就是一個外鍵約束的名字 如果不寫 系統會自動給
foreign key(從表的字段) 將 從表中的字段作為外鍵
references 主表名(主表的字段) 映射到主表的字段

CREATE TABLE student(
sid INT
PRIMARY KEY AUTO_INCREMENT,//默認自動增加
sname VARCHAR(10) NOT NULL,//值不能為空
gender VARCHAR(10) DEFAULT "男"
)
CREATE TABLE score(
id INT PRIMARY KEY,
score INT,
fsid INT,
CONSTRAINT fk_student_score FOREIGN KEY(fsid) REFERENCES student(sid)//這裏不加分號也不加逗號
)
第二種 表已經創建 後期追加
alter table 主表 add primary key(主表列名)
alter table 從表 add foreign key(從表列名) references 主表(主表列名)
註意:
1.在從表中添加數據時 外鍵關聯列中存儲的數據 必須是主表中存在的數據
2.想要刪除主表中 正在被從表使用的行 必須先刪除從表 再刪除主表
刪除外鍵關聯:
alter table 表名 drop foreign key 外鍵關系名//就是你起得名字fk_student_score
二.表與表之間的關系
三種關系
1.一對一 1 vs 1
person 表 card 表 人表 和 身份證表
人是主表 身份證表是從表

2.一對多 1 vs N
3.多對多 N vs N
三.多表聯合查詢***
在關系型數據庫中 一個查詢往往會涉及到多張表 多張表如何進行聯合查詢 就成為了學習sql查詢的關鍵
如果單純的只將數據放在一張表中 那麽這個表存在大量的數據冗余 這種數據庫的設計是不合理的(一般不用)
1.合並結果集
union
union all
作用 合並結果集 把兩個select語句的查詢結果合並到一起

CREATE TABLE g(
gname VARCHAR(10),
gage INT
)
CREATE TABLE h(
hname VARCHAR(10),
hage INT
)
INSERT INTO g VALUES("a",1),("b",2),("c",3);
INSERT INTO h VALUES("d",1),("e",2),("c",3);
/*union 去除重復數據 合並*/
SELECT * FROM g UNION SELECT * FROM h;
/*union all 不去除重復數據 合並*/
SELECT * FROM g UNION ALL SELECT * FROM h;

要求:被合並的兩個結果集 列數/列類型 必須相同


2.連接查詢
連接查詢 就是求多個表的乘積
例如 a表 連接 b表 那麽查詢結果就是 a表*b表
連接查詢 產生 笛卡爾積(在sql中 實現方式 交叉連接 cross join)
所有的連接方式 都會先產生笛卡爾積 然後 加上限制條件 才會有實際查詢意義
select * from emp,dept;
join 就是把多個表連接成一個表的手段
多表查詢 分為 內/外連接

SELECT emp.ename,dept.dname,emp.job FROM emp,dept WHERE emp.deptno = dept.deptno;
SELECT e.ename,d.dname,e.job FROM emp AS e,dept AS d WHERE e.deptno = d.deptno;

AS關鍵字 可以給表 起別名 as可省略

內連接 [INNER]join...on INNER可省略
[隱式]
SELECT e.ename,d.dname,e.job FROM emp AS e,dept AS d WHERE e.deptno = d.deptno;
[顯示]
SELECT e.ename,d.dname,e.job FROM emp e INNER join dept d ON e.deptno = d.deptno;
特點: 查詢結果必須是滿足條件的

外連接 [OUTER]join...on OUTER可省略
左外連接 Left [OUTER]join
右外連接 right [OUTER]join
全外連接 full join (Mysql不支持)

左外連接
以左表為主
SELECT * FROM emp e LEFT OUTER JOIN dept d ON e.deptno = d.deptno;
左連接 是先查詢出左表(以左表為主)
然後查詢右表 右表中滿足條件的顯示 不滿足條件的顯示為null
右外連接
以右表為主
SELECT * FROM emp e RIGHT OUTER JOIN dept d ON e.deptno = d.deptno;
右連接 是先查詢出右表(以右表為主)
然後查詢左表 做表中滿足條件的顯示 不滿足條件的顯示為null
/*練習 查詢出 員工姓名 工作 部門 部門所在地 當部門為 RESEARCH 的 不顯示 */
SELECT * FROM emp LEFT JOIN dept ON emp.deptno = dept.deptno WHERE dept.dname!="RESEARCH";
SELECT * FROM emp LEFT JOIN dept ON emp.deptno = dept.deptno AND dept.dname!="RESEARCH" WHERE emp.ename !="SMITH";

/* 步驟
1.生成笛卡爾積 select * from emp cross join dept
2.應用 on 篩選器 emp.deptno = dept.deptno
3.看外連接 是 Left join 還是 right join
如果是 left join 會以左表為主 作為保留表
4.where過濾器 過濾的是 left join 之後的數據
*/
總結:
1.如果sql 用的是Left join
on 後面條件 對left表沒作用 只是對right表起過濾作用
where語句可以對生成臨時表後起到過濾 相當於過濾了 left表
2.如果sql 用的是right join
on 後面條件 對right表沒作用 只是對left表起過濾作用
where語句可以對生成臨時表後起到過濾 相當於過濾了 right表
on 和 where 的區別:
在使用left join時 on 和 where 區別如下:
1.on條件是在 生成臨時表 時 使用的條件
不管on的條件是否為真 都會返回左邊表的數據
2.where條件在 生成臨時表 後 再對臨時表進行過濾
如果條件不為真 就會全部過濾
自然連接 Natural join
自然連接 無需你去給出外鍵關聯等式 它會自動找到這一等式
兩張連接表中 名稱 和 類型 完全一致的列 作為條件

/*自然連接*/
SELECT * FROM emp NATURAL JOIN dept;
SELECT * FROM emp NATURAL LEFT JOIN dept;
SELECT * FROM emp NATURAL RIGHT JOIN dept;
總結:
連接查詢時 sql查詢的核心 按照實際需求來選擇對應的類型
如果選擇不當 非但不能提高效率 反而會帶來一系列的邏輯錯誤 或者性能下降
選擇依據:
1.查兩張表關聯列相等的數據 用內連接
2.right表是left表的子集 用左外連接
3.left表是right表的子集 用右外連接
4.right 和 left 彼此之間有交集 但是互不為子集 使用全外連接
3.子查詢
一個select語句中 包含另一個完整的select語句
子查詢 就是 嵌套查詢
子查詢出現的位置:
where 後: 作為查詢條件的一部分
from 後:作為表出現
當子查詢出現在where後 作為條件時 還可以使用如下關鍵字
any 任意一個 ---> min
all 所有 ---> max
子查詢結果集的形式:
1.單行單列 (用於條件)
2.單行多列 (用於條件)
3.多行單列 (用於條件)
4.多行多列 (表)
1.單行單列 (用於條件)
例如 :員工表中 工資高於CLARK的員工都有誰
分析 :
1.查詢CLARK的工資
select sal from emp where ename="CLARK"
2.查詢高於CLARK的員工
select * from emp where sal > 第一步的結果
3.結論
select * from emp where sal > (select sal from emp where ename="CLARK")

2.單行多列 (用於條件)
例如 :查詢員工表中 工作 和 工資 與 MARTIN完全相同的員工信息
分析 :
1.查詢MARTIN的工作和工資
select job,sal from emp where ename="MARTIN";
2.查詢與MARTIN工作和工資相同的人
select * from emp where (job,sal) in 第一步的結果
3.結論
select * from emp where (job,sal) in (select job,sal from emp where ename="MARTIN")
3.多行單列 (用於條件)
多行子查詢 返回多行數據
在where 使用多行子查詢時 要用 all any in

例如 :查找工資高於30號部門所有人的 員工
分析 :
1.查找30號部門所有人的工資
select sal from emp where deptno=30;
2.查找高於30號部門所有人工資的員工信息
select * from emp where sal > all 第一步的結果
3.結論
SELECT * FROM emp WHERE sal > ALL (SELECT sal FROM emp WHERE deptno=30);

SELECT * FROM emp WHERE sal > ANY (SELECT sal FROM emp WHERE deptno=30);

/*練習 部門編號為20的員工工資 並且 大於部門編號為30的所有人工資的 員工列表*/
SELECT * FROM emp WHERE deptno=20 AND sal> ALL(SELECT sal FROM emp WHERE deptno=30)
4.多行多列 (表)
例如 :查詢員工編號為7788的員工 姓名 工資 部門名稱 部門地址
分析 :涉及到 emp dept兩張表
1.查詢 姓名 和 工資
select ename,sal from emp where empno=7788
2.查詢 部門名稱 和 部門地址
select e.ename,e.sal,d.dname,d.loc
from emp e,dept d
where e.deptno = d.deptno and e.empno=7788
改版:
select e.ename,e.sal,d.dname,d.loc
from emp e,(select dname,loc,deptno from dept) d
where e.deptno = d.deptno and e.empno=7788

/*練習 求7369員工 姓名 經理姓名 經理編號 自己連接自己*/
SELECT e1.ename,e2.ename,e2.empno
FROM emp e1,(SELECT empno,ename FROM emp) e2
WHERE e1.mgr = e2.empno AND e1.empno = 7369

約束條件 ,表與表之間的關系 和多表聯合查詢***