1. 程式人生 > >數據庫 MySQL part3

數據庫 MySQL part3

個學生 rri 上進 返回 cnblogs ron nod 推薦 笛卡爾積

外鍵約束

如果表A的主關鍵字是表B中的字段,則該字段稱為表B的外鍵,表A稱為主表,表B稱為從表。

外鍵是用來實現參照完整性的,不同的外鍵約束方式將可以使兩張表緊密的結合起來,特別是修改或者刪除的級聯操作。外鍵主要用來保證數據的完整性和一致性。

兩個表必須是InnoDB表,MyISAM表暫時不支持外鍵。

外鍵關系的兩個表的列必須是數據類型相似,也就是可以相互轉換類型的列,比如int和tinyint可以,而int和char則不可以。

創建外鍵

#每一個班主任會對應多個學生 , 而每個學生只能對應一個班主任

#主表
CREATE TABLE ClassCharger(
       id TINYINT PRIMARY KEY auto_increment,
       name VARCHAR (20),
       age INT ,
       is_marriged boolean  -- show create table ClassCharger: tinyint(1)
);

INSERT INTO ClassCharger (name,age,is_marriged) VALUES ("冰冰",12,0),
                                                       ("丹丹",14,0),
                                                       ("歪歪",22,0),
                                                       ("姍姍",20,0),
                                                       ("小雨",21,0);


#子表
CREATE TABLE Student(
       id INT PRIMARY KEY auto_increment,
       name VARCHAR (20),
       charger_id TINYINT,     --切記:作為外鍵一定要和關聯主鍵的數據類型保持一致
       -- [ADD CONSTRAINT charger_fk_stu]FOREIGN KEY (charger_id) REFERENCES ClassCharger(id)    #創建關聯

) ENGINE=INNODB;

INSERT INTO Student(name,charger_id) VALUES ("alvin1",2),
                                            ("alvin2",4),
                                            ("alvin3",1),
                                            ("alvin4",3),
                                            ("alvin5",1),
                                            ("alvin6",3),
                                            ("alvin7",2);


DELETE FROM ClassCharger WHERE name="冰冰";
INSERT student (name,charger_id) VALUES ("yuan",1);
-- 刪除居然成功,可是 alvin3顯示還是有班主任id=1的冰冰的;

-----------增加外鍵和刪除外鍵---------
ALTER TABLE student  ADD CONSTRAINT abc
                     FOREIGN KEY(charger_id)
                     REFERENCES  classcharger(id);
ALTER TABLE student DROP FOREIGN KEY abc;

INNODB支持的ON語句

--外鍵約束對子表的含義:   如果在父表中找不到候選鍵,則不允許在子表上進行insert/update
--外鍵約束對父表的含義:    在父表上進行update/delete以更新或刪除在子表中有一條或多條對
                    -- 應匹配行的候選鍵時,父表的行為取決於:在定義子表的外鍵時指定的
                    -- on update/on delete子句

-----------------innodb支持的四種方式---------------------------------------
-----cascade方式 在父表上update/delete記錄時,同步update/delete掉子表的匹配記錄
-----外鍵的級聯刪除:如果父表中的記錄被刪除,則子表中對應的記錄自動被刪除--------

     FOREIGN KEY (charger_id) REFERENCES ClassCharger(id)
                              ON DELETE CASCADE

------set null方式 在父表上update/delete記錄時,將子表上匹配記錄的列設為null
   -- 要註意子表的外鍵列不能為not null

     FOREIGN KEY (charger_id) REFERENCES ClassCharger(id)
                              ON DELETE SET NULL


------Restrict方式 :拒絕對父表進行刪除更新操作(了解)
------No action方式 在mysql中同Restrict,如果子表中有匹配的記錄,則不允許對父表對應候選鍵
   -- 進行update/delete操作(了解)

多表查詢

準備表

-- 準備兩張表
-- company.employee
-- company.department

      create table employee(
      emp_id int auto_increment primary key not null,
      emp_name varchar(50),
      age int,
      dept_id int
      );

      insert into employee(emp_name,age,dept_id) values
        (‘A‘,19,200),
        (‘B‘,26,201),
        (‘C‘,30,201),
        (‘D‘,24,202),
        (‘E‘,20,200),
        (‘F‘,38,204);


    create table department(
       dept_id int,
       dept_name varchar(100)
      );

    insert into department values
      (200,‘人事部‘),
      (201,‘技術部‘),
      (202,‘銷售部‘),
      (203,‘財政部‘);

