oracle入門學習總結

數據庫第一天2017/9/4
主鍵 Primary key(PK) 主鍵非空切唯一
外鍵 Foreign Key用來關聯
primary primary primary primary primary primary primary primary primary primary primary




1 數據兩個管理員 sys  system


   登陸system
  (1) sqlplus
system
口令(看不到)
  (2) sqlplus system
        口令(看不到)
  (3) sqlplus system/口令(可見)


   在SQL命令行下
   (1)  conn
          system
  口令(看不到的)
   (2)  conn system
          口令(看不到)
   (3)  conn system/口令(可見)


   登陸sys
   (1)sqlplus / as sysdba
   在SQL命令行下
   (2) conn / as sysdba
  查看當前用戶: show user
  退出當前用戶 quit/exit




  在管理員權限下:
  創建用戶:
  create user 用戶名 identified by 密碼;
  授權:
  grant connect,resource to 用戶名;
  刪除用戶:
  drop user 用戶名 cascade;




  導入sql文件
  1 將會話改成英文(僅在本次登陸有效)
  alter session set nls_date_language = english;
  2 導入sql文件
  @盤符:\文件名.sql;
  如: @D:\oaec.sql;




sys_guid() UUID使用方法36位的


SELECT語句
SELECT 字段名 FROM 表名


查詢該用戶下有哪些表
SELECT table_name FROM user_tables;


查看錶結構
DESC 表名;


查詢表當中所有的信息
SELECT * FROM 表名;


查詢指定信息
SELECT 列名1,列名2 FROM 表名
eg:查詢s_emp表下所有的員工的姓和名
SELECT first_name,last_name FROM s_emp;


算術表達式:+ - * /
操作數值類型
eg:查詢所有員工的年薪
select salary*12 from s_emp;
操作日期類型(僅限加減)
eg:查詢所有員工入職日期的後一天
select start_date+1 from s_emp;




NULL:進行算數運算還是NULL
需要進行空值轉換
空值轉換函數
NVL(列名,數值)
eg:查詢所有員工的提成 沒有提成的顯示0
select first_name,NVL(commission_pct,0)*salary 
from s_emp;
NVL(列名,'字符串')


列的別名
跟在列名後 會默認大寫
eg:將獎金取名爲bonus 查詢出來
select NVL(commission_pct,0)*salary bonus
from s_emp;
如果要加入特殊符號或者小寫,就給別名添加"";
eg:
select NVL(commission_pct,0)*salary "Bonus"
from s_emp;


||連接符
連接之後建議區一個別名
eg:將姓和名取名爲Name 查詢出來
select first_name||'   '||last_name  "Name" 
from s_emp;




DISTINCT 去掉重複項
eg:查詢部門表當中不重複的部門信息
SELECT DISTINCT name FROM s_dept;






ORDER BY子句
必須放在SELECT語句的最後


1)按照列名升序排序
select first_name from s_emp
order by first_name;
2)按照別名進行升序排序
select first_name "Name" from s_emp
order by "Name";
3)按照表達式進行排序
select first_name,salary*12 from s_emp
order by salary*12;
4)按照列號進行排序
select first_name,salary*12 from s_emp
order by 2;


列名後可以跟排序方式 默認是ASC(升序)
DESC(降序)


多列:
SELECT first_name,dept_id,salary
FROM s_emp
ORDER BY dept_id,salary DESC;
先按照部門ID升序排序
如果部門ID相同,就按照薪水降序排序


NULL默認爲最大值




WHERE子句:條件查詢


SELECT 列
FROM 表
WHERE 條件
ORDER BY..;


eg:查詢薪水大於1000的員工姓名
並且按照薪水降序排序
SELECT FIRST_NAME||'  '||LAST_NAME "Name",SALARY
FROM S_EMP
WHERE SALARY>1000
ORDER BY SALARY DESC;








調整列寬
col 列名 format a字符個數;
調整數值顯示位數
col 列名 format 999;(只顯示三位)




WHERE子句


對字符串進行條件限制(注意使用單引號)
eg:求Ben的年薪
SELECT SALARY*12
FROM S_EMP
WHERE FIRST_NAME = 'Ben';


對日期進行限制
Oracle默認日期格式 'DD-MM-YY'
eg:求入職日期 在90年5月1日之後的所有員工
SELECT START_DATE,FIRST_NAME
FROM S_EMP
WHERE START_DATE > '01-5月-90';




WHERE子句關係運算符


BETWEEN...AND...:在。。。。和。。。之間
eg:查詢薪水在1000到1500之間所有員工的姓名
SELECT FIRST_NAME
FROM S_EMP
WHERE SALARY BETWEEN 1000 AND 1500;


IN限定內容,不是區間範圍
eg:查詢薪水爲1000和1400的員工姓名
SELECT FIRST_NAME
FROM S_EMP
WHERE SALARY IN(1000,1400);


LIKE模糊查詢
通配符:
(1)% 0到多個字符 任意個字符 
(2)_ 1個字符 有且僅有一個


eg:查詢名字內包含小寫m的所有人
SELECT FIRST_NAME
FROM S_EMP
WHERE FIRST_NAME LIKE '%m%';


eg:查詢名字第二個字母包含小寫m的所有人
SELECT FIRST_NAME
FROM S_EMP
WHERE FIRST_NAME LIKE '_m%';


查詢以_a開頭的人的姓名
SELECT FIRST_NAME
FROM S_EMP
WHERE FIRST_NAME LIKE '\_a%' ESCAPE '\';


ESCAPE '\';   轉義符
不再將'_'當作通配符來看待


IS NULL判斷是否爲空值
查詢沒有提成的員工姓名
SELECT FIRST_NAME,NVL(COMMISSION_PCT,0)
FROM S_EMP
WHERE COMMISSION_PCT IS NULL;
不可以使用 = 來判斷是否爲空


邏輯運算符
AND  OR  NOT


eg:查詢部門id大於等於41並且薪水大於1300的員工姓名
SELECT FIRST_NAME,SALARY,DEPT_ID
FROM S_EMP
WHERE DEPT_ID >= 41
AND SALARY >1300;
eg:查詢部門id大於等於41或者薪水大於1300的員工姓名
SELECT FIRST_NAME,SALARY,DEPT_ID
FROM S_EMP
WHERE DEPT_ID >= 41
OR SALARY >1300;
eg:查詢部門id不等於41且薪水大於1300的員工姓名
SELECT FIRST_NAME,SALARY,DEPT_ID
FROM S_EMP
WHERE DEPT_ID NOT IN 41
AND SALARY >1300;






/*
  單行函數:
  作用在單條記錄上
  每一行都可以返回一個結果
  可以嵌套
  
  1 字符函數
  UPPER 大寫轉換
  LOWER 小寫轉換
  INITCAP 首字母大寫其餘字母小寫
  LENGTH 字符長度
  SUBSTR 字符截取 第一位是1
  NVL 空值轉換
  
  查詢名字長度大於5的所有員工
  SELECT FIRST_NAME
  FROM S_EMP
  WHERE LENGTH(FIRST_NAME) >= 5;
  
  一般將字符函數用於忽略大小寫的比較
  
  
  數值函數
  ROUND 四捨五入
  TRUNC 截取,不進行四捨五入
  MOD   取餘
  
  ROUND(數值,number)
  number:
  正整數表示保留小數點後number位
  0:取整
  負整數表示保留小數點左邊幾位
  
  SELECT TRUNC(15.193,-1) FROM DUAL;
  結果返回10
  DUAL是一張虛表,可以用來做一些時間查詢
  或者基本的算數計算等
  
  時間函數
  查詢當前時間
  SELECT SYSDATE FROM DUAL;顯示的比較簡單
  SELECT SYSTIMESTAMP FROM DUAL;顯示的比較複雜
  
  MONTH BETWEEN 計算兩個月之前的月數
  如果不是正月數,會返回小數
  SELECT months_between (SYSDATE,'10-10月-17') FROM DUAL;
  
  ADD MONTH 增加月數
  SELECT ADD_MONTHS(SYSDATE,2) FROM DUAL;
  
  NEXT_DAY 指定日期的下一天
  SELECT NEXT_DAY(SYSDATE,'星期一') FROM DUAL;
  
  LAST_DAY 指定日期所在月份的最後一天
  SELECT LAST_DAY(SYSDATE) FROM DUAL;
  
  ROUND(DATE,精確度)
  精確到年:看月份,逢七進位
  精確到月:看天數,逢16進位
  SELECT ROUND('06-9月-17','MONTH') FROM DUAL;  01-9月 -17
  SELECT ROUND('06-9月-17','YEAR') FROM DUAL;   01-1月 -18
  
  轉換函數:
  TO_CHAR將日期轉換爲字符串
  年: YEAR,YYYY
  月: MM
  日: DD
  時: HH24
  分:  MI
  秒: SS
  fm:去掉空格和0
  SELECT TO_CHAR(SYSDATE,'fmYYYY-MM-DD HH24:MI:SS') 
  FROM DUAL;   2017-9-6 10:33:13
  
  
  SELECT LAST_NAME,TO_CHAR(START_DATE,'fmddspth "of" MONTH-YYYY-HH:MI:SS AM') HIREDATE
  FROM S_EMP
  WHERE START_DATE LIKE '%91';
  查詢91年入職員工在該月份第幾天入職;
  
  將數值類型轉換爲字符串
  SELECT TO_CHAR(12,'$0000.00') FROM DUAL;  $0012.00
  SELECT TO_CHAR(12,'L9999.99') FROM DUAL;  ¥12.00


  TO_NUMBER將字符串轉化爲數值
  SELECT TO_NUMBER('1')+2
  from dual;  3
  
  TO_DATE將字符串轉化爲日期
  可以帶格式也可不帶使用默認格式
  SELECT TO_DATE('06-SEP-17')+1
  FROM DUAL;
 */ 
  SELECT TO_DATE('2017-06-12 22:22:22','YYYY-MM-DD HH24:MI:SS')
  FROM DUAL;


/*
   多表查詢:
   1 等價連接 表之間的連接使用“=” 
   如果不鏈接 就會出現笛卡兒積 造成數據的浪費
   會產生大量無意義的數據
   查詢所有的員工姓名和所在部門
   SELECT FIRST_NAME,NAME
   FROM S_EMP,S_DEPT
   WHERE S_EMP.DEPT_ID = S_DEPT.ID;
   
   查詢所有部門名及其所在區域
  SELECT S_DEPT.NAME,S_REGION.NAME
  FROM S_DEPT,S_REGION
  WHERE S_DEPT.REGION_ID = S_REGION.ID;


  SELECT D.NAME,R.NAME
  FROM S_DEPT D,S_REGION R
  WHERE D.REGION_ID = R.ID;
  
  多表查詢,如果出現同名字段,可以使用表名.字段名來區分
  也可以使用別名,但是注意,一旦定義了別名,就必須使用。
  
  查詢所有薪水大於1000的員工的姓名,薪水,屬部門
  SELECT E.FIRST_NAME,E.SALARY,D.NAME
  FROM S_EMP E,S_DEPT D
  WHERE E.DEPT_ID = D.ID
  AND E.SALARY > 1000;
  查詢員工的姓名,部門名,部門所在區域
  SELECT E.FIRST_NAME,D.NAME,R.NAME
  FROM S_DEPT D,S_EMP E,S_REGION R
  WHERE E.DEPT_ID = D.ID
  AND D.REGION_ID = R.ID;
  
  不等價連接
  不使用“=”進行的連接 可以是 > BETWEEN AND  LIKE 等
  
  查詢所有員工姓名 職位 薪水 以及 薪水等級
  SELECT E.FIRST_NAME,E.SALARY,E.TITLE,S.GRADE
  FROM S_EMP E,S_SALGRADE S
  WHERE E.SALARY BETWEEN S.LOSAL AND S.HISAL;
  
  外連接
  查所有的客戶NAME以及客戶對應的銷售人員NAME
  SELECT C.NAME,E.FIRST_NAME
  FROM S_CUSTOMER C,S_EMP E
  WHERE E.ID (+)= C.SALES_REP_ID;
  左外連接 寫在等號右側 顯示左側未匹配項
  右外連接 寫在等號左側 顯示右側未匹配項
  只有oracle數據庫才允許使用(+)來表示左外右外連接
  其他數據庫外連接標準寫法
  SELECT C.NAME,E.FIRST_NAME
  FROM S_CUSTOMER C LEFT JOIN S_EMP E
  ON E.ID = C.SALES_REP_ID;
  全外連接:
  既顯示沒有客戶的員工,也顯示沒有員工的客戶
  SELECT C.NAME,E.FIRST_NAME
  FROM S_CUSTOMER C FULL JOIN S_EMP E
  ON E.ID = C.SALES_REP_ID;
 
  內連接 inner join 作用和等價連接相同 很少使用
  SELECT D.NAME,R.NAME
  FROM S_DEPT D inner join S_REGION R
  on D.REGION_ID = R.ID;
  
  自連接:在一張表中,自己和自己連接
  eg:查詢所有員工和其領導的姓名
  SELECT W.FIRST_NAME,L.FIRST_NAME
  FROM S_EMP W,S_EMP L
  WHERE W.MANAGER_ID = L.ID(+);
*/