mysql> select * from employee;
+--------+----------+------+---------+
| emp_id | emp_name | age  | dept_id |
+--------+----------+------+---------+
|      1 | A        |   19 |     200 |
|      2 | B        |   26 |     201 |
|      3 | C        |   30 |     201 |
|      4 | D        |   24 |     202 |
|      5 | E        |   20 |     200 |
|      6 | F        |   38 |     204 |
+--------+----------+------+---------+
6 rows in set (0.00 sec)

mysql> select * from department;
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
|     200 | 人事部    |
|     201 | 技術部    |
|     202 | 銷售部    |
|     203 | 財政部    |
+---------+-----------+
4 rows in set (0.01 sec)

連接查詢

1、迪爾卡積查詢:這種查詢本身是沒有意義的

mysql> SELECT * FROM employee,department;

--        select employee.emp_id,employee.emp_name,employee.age,
--        department.dept_name from employee,department;

+--------+----------+------+---------+---------+-----------+
| emp_id | emp_name | age  | dept_id | dept_id | dept_name |
+--------+----------+------+---------+---------+-----------+
|      1 | A        |   19 |     200 |     200 | 人事部    |
|      1 | A        |   19 |     200 |     201 | 技術部    |
|      1 | A        |   19 |     200 |     202 | 銷售部    |
|      1 | A        |   19 |     200 |     203 | 財政部    |
|      2 | B        |   26 |     201 |     200 | 人事部    |
|      2 | B        |   26 |     201 |     201 | 技術部    |
|      2 | B        |   26 |     201 |     202 | 銷售部    |
|      2 | B        |   26 |     201 |     203 | 財政部    |
|      3 | C        |   30 |     201 |     200 | 人事部    |
|      3 | C        |   30 |     201 |     201 | 技術部    |
|      3 | C        |   30 |     201 |     202 | 銷售部    |
|      3 | C        |   30 |     201 |     203 | 財政部    |
|      4 | D        |   24 |     202 |     200 | 人事部    |
|      4 | D        |   24 |     202 |     201 | 技術部    |
|      4 | D        |   24 |     202 |     202 | 銷售部    |
|      4 | D        |   24 |     202 |     203 | 財政部    |
|      5 | E        |   20 |     200 |     200 | 人事部    |
|      5 | E        |   20 |     200 |     201 | 技術部    |
|      5 | E        |   20 |     200 |     202 | 銷售部    |
|      5 | E        |   20 |     200 |     203 | 財政部    |
|      6 | F        |   38 |     204 |     200 | 人事部    |
|      6 | F        |   38 |     204 |     201 | 技術部    |
|      6 | F        |   38 |     204 |     202 | 銷售部    |
|      6 | F        |   38 |     204 |     203 | 財政部    |
+--------+----------+------+---------+---------+-----------+

2、內連接

-- 查詢兩張表中都有的關聯數據,相當於利用條件從笛卡爾積結果中篩選出了正確的結果。
select * from employee,department where employee.dept_id = department.dept_id;
--select * from employee inner join department on employee.dept_id = department.dept_id;(推薦使用方法)

      +--------+----------+------+---------+---------+-----------+
      | emp_id | emp_name | age  | dept_id | dept_id | dept_name |
      +--------+----------+------+---------+---------+-----------+
      |      1 | A        |   19 |     200 |     200 | 人事部    |
      |      2 | B        |   26 |     201 |     201 | 技術部    |
      |      3 | C        |   30 |     201 |     201 | 技術部    |
      |      4 | D        |   24 |     202 |     202 | 銷售部    |
      |      5 | E        |   20 |     200 |     200 | 人事部    |
      +--------+----------+------+---------+---------+-----------+

3、外連接