/*
  集合運算符
  1 union:並集 把重複的去掉 並且按照查詢的第一列升序排序
  如果 134578
       union
       1364
  結果返回 1345678
  左外連接union右外連接 = 全連接
  SELECT E.FIRST_NAME,C.NAME
  FROM S_EMP E FULL JOIN S_CUSTOMER C
  ON E.ID = C.SALES_REP_ID;


  SELECT E.FIRST_NAME,C.NAME
  FROM S_EMP E LEFT JOIN S_CUSTOMER C
  ON E.ID = C.SALES_REP_ID
  UNION
  SELECT E.FIRST_NAME,C.NAME
  FROM S_EMP E RIGHT JOIN S_CUSTOMER C
  ON E.ID = C.SALES_REP_ID;
  
  UNION ALL 既不去掉重複的,也不進行排序
  SELECT E.FIRST_NAME,C.NAME
  FROM S_EMP E LEFT JOIN S_CUSTOMER C
  ON E.ID = C.SALES_REP_ID
  UNION ALL
  SELECT E.FIRST_NAME,C.NAME
  FROM S_EMP E RIGHT JOIN S_CUSTOMER C
  ON E.ID = C.SALES_REP_ID;
  
  MINUS 差操作 第一個結果集減去第二個結果集(公共部分)
  按照第一列升序排序
  
  rownum:代表行數
  查詢前10條數據
  select * from s_emp
  where rownum <= 10
  查詢第五條到第十條的數據
  select * from s_emp
  where rownum <= 10
  minus
  select * from s_emp
  where rownum <= 5;
  
  INTERSECT 取交集 按照第一列升序排序
  查詢1-5條數據
  select * from s_emp
  where rownum <= 10
  INTERSECT
  select * from s_emp
  where rownum <= 5;
  
  組函數:作用於一組數據,返回一個結果
  常見 AVG()  MAX() MIN() SUM() COUNT()
  ALL 統計全部的
  DISTINCT 統計不重複的
  查詢所有員工的 平均工資 工資和 最小工資 最大工資
  SELECT AVG(SALARY),SUM(SALARY),MIN(SALARY),MAX(SALARY)
  FROM S_EMP;
  查詢字母最大的員工和最小員工的姓名
  SELECT MAX(FIRST_NAME),MIN(FIRST_NAME)
  FROM S_EMP;
  
  COUNT(字段名/*)統計次數
  COUNT(字段數) 不計算空的列,統計總數據不靠譜
  COUNT(*) 統計全部數據 包含空值
  統計有提成的員工數量
  SELECT COUNT(COMMISSION_PCT)
  FROM S_EMP;
  統計全部員工數量
  SELECT COUNT(*)
  FROM S_EMP;
  
  可以操作字符串 日期 數值類型的:MAX() MIN() COUNT()
  只能操作數值的: SUM() AVG()
*/








/*
GROUP BY 子句
以。。。分組


查詢每個部門薪水最高是多少
SELECT MAX(SALARY),DEPT_ID
FROM S_EMP
GROUP BY DEPT_ID;


錯誤1:ORA-00979 不是 GROUP BY 表達式
SELECT語句中出現的字段必須出現在GROUP BY子句中
SELECT MAX(SALARY),FIRST_NAME
FROM S_EMP
GROUP BY DEPT_ID;




錯誤2 ORA-00934: 此處不允許使用分組函數
組函數不可以和WHERE子句配合使用
SELECT MAX(SALARY),DEPT_ID
FROM S_EMP
WHERE MAX(SALARY) >1000
GROUP BY DEPT_ID;


查詢語句中如果有組函數,那麼查詢的列
要麼是組函數,要麼是被分組的列


HAVING子句 寫在GROUP BY 子句之後
對GROUP BY子句做出限制
查詢最大薪水大於1400的所有部門編號,並升序排序
SELECT MAX(SALARY),DEPT_ID
FROM S_EMP
GROUP BY DEPT_ID
HAVING MAX(SALARY) >1400
ORDER BY DEPT_ID;


執行順序: 1.WHERE->2.GROUP BY->3.HAVING->4.ORDER BY


S_ORDER訂單表
S_ITEM訂單明細表
1 統計每一個訂單的訂單明細數量
SELECT ORD_ID,COUNT(*)
FROM S_ITEM
GROUP BY ORD_ID;
2 查詢訂單號對應的訂單明細數量及總額
SELECT ORD_ID,COUNT(*),SUM(PRICE)
FROM S_ITEM
GROUP BY ORD_ID;


子查詢:
查詢部門編號是41的所有員工姓名及部門編號
SELECT FIRST_NAME,DEPT_ID
FROM S_EMP
WHERE DEPT_ID = 41;
查詢LaDoris所在部門的所有員工姓名及部門編號
第一步:查詢LaDoris所在的部門編號
第二步:根據查到的部門ID進行信息匹配
SELECT FIRST_NAME,DEPT_ID
FROM S_EMP
WHERE DEPT_ID = (
  SELECT DEPT_ID
  FROM S_EMP
  WHERE FIRST_NAME = 'LaDoris'
);
子查詢是一個完整的select語句
外圍可以跟SELECT INSERT CREATETABLE
如果外圍是SELECT
子查詢可以寫在WHERE/HAVING/FROM


查詢和Patel(last_name)同一個部門的所有人員信息及部門id
SELECT LAST_NAME,DEPT_ID
FROM S_EMP
WHERE DEPT_ID IN (
  SELECT DEPT_ID
  FROM S_EMP
  WHERE LOWER(LAST_NAME) = 'patel'
);
如果子查詢就產生一個結果使用“=”
如果產生了多個結果使用關鍵字IN


查詢薪水高於平均工資的員工姓名
SELECT FIRST_NAME,SALARY
FROM S_EMP
WHERE SALARY > (
  SELECT AVG(SALARY)
  FROM S_EMP
);
使用子查詢可以解決組函數和WHERE子句不兼容的問題


子查詢配合HAVING子句:
查詢平均薪水大於41號部門平均薪水所有部門ID
SELECT DEPT_ID,AVG(SALARY)
FROM S_EMP
GROUP BY DEPT_ID
HAVING AVG(SALARY) > (
    SELECT AVG(SALARY)
    FROM S_EMP
    WHERE DEPT_ID =41
);
子查詢配合FROM使用
查詢第5到10條數據
SELECT R,FIRST_NAME
FROM (
  SELECT ROWNUM R,FIRST_NAME
  FROM S_EMP
)
WHERE R BETWEEN 5 AND 10;
主查詢可以引用子查詢的數據


子查詢也可以引用主查詢的字段
查詢薪水高於其領導的所有員工姓名
方式1 使用自連接
SELECT E1.SALARY,E1.FIRST_NAME,E2.SALARY,E2.FIRST_NAME
FROM S_EMP E1,S_EMP E2
WHERE E1.MANAGER_ID = E2.ID
AND E1.SALARY > E2.SALARY;
方式二:使用子查詢
SELECT SALARY,FIRST_NAME
FROM S_EMP E
WHERE E.SALARY > (
  SELECT SALARY
  FROM S_EMP
  WHERE E.MANAGER_ID = ID
);
*/






數據類型
varchar2(size)  Variable length character values可變字符串長度
char(size) Fixed length character values 固定字符串長度默認長度爲1
number Floating point numbers 整形參數有兩個(第一個正數的,第二個小數的長度)
date Date and time values 時間類型長度
長類型的 字符串
clob Variable length character values up to 2GB 
blob Variable length character for binary data








第六天


/*
實體:一些數據表 類似於java當中的類
屬性:表中的列 類似於java當中的屬性
關係:表與表之間的關係(實體之間的關係)
一對一:人和護照 外鍵放在任意一側都可以
如果一側實線一側虛線 外鍵放在實線一側
一對多:銷售人員和客戶 外鍵放到多的那一側
多對多:老師和學生 
第一種方式:將多對多拆分爲多個一對多
第二種方式:建立一張橋表,引用兩個表的主鍵作爲聯合主鍵
間接實現兩張表的連接


完整性約束:5個
主鍵 primary key  PK 
一張表當中只能有一個主鍵 非空且唯一
如果是聯合主鍵 聯合唯一,單列非空
代理主鍵:一般來說是數值類型 沒有具體意義
代表的唯一的一行數據,推薦使用
自然主鍵:本身就具有意義的數據,有可能會被修改
不推薦使用


外鍵 foreign key FK
可以是一列,也可以是多列,值可以爲空,來源於其他表的
主鍵列或者唯一項 ,如果外鍵作爲聯合主鍵存在,則不可以
爲空


非空 not null


唯一 unique


自定義約束 check




DDL語句
1CREATE語句
CREATE TABLE 表名(
   列名1  數據類型(長度) 約束,
   列名2  數據類型(長度) 約束,
   列名3  數據類型(長度) 約束
);


命名規則:
以字母開頭,多個單詞用“_”分割
組成:字母 數字 下劃線 美元符 #
不能使用系統關鍵字,不可以出現同名表


數據類型:
字符串:
VARVHAR2  變長字符串:varrchar2(20)
CHAR      定長字符串char(20)
數值型;
NUMBER   NUMBER(10)  NUMBER(10,2)
時間型:
DATE


CLOB:大字符串
BLOB:大二進制數據




約束:表級別約束,列級別約束
如果約束自動創建,約束名就爲SYS_.....
建議給約束起名 使用關鍵字CONSTRAINT
默認格式最好爲:表名_列名_約束簡寫


create table teacher(
  id number(10) CONSTRAINT TEACHER_ID_PK primary key,
  name varchar2(40) CONSTRAINT TEACHER_NAME_NN not null,
  sex varchar2(10)  CONSTRAINT TEACHAER_SEX_CK CHECK(sex in('男','女')),
  age number(20) CONSTRAINT TEACHER_AGE_CK CHECK(age < 150 AND age >0)
)
*/


drop table teacher;


/*
  學科表
  ID  學科ID
  NAME 學科名
*/
create table TEST_SUBJECT(
  ID NUMBER(10) CONSTRAINT TEST_SUBJECT_ID_PK PRIMARY KEY,
  NAME VARCHAR2(40) CONSTRAINT TEST_SUBJECT_NAME_NN NOT NULL
)
/*
  老師表
  id  主鍵 代表老師的id
  name 非空
  sex  限制
  age  限制
  subject_id 學科id
*/
create table teacer(
  id number(10) CONSTRAINT TEACHER_ID_PK primary key,
  name varchar2(40) CONSTRAINT TEACHER_NAME_NN not null,
  sex varchar2(10)  CONSTRAINT TEACHAER_SEX_CK CHECK(sex in('男','女')),
  age number(20) CONSTRAINT TEACHER_AGE_CK CHECK(age < 150 AND age >0),
  subject_id number(20) CONSTRAINT TEACHER_SUBJECT_ID_FK REFERENCES TEST_SUBJECT(ID)
)








drop table teacher;




/*
  學科表
  ID  學科ID
  NAME 學科名
*/


create table TEST_SUBJECT(
 
ID NUMBER(10) CONSTRAINT TEST_SUBJECT_ID_PK PRIMARY KEY,

 NAME VARCHAR2(40) CONSTRAINT TEST_SUBJECT_NAME_NN NOT NULL


)


/*
  老師表
  id  主鍵 代表老師的id
  name 非空
  sex  限制
  age  限制
  subject_id 學科id
*/
create table teacher(


  id number(10) CONSTRAINT TEACHER_ID_PK primary key,
 
  name varchar2(40) CONSTRAINT TEACHER_NAME_NN not null,


  sex varchar2(10)  CONSTRAINT TEACHAER_SEX_CK CHECK(sex in('男','女')),


  age number(20) CONSTRAINT TEACHER_AGE_CK CHECK(age < 150 AND age >0),


  subject_id number(20) CONSTRAINT TEACHER_SUBJECT_ID_FK REFERENCES TEST_SUBJECT(ID)


)
/*
  
約束:
  1 列級別約束
  直接定義在列名後,約束和列名之間沒有逗號間隔
  2 表級別約束
  在列名定義後,約束和表通過逗號隔開的
 NOT NULL只能用於列級別,不能用於表級別,其他約束在
列級別和表級別上均可定義 約束(包括聯合主鍵,聯合外鍵,聯合唯一鍵)時必須在表級別上定義
如果爲兩個或者兩個以上的列定義聯合
 */