--(1)左外連接:在內連接的基礎上增加左邊有右邊沒有的結果

 select * from employee left join department on employee.dept_id = department.dept_id;

     +--------+----------+------+---------+---------+-----------+
    | emp_id | emp_name | age  | dept_id | dept_id | dept_name |
    +--------+----------+------+---------+---------+-----------+
    |      1 | A        |   19 |     200 |     200 | 人事部    |
    |      5 | E        |   20 |     200 |     200 | 人事部    |
    |      2 | B        |   26 |     201 |     201 | 技術部    |
    |      3 | C        |   30 |     201 |     201 | 技術部    |
    |      4 | D        |   24 |     202 |     202 | 銷售部    |
    |      6 | F        |   38 |     204 |    NULL | NULL      |
    +--------+----------+------+---------+---------+-----------+

 --(2)右外連接:在內連接的基礎上增加右邊有左邊沒有的結果

 select * from employee RIGHT JOIN department on employee.dept_id = department.dept_id;

        +--------+----------+------+---------+---------+-----------+
        | emp_id | emp_name | age  | dept_id | dept_id | dept_name |
        +--------+----------+------+---------+---------+-----------+
        |      1 | A        |   19 |     200 |     200 | 人事部    |
        |      2 | B        |   26 |     201 |     201 | 技術部    |
        |      3 | C        |   30 |     201 |     201 | 技術部    |
        |      4 | D        |   24 |     202 |     202 | 銷售部    |
        |      5 | E        |   20 |     200 |     200 | 人事部    |
        |   NULL | NULL     | NULL |    NULL |     203 | 財政部    |
        +--------+----------+------+---------+---------+-----------+

 --(3)全外連接:在內連接的基礎上增加左邊有右邊沒有的和右邊有左邊沒有的結果

    -- mysql不支持全外連接 full JOIN
    -- mysql可以使用此種方式間接實現全外連接
    
   select * from employee RIGHT JOIN department on employee.dept_id = department.dept_id
   UNION
   select * from employee LEFT JOIN department on employee.dept_id = department.dept_id;

        

        +--------+----------+------+---------+---------+-----------+
        | emp_id | emp_name | age  | dept_id | dept_id | dept_name |
        +--------+----------+------+---------+---------+-----------+
        |      1 | A        |   19 |     200 |     200 | 人事部    |
        |      2 | B        |   26 |     201 |     201 | 技術部    |
        |      3 | C        |   30 |     201 |     201 | 技術部    |
        |      4 | D        |   24 |     202 |     202 | 銷售部    |
        |      5 | E        |   20 |     200 |     200 | 人事部    |
        |   NULL | NULL     | NULL |    NULL |     203 | 財政部    |
        |      6 | F        |   38 |     204 |    NULL | NULL      |
        +--------+----------+------+---------+---------+-----------+

      -- 註意 union與union all的區別:union會去掉相同的紀錄

4、復合條件連接查詢

-- 查詢員工年齡大於等於25歲的部門

    SELECT DISTINCT department.dept_name
    FROM employee,department
    WHERE employee.dept_id = department.dept_id
    AND age>25;


--以內連接的方式查詢employee和department表,並且以age字段的升序方式顯示

    select employee.emp_id,employee.emp_name,employee.age,department.dept_name
    from employee,department
    where employee.dept_id = department.dept_id
    order by age asc;

5、子查詢(嵌套查詢)

-- 子查詢是將一個查詢語句嵌套在另一個查詢語句中。
-- 內層查詢語句的查詢結果,可以為外層查詢語句提供查詢條件。
-- 子查詢中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等關鍵字
-- 還可以包含比較運算符:= 、 !=、> 、<等


-- 1. 帶IN關鍵字的子查詢

   ---查詢employee表,但dept_id必須在department表中出現過

   select * from employee
            where dept_id IN
            (select dept_id from department);


+--------+----------+------+---------+
| emp_id | emp_name | age  | dept_id |
+--------+----------+------+---------+
|      1 | A        |   19 |     200 |
|      2 | B        |   26 |     201 |
|      3 | C        |   30 |     201 |
|      4 | D        |   24 |     202 |
|      5 | E        |   20 |     200 |
+--------+----------+------+---------+
5 rows in set (0.01 sec)



-- 2. 帶比較運算符的子查詢
      --      =、!=、>、>=、<、<=、<>

     -- 查詢員工年齡大於等於25歲的部門
     select dept_id,dept_name from department
           where dept_id IN
          (select DISTINCT dept_id from employee where age>=25);

-- 3. 帶EXISTS關鍵字的子查詢

-- EXISTS關字鍵字表示存在。在使用EXISTS關鍵字時,內層查詢語句不返回查詢的記錄。
-- 而是返回一個真假值。Ture或False
-- 當返回Ture時,外層查詢語句將進行查詢;當返回值為False時,外層查詢語句不進行查詢

     select * from employee
              WHERE EXISTS
              (SELECT dept_name from department where dept_id=203);

      --department表中存在dept_id=203,Ture


     select * from employee
                WHERE EXISTS
              (SELECT dept_name from department where dept_id=205);

     -- Empty set (0.00 sec)


    ps:  create table t1(select * from t2);

數據庫 MySQL part3