/*
  學生表
  id  學生的學號
  name 學生的姓名
  age 年齡18~25之間
*/


/*列級別約束建表*/


CREATE TABLE STUDENT(
  
ID NUMBER(10) CONSTRAINT STUDNT_ID_PK PRIMARY KEY,

NAME VARCHAR2(20) CONSTRAINT STUDENNT_NAME_NN NOT NULL,
AGE NUMBER(10) CONSTRAINT STUDENT_AGEE_CK CHECK(age > 18 AND age <25)


)


/*表級別約束建表*/
CREATE TABLE STUDENT(


  ID NUMBER(10),


  NAME VARCHAR2(20),


  AGE NUMBER(10),


  /*主鍵的表級別約束*/


CONSTRAINT STUDENT_ID_PK PRIMARY KEY(ID),


/*CHECK的表級別約束*/
 
 CONSTRAINT STUDENT_AGE_CK CHECK(AGE > 18 AND AGE <25)


)






/*外鍵的列級別約束*/


CREATE TABLE WORKER(


  ID NUMBER(10) CONSTRAINT WORKER_ID_FK  REFERENCES TEACHER(ID)


)




/*外鍵的表級別約束*/


CREATE TABLE WORKER(


  ID NUMBER(10),


  CONSTRAINT WORKER_ID_FK FOREIGN KEY(ID) REFERENCES TEACHER(ID)


)






/*
  授課表
  TEACHER_ID(外鍵)
  STUDENT_ID(外鍵)
*/


CREATE TABLE TEACH(


  TEACHER_ID CONSTRAINT TEACH_TEACHER_ID_FK REFERENCES TEACHER(ID),


  STUDENT_ID CONSTRAINT TEACH_STUDENT_ID_FK REFERENCES STUDENT(ID),


  /*表級別約束定義聯合主鍵*/


  CONSTRAINT TEACH_S#T_PK PRIMARY KEY(TEACHER_ID,STUDENT_ID)
 
)




/*查看一張表當中的所有的約束
注意表名大寫
*/


as 
SELECT CONSTRAINT_NAME,
CONSTRAINT_TYPE 
FROM USER_CONSTRAINTS
WHERE TABLE_NAME = 'TEACHER'
;


/*通過子查詢創建表
注意:數據會被複制 但是約束只能複製NOT NULL*/


CREATE TABLE COPY_OF_TEACHER
AS
SELECT * 
FROM TEACHER;




/*ALTER語句
增加表列:
ALTER TABLE 表名
ADD (
  列名1 數據類型(長度),
  列名2 數據類型(長度),
)
約束只可以添加NOT NULL 並且是在表中沒有數據的前提下
也可以添加默認值 道理同上
*/


ALTER TABLE TEACHER


ADD(
 BIRTH VARCHAR2(20) 
);






/*
  修改列
  有個關鍵字是modify MODIFY這個關鍵字
修改表列 默認格式語法:
ALTER TABLE table 
MODIFY (column datatype [DEFAULT expr][NOT NULL]
[,column datatype]...);


修改表列要注意的事:
1.修改表列的同時,可以增加not null約束以及默認值,不能增加其他約束
2.若要縮小列的寬度,只有該列值爲空或表裏沒有記錄
3.增加的默認值只能拿個影響到後來插入的值
4.若一列有空值不能加非空約束
5.若要改變列的類型只有該列爲空或這表裏沒有記錄。
ALTER TABLE 表名
  MODIFY(
    列名 數據類型
  )
*/




ALTER TABLE TEST


MODIFY(
  NAME VARCHAR2(60) DEFAULT '張三'
);




/*增加 修改 只可以添加非空約束*/




/*
關鍵詞組 drop column
語法格式:
ALTER TABLE table 
DROP COLUMN column_name;
刪除列
ALTER TABLE 表名
DROP COLUMN列名




不能直接刪除有主外鍵關係的列


*/


ALTER TABLE TEST
DROP COLUMN NAME;








/*增加約束
ALTER TABLE table 
ADD[CONSTRAINT constraint] type (column);
NOT NULL 約束只能在增加列或者修改列的時候完成
*/


ALTER TABLE TEST


ADD CONSTRAINT TEST_ID_PK PRIMARY KEY(ID);


ALTER TABLE TEST


ADD CONSTRAINT TEST_ID_CK CHECK(ID > 20);


/*刪除約束
CASCADE :級聯 破壞掉字段所屬的級聯關係
所以,想要刪除主外鍵關係列,就必須先破壞掉關係
纔可以刪除
*/




ALTER TABLE TEST 


DROP CONSTRAINT TEST_ID_PK CASCADE;




/*約束失效*/


ALTER TABLE TEST


DISABLE CONSTRAINT TEST_ID_CK CASCADE;
/*約束生效 所有數據都必須滿足生效條件纔可以*/
ALTER TABLE TEST
ENABLE CONSTRAINT TEST_ID_CK;


/*
  約束只可以添加 刪除 生效 失效 但不可以被修改
*/








/*DROP 刪除表 
DROP TABLE 表名 
表和數據都沒有了


CASCADE CONSTRAINTS 級聯刪除相關聯性約束
不能進行回滾該命令。
*/


DROP TABLE TEST;




/*TRUNCATE 截斷表(清空表)
TRUNCATE TABLE 表名 
數據都沒有了 表還在


刪除表中所有的記錄
釋放表中所佔用的表空間
是一DDL語句,不能回滾
不會觸發觸發器動作
TRUNCATE和DELETE的區別
1、TRUNCATE不可以回滾,DELETE可以回滾 2、在刪除大量數據時,TRUNCATE
速度要比DELETE快.3.TRUNCATE可以釋放表空間,DELETE不可以釋放表空間
4.TRUNCATE操作對象只能是表,DELETE可以是表、視圖或者同義詞。
*/


TRUNCATE TABLE STUDENT;




/*重命名錶名*/


RENAME oldname TO newname;




/*重命名列名*/


ALTER TABLE TEST_STUDENT RENAME COLUMN
ID oldname TO newname;














user_constraints


constraints_name,constraints_type
sys_開頭***    C代表非空約束
sys_******* P代表主鍵約束
sys_******* U代表唯一約束
sys_******* R代表外鍵約束


級聯刪除
在references 外鍵 後面加上 on delete cascade


使用子查詢創建表
creater table table
[column(,column...)]
as subquery;
通過子查詢創建表,可以獲得源表的結構以及數據
只有not null約束才能拷貝如新表其他約束丟失




留給第七天上午的






/*
DML語句 對錶的數據產生影響
INSERT DELETE UPDATE
INSERT語法格式:
INSERT INTO TABLE [COLUMN,[COLUMN..]]
VALUES(VALUE[,VALUE...]);
例子:
INSERT插入一條數據
INSERT INTO 表名(列1,列2)
VALUES (值1,值2);
如果不指定列名,就必須按照順序插入所有的值
注意外鍵可以爲空
*/


一次插入一行記錄
列名和插入值的順序、類型和數量的一致




INSERT INTO TEACHER(name,id)
VALUES ('王五',4);


/*使用子查詢一次性插入多條數據*/
INSERT INTO TABLE [(COLUMN[,COLUMN..])] SUBQUERY
一次插入多行記錄 
通過子查詢實現批量插入
列名和插入值順序、類型和數量一致
INSERT INTO TEACHER(ID,NAME)
SELECT ID,FIRST_NAME
FROM S_EMP;


/*
  UPDATE
  UPDATE 表名
  SET 列1 = 值1,列2 = 值2
  WHERE.....;
  修改Ben的NAME爲Jack
*/
UPDATE TEACHER
SET NAME = 'Ben',sex = '男'
WHERE NAME = 'Jack';


/*
 DELETE
 DELETE FROM 表名
 WEHRE 條件;
 如果沒有條件就會刪除所有記錄
*/
DELETE FROM TEACHER
WHERE ID = 1;


/*
  TRUNCATE 與 DELETE的區別
  1 truncate DDL語句  delete是DML語句
  DDL語句是不可逆的  DML是可逆的
  2 truncate會釋放表空間 delete不會釋放
   truncate適合刪除大量表中數據
  3 truncate只可以作用於表
    delete可以作用於 表 同義詞 視圖
  
  
  如果存在主外鍵關係
  我們必須先刪子表,再刪主表
*/








/*
  事務 ACID
  
  COMMIT正常提交事務
  DDL/DCL:自動調用COMMIT
  DML:不會自動提交COMMIT
  
  ROLLBACK回滾 回滾到事務的開始點
  try{
    1 插入了一個subject
    2 插入了一個老師 對應新插入的subject
    commit
  }catch(e){
    rollback
  }
  代碼都執行成功了才commit,否則就rollback
*/


/*設置回退節點*/
INSERT INTO SUBJECT
VALUES (2,'WEB');
SAVEPOINT S;
INSERT INTO SUBJECT
VALUES (3,'ORACLE');
ROLLBACK TO S;


/*
  數據字典
  1 user_table:查看所有表
  2 user_constrants :查看所有約束
  3 USER_CONS_COLUMNS:查看約束對應的列
  4 USER_USERS:查看當前用戶信息
  views視圖  indexes索引  sequences序列
*/
select *
from USER_USERS;




/*
  序列 4是ORACLE特有的對象,能夠產生連續的整數值
  用來生成主鍵
*/


CREATE SEQUENCE TEACHER_SEQ1


起始值
STARTWITH 1


--步長一次增加幾個字節
INCREMENT BY 1


--最大值
MAXVALUE 999999


--沒有緩衝區
NOCACHE


--沒有循環
NOCYCLE;


/*
  調用序列的下一個值 NEXTVAL
*/


SELECT TEACHER_SEQ.NEXTVAL FROM DUAL;


/*
 序列的當前值 CURRVAL
  沒有初始化的序列無法調用當前值
*/


SELECT TEACHER_SEQ.CURRVAL FROM DUAL;
INSERT INTO TEACHER


VALUES(TEACHER_SEQ.NEXTVAL,'JACK','BOY',1);


/*
  序列的數據字典 user_sequences
*/


SELECT * FROM user_sequences;


/*
  刪除序列
  DROP SEQUENCE 序列名
*/


DROP SEQUENCE TEACHER_SEQ1;


/*
  修改序列
  ALTER SEQUENCE 序列名
  .....
  不可以修改起始值
*/


ALTER SEQUENCE TEACHER_SEQ


INCREMENT BY 2


MAXVALUE 123456


CYCLE


CACHE 10;


/*
  視圖VIEW
  視圖本質上就是一個帶有名字的select語句
 
 一般用戶無法直接創建視圖
  需要DBA授權 GRANT CREATE VIEW TO 用戶名
*/


CREATE VIEW DEPT_41


AS SELECT ID,
FIRST_NAME,DEPT_ID


FROM S_EMP


WHERE DEPT_ID = 41;


/*利用視圖獲取41號部門的相關信息*/


SELECT FIRST_NAME
FROM DEpt_41;


/*
  OR REPLACE如果有相同的視圖就替換掉
*/


CREATE OR REPLACE VIEW DEPT_41
AS SELECT ID,FIRST_NAME,DEPT_ID,SALARY
FROM S_EMP
WHERE DEPT_ID = 41;


/*給視圖列起名字*/


CREATE OR REPLACE VIEW DEPT_41
(ID,NAME,D_ID,MONEY)


AS SELECT ID,FIRST_NAME,DEPT_ID,SALARY
FROM S_EMP


WHERE DEPT_ID = 41;


/*
創建一個視圖
要求顯示
教java的所有老師的 NAME SEX SUBJECT_ID
*/






















/*
  序列 SEQUENCE
  是ORACLE特有的對象,能夠產生連續的整數值
  用來生成主鍵
*/
CREATE SEQUENCE TEACHER_SEQ1
START WITH 1
INCREMENT BY 1
MAXVALUE 999999
NOCACHE
NOCYCLE;
/*
  調用序列的下一個值 NEXTVAL
*/
SELECT TEACHER_SEQ.NEXTVAL FROM DUAL;
INSERT INTO TEACHER
VALUES(TEACHER_SEQ.NEXTVAL,'JACK','BOY',1);
/*
  序列的數據字典 user_sequences
*/
SELECT * FROM user_sequences;
/*
  序列的當前值 CURRVAL
  沒有初始化的序列無法調用當前值
*/
SELECT TEACHER_SEQ.CURRVAL FROM DUAL;
/*
  刪除序列
  DROP SEQUENCE 序列名
*/
DROP SEQUENCE TEACHER_SEQ1;
/*
  修改序列
  ALTER SEQUENCE 序列名
  .....
  不可以修改起始值
*/
ALTER SEQUENCE TEACHER_SEQ
INCREMENT BY 2
MAXVALUE 123456
CYCLE
CACHE 10;
/*
  視圖VIEW
  視圖本質上就是一個帶有名字的select語句
  一般用戶無法直接創建視圖
  需要DBA授權 GRANT CREATE VIEW TO 用戶名
*/
CREATE VIEW DEPT_41
AS SELECT ID,FIRST_NAME,DEPT_ID
FROM S_EMP
WHERE DEPT_ID = 41;
/*利用視圖獲取41號部門的相關信息*/
SELECT FIRST_NAME
FROM DEpt_41;
/*
  OR REPLACE如果有相同的視圖就替換掉
*/
CREATE OR REPLACE VIEW DEPT_41
AS SELECT ID,FIRST_NAME,DEPT_ID,SALARY
FROM S_EMP
WHERE DEPT_ID = 41;
/*給視圖列起名字*/
CREATE OR REPLACE VIEW DEPT_41
(ID,NAME,D_ID,MONEY)
AS SELECT ID,FIRST_NAME,DEPT_ID,SALARY
FROM S_EMP
WHERE DEPT_ID = 41;
/*
創建一個視圖
要求顯示
教java的所有老師的 NAME SEX SUBJECT_ID
*/
CREATE VIEW TEACHER_MESSAGE
AS
SELECT NAME,SEX,SUBJECT_ID
FROM TEACHER
WHERE SUBJECT_ID = 1;
/*
  對視圖使用DML語句
  其實就是在對錶使用DML語句
  修改表的數據,所對應的視圖也會發生變化
*/
UPDATE TEACHER_MESSAGE
SET NAME = 'FRANK';






CREATE OR REPLACE VIEW TEACHER_MESSAGE
AS
SELECT ID,NAME,SEX,SUBJECT_ID
FROM TEACHER
WHERE SUBJECT_ID = 1
WITH READ ONLY;
/*
  WITH READ ONLY只讀,一旦定義就只能被查看,不能修改
*/
INSERT INTO TEACHER_MESSAGE
VALUES(TEACHER_SEQ.NEXTVAL,'LUCY','GIR',1);








CREATE OR REPLACE VIEW TEACHER_MESSAGE
AS
SELECT ID,NAME,SEX,SUBJECT_ID
FROM TEACHER
WHERE SUBJECT_ID = 1
WITH CHECK OPTION;
/*WITH CHECK OPTION 可以增刪改
但是必須滿足where條件
*/
INSERT INTO TEACHER_MESSAGE
VALUES(TEACHER_SEQ.NEXTVAL,'ABCD','GIR',2);/*錯*/
INSERT INTO TEACHER_MESSAGE
VALUES(TEACHER_SEQ.NEXTVAL,'ABCD','GIR',1);/*對*/


/*複雜視圖:數據來源於多個表
不可以同時增刪改兩個表中的數據
*/
CREATE VIEW MESSAGE
AS
SELECT E.FIRST_NAME,D.NAME 
FROM S_EMP E,S_DEPT D
WHERE E.DEPT_ID = D.ID;
/*
刪除視圖 DROP VIEW 視圖名
*/
DROP VIEW MESSAGE;
/*
視圖對應的數據字典:user_views
*/
SELECT *
FROM USER_VIEWS;




/*
INDEX索引
加快數據庫檢索速度
一些表數據量比較大,但是要查找的值只佔其中的很小一部分
大概5%左右,可以創建索引,提高查詢效率


主鍵,唯一項會自動創建索引
*/
CREATE INDEX TEACHER_NAME_IDX
ON TEACHER(NAME);
/*刪除索引*/
DROP INDEX TEACHER_NAME_IDX;




/*
  臨時表空間:負責執行算法的臨時空間
  每次數據庫關閉都會清空臨時表空間
  
  表空間:數據庫的存儲空間,會一直存在,
  不會自動丟失。
  
  oracle有默認的表空間system
  和臨時表空間users
*/
/*表空間的創建*/
CREATE TABLESPACE OAECSPCAE
DATAFILE 'D:\OAECSPACE.DBF'
SIZE 500M
AUTOEXTEND ON NEXT 5M MAXSIZE 1000M
EXTENT MANAGEMENT LOCAL;


/*臨時表空間的創建*/
CREATE TEMPORARY TABLESPACE OAEC_TEMPS
TEMPFILE 'E:\OAEC_TEMPS.DBF'
SIZE 50M
AUTOEXTEND ON NEXT 5M MAXSIZE 100M
EXTENT MANAGEMENT LOCAL;


/*使用自定義表空間和臨時表空間創建用戶*/
CREATE USER SSSS IDENTIFIED BY SSSS
DEFAULT TABLESPACE OAECSPACE
TEMPORARY TABLESPACE OAEC_TEMPS;


/*DBA授權:在DBA權限下*/
GRANT DBA TO TESTS;
/*撤銷權限*/
REVOKE DBA FROM tests;


/*創建同義詞*/
CREATE SYNONYM UU
FOR S_EMP;


/*數據泵導出數據*/
$exp userid=tests/tests full=y file=D:\ss.dmp;
/*數據泵導入數據*/
$imp userid=SSSS/SSSS full=y file=D:\ss.dmp;




視圖view


--創建視圖的方法
create view course_view
as select id,name,credit
from course;
--帶where條件的,視圖名字不能重複
create view course_view2
as select id,name,credit
from course
where credit = 50;
select * from course_view;


create or replace view course_view2
--or replace 創建或者替換
--這個是給對應的列起別名 
(newid,newname,newcredit)
as select id,name,credit
from course
where id = 3;
select * from course_view2;


create or replace view course_view2
as select * from course
where id between 2 and 3
--這個的作用就是向視圖中插入的數據必須符合where條件
with check option;


create or replace view course_view3
as select * from course
--只讀這個不能讓視圖被修改,但是修改源表依然會改變視圖
with read only;


--複雜視圖,多個表直接的連接
create view dept_sum_vn
(name,minsal,maxsal,avgsal)
as select d.name,MIN(e.salary),
max(e.salary),avg(e.salary)
from s_emp e,s_dept d
where e.dept_id = d.id
group by d.name;


select * from dept_sum_vn;


--刪除視圖
drop view dept_sum_vn;


select * from dept_sum_vn;






數據庫權限
創建用戶
create user scott(用戶名) identified by tiger(密碼)


創建用戶不是用表空間


CREATE USER oace IDENIFIED BY oaec
--指定默認表空間
DEFAULT TABLESPACE oaecspace
--使用臨時表空間
TEMPORARY TABLESPACE oaec_temp;


修改用戶密碼
ALTER USER scott IDENTIFIED BY lion;


角色


connect:提供了登錄和執行基本函數的能力。可以連接數據庫以及在這
些表中對數據進行查詢,插入,修改及刪除的權限。


resource:建立對象的能力


dba:擁有所有的系統權限,包括無線的空間配額,以及給其他用戶授予
全部權限的能力。


select sydate from dual;返回當前的日期函數












--權限
--權限授予用戶對象權限
GRANT object priy[(columns)]
ON  object
TO {user|role|PUBLIC}
--允許分配到權限的用戶繼續將權限分配給其他用戶
[WITH GRANT OPTION]
--PUBLTC:將權限賦予給所有的用戶
--WITH GRANT OPTION:權限的授權者也可以將權限賦予其他的用戶
--沒有這個選項,接受權限用戶就不能將接受到的權限在賦予其他的用戶,此選項不能賦予PUBLTC


--將查詢表emp的權限賦予給sue和rich用戶
GRANT SELECT 
ON s_emp
TO sue,rich;


--將修改表s_dept中的id,name,region_id的權限賦予給scott,manager
GRANT UPDATE(id,name,region_id)
ON s_dept
TO scott,manager;


--將查詢表s_emp的權限賦予給scott,並且他還有這個向下賦予的權限。
GRANT select 
ON S_EMP
TO scott
WITH GRANT OPTION;


--回收權限
REVOKE select,insert
ON s_dept
FROM scott;
--WITH GRANT OPTION:回收 賦予給其他用戶的權限


--同義詞synonym 爲對象定義另一個名字,可以通過這個名字訪問該對象
CREATE [PUBLIC] SYNONYM synonym_name FOR object_name;
--PUBLITC:創建和刪除同義詞只能由DBA執行
--刪除同義詞
DROP SYNONYM synonym_name;
--注意在導入導出之前要注意回話格式,並且數據還得在cmd中斷開連接的情況下導出
alter session set nls_date_language = english;
--數據導出
 exp userid=oace2/oace2 full=y file=E:/oace2.dmp;


--數據導入
 imp userid =oaec2/oace2 full=y file=sql.dmp;






創建索引
create index s_emp_last_name_idx
on s_emp(last_name);


確定索引
user_indexes包含索引的名字和他的唯一性約束索引
user_ind_columns包含索引名、表名和列名。




Oracle 體系結構
表空間是Oracle數據庫最大的邏輯結構,一個Oracle數據庫在邏輯上由多個表空間組成,
一個表空間只隸屬於一個數據庫。
Oracle中有一個稱爲SYSTEM的表空間,這個表空間是在創建或安裝數據庫時自動創建的
。主要用於存儲系統的數據字典,過程,函數,觸發器等;也可以儲存用戶的表,索引等。
表空間在物理上包含一個或多個數據文件。
查看錶空間
--defaul_tablespace是默認表空間,temporaru_tablespace臨時表空間。
select username,user_id,default_tablespace,temporary_tablespace
from dba_user;


創建表空間
create tablespace oaecspace
datafile 'src.dbf'
size 500m
autoextend no next 5m maxsize 1000m
extent management local;




創建臨時表空間
create temporary tablespace oace_temp
tempfle 'src.dbf'
size 32M
--這裏代表自動正將
autoextend on next 32M maxsize 512m
extent management local;


擴展表空間之方法1:
修改數據庫的數據文件system.dbf,擴展其大小爲1024m
alter database datafile  'src' 
resize 1024m;


擴展表空間之方法2:
修改數據庫的數據文件system.dbf,其大小每次自動擴展100m,最大爲1000m
alter database datafile 'src'
autoextend on 
next 100m
maxsize 2048m;


刪除表空間
drop tablespace oaecspace
including contents and datafiles;




oacle數據庫文件名字: ojdbc6.jar


JDBC驅動類型
1、jdbc-odbc橋加odbc
將jdbc調用轉換爲odbc調用,性能低
2、本地api部分用java編寫的驅動
將jdbc調用轉換爲RDBMS調用,要在客戶端安裝相關的數據庫客戶端程序。
JDBC驅動由兩部分組成,一部分用Java編寫,一部分
是其他語言編寫的二進制代碼。
3、基於網絡純Java的驅動
將jdbc調用轉換爲與dbms無關的網絡協議,然後由
相應服務器轉換爲dbms調用。
4、基於本地協議純Java的驅動
將jdbc嗲用後直接和數據庫進行交互。


JDBC的常用的API
Driver:數據庫驅動的藉口
DriverManager:管理多個加載的驅動程序
Connection:事和數據庫連接的對象形式,代表了一個和數據庫的連接。
Statement:用以執行SQL語句
PreparedStatement:Statement的子接口
CallableStatement:Statement的子接口
ResultSet:封裝Select語句執行返回的結果集,並提供方法對結果集中內榮進行獲取和其他操作。


JDBC開發流程
1、註冊驅動
使用類裝載器(最常用)
Class.forName(driverName)
直接實例化驅動
Driver driver = new oracle.jdbc.driver.OracleDriver();
DriverManager.registerDriver(driver);
使用jdbc.drivers屬性
java-Djdbc.drivers = driverName[:driverName1]...[:driverNamen]
常見驅動
Oracle:oracle.jdbc.driver.OracleDriver
Mysql:com.mysql.jdbc.Driver


2.建立和數據庫的連接
DriverManager.getConnection()方法
getConnection(String url)
getConnection(String url,java.util.properties info)
getConnection(String url,String user String passwd)
--內部調用Driver.connect(String url,Properties info)
常見數據庫URL
host 和localhost 和 127.0.0.1都可以是服務器的默認地址
Oracle jdbc:oracle:thin:@host:1521:SID
Mysql  jdbc:mesql://host:3306:SID

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章