1. 程式人生 > >ORACLE資料庫-查詢語句SELECT

ORACLE資料庫-查詢語句SELECT

---------查詢語句
--完整語法描述:
--SELECT [ALL|DISTINCT] TOP n[PERCENT] WITH TIES select_list
--[INTO[new table name]]
--[FROM{table_name|view_name}[(optimizer_hints)]
--[,{table_name2|view_name2}[(opyimizer_hints)]
--[...,table_name16|view_name16][(optimizer hints)]]]
--[WHERE clause]
--[GROUP BY clause]
--[HAVING clause]
--[ORDER BY clause]
--[COMPUTE clause]
--[FOR BROWSE]
----------簡單查詢(僅含有SELECT和FROM 子句的查詢是簡單查詢)
--顯示錶中的所有行和列
SELECT * FROM EMP;
--1.使用FROM 子句指定表
SELECT * FROM EMP,DEPT;--FROM後接多個表,按笛卡爾積來顯示
--2.使用SELECT指定列
SELECT EMPNO,ENAME FROM EMP;--可以通過改變列的順序來顯示查詢結果,甚至可以多次指定同一列
SELECT EMPNO,LOC FROM EMP,DEPT;--這生成的也是笛卡爾積,只不過只選了兩列
--3.算數表示式
--SELECT語句中可以包括(加減乘除和括號的算術運算子)
SELECT EMPNO,ENAME,SAL*(1+0.1) FROM EMP;--給員工加薪百分之十
SELECT EMPNO "編號" FROM EMP;
SELECT EMPNO 編號 FROM EMP;
SELECT EMPNO AS 編號 FROM EMP;--都可以給表裡的列新增上標題,不過最好不用漢語名字,如果列標題裡含有一些特殊符號如空格,則指定的列標題必須用雙引號括起來;
SELECT EMPNO AS A A FROM EMP;--ORA-00923: 未找到要求的 FROM 關鍵字,因為列標題中加了空格;
SELECT EMPNO AS "A A" FROM EMP;--加上雙引號這樣就可以了
--4.DISTINCT關鍵字
--如考勤記錄表中僅顯示考勤人員而不顯示時間時,人員的名字會有很大的重複
--這時需要DISTINCT關鍵字來去除結果集中重複的行
SELECT DISTINCT DEPTNO FROM EMP;--顯示了EMP表中有員工的部門號
SELECT DEPTNO FROM EMP;--返回了EMP表中該列的所有值
--------WHERE子句
--WHERE子句用於篩選從FROM子句中返回的值,完成的是選擇操作;
--WHERE將對FROM子句指定的資料表進行判斷,只有滿足WHERE子句判斷條件的行才會顯示,不滿足WHERE條件的不包括在結果集中;
--WHERE子句位於FROM之後
SELECT ENAME FROM EMP WHERE SAL>1500;
--1.條件表示式
--A=B,A>B,A<B,A!=B 或A<>B,A LIKE B ,其中LIKE 是匹配運算子,"%" 代表0,1,或多個任意字元,"_"代表一個任意字元;
--NOT <條件表示式> 它用於對結果取反;
如查詢EMP表中名字裡有"S"的員工姓名;
SELECT ENAME FROM EMP WHERE ENAME LIKE'%S%';
--2.連線運算子
--AND 在其左右的條件都為TRUE時,AND 運算子才返回TRUE;OR 在其左右的條件有一個為TRUE 就返回TRUE值;
SELECT * FROM EMP WHERE SAL>2000 AND DEPTNO=20;
SELECT * FROM EMP WHERE SAL>2000 OR DEPTNO=20;
SELECT * FROM EMP WHERE DEPTNO=10 OR DEPTNO=30;--ORACLE 有優先順序判斷順序的,可以通過加括號將表示式括起來,增加可讀性;
--3.NULL值
--用來描述記錄中沒有定義內容的欄位值,判斷某個條件時,返回值可能為TRUE,FALSE,UNKNOWN;
SELECT * FROM EMP WHERE COMM IS NULL;
如下面的例子:
CREATE TABLE DEPARTMENTS(DEPARTMENT_ID VARCHAR2(10),DEPARTMENT_NAME VARCHAR2(10),MANAGER_ID VARCHAR(10));
INSERT INTO DEPARTMENTS(DEPARTMENT_ID,DEPARTMENT_NAME,MANAGER_ID) VALUES(30,'資料庫',NULL);
SELECT DEPARTMENT_ID,DEPARTMENT_NAME,MANAGER_ID FROM DEPARTMENTS WHERE MANAGER_ID = NULL;--沒有結果,證明不能使用"=" ;
SELECT DEPARTMENT_ID,DEPARTMENT_NAME,MANAGER_ID FROM DEPARTMENTS WHERE MANAGER_ID IS NULL;--這個表達才對,用"IS NULL" 和"IS NOT NULL";
--ORDER BY 子句,對檢測到的結果進行排序
--SELECT 列名 FROM  表名 ORDER BY [(要排序的列,ASC,DESC)];
ASC為預設排序,且它為升序排列;DESC為降序排列;
如:SELECT EMPNO,ENAME,SAL FROM EMP WHERE SAL>2000 ORDER BY SAL DESC;
如果需要對多個列進行排序,只需要在 ORDER BY 子句後指定多個列名。這樣當輸出排列結果時,首先根據第一列進行排序,
當第一列的值相同時,再對第二列進行比較排序。比如,先對job排序,然後再排sal這樣就可以使僱員的薪資分工種顯示;
select * from emp for update;--更新表資料
--GROUP BY 子句
--在查詢結果集中對記錄進行分組,以彙總資料或者分組顯示單行的彙總資訊;
--使用GROUP BY 子句和統計函式,可以實現對查詢結果中每一組資料進行分類統計
常用統計函式:COUNT()---返回找到的記錄行數;
MIN()---返回一個數字列或是計算列的最小值;
MAX()---最大值;
SUM()---計算總和;
AVG()---平均值;
在使用 group by 子句時,必須滿足下面的條件:
1.在SELECT子句的後面只可以有兩類表示式,統計函式和進行分組的列名;
2.在SELECT子句中的列名必須是進行分組的列,除此之外新增其他的列都是錯誤的;
  但是 group by 子句後面的列名可以不出現在SELEECT子句中;
3.如果使用了 WHERE 子句,那麼所有參加分組計算的資料必須首先滿足 WHERE 子句指定的條件;
4.在預設情況下,將 group by 子句指定的分組列升序排列,如需重新排序,可以使用 ORDER BY 子句指定新的排列順序;
SELECT 子句中包含了未參與分組的列,會報錯:
SELECT JOB,SUM(JOB),DEPTNO FROM EMP WHERE SAL>2000 GROUP BY DEPTNO;
--ORA-00979: 不是 GROUP BY 表示式
--GROUP BY 子句對多個列進行分組,在這種情況下,GROUP BY 子句將在主分組範圍內進行二次分組;
如:對各個部門中的各個工種型別進行分組;
SELECT DEPTNO,JOB,AVG(SAL),SUM(SAL),COUNT(*) FROM EMP GROUP BY DEPTNO,JOB;
在 group by 子句中還可以加上 ROLLUP 和 CUBE,這兩個運算子在功能上非常類似,
group by 子句中使用它們後,都會在查詢結果中附加一行彙總資訊;
如:SELECT JOB,AVG(SAL),SUM(SAL),MAX(SAL),COUNT(*) FROM EMP GROUP BY ROLLUP(JOB);--最後一行多了個彙總行
SELECT JOB,AVG(SAL),SUM(SAL),MAX(SAL),COUNT(*) FROM EMP GROUP BY CUBE(JOB);--第一行多了個彙總行
--5.HAVING 子句
--HAVING 子句通常與GROUP BY 子句一起使用,在完成對分組結果統計後,可以使用HAVING 子句對分組結果做進一步的篩選;
--如果不用GROUP BY 子句則HAVING 與WHERE 子句一樣;
--HAVING 與WHERE 子句都是定義搜尋條件的,但是HAVING 子句與組相關,WHERE 子句與單個行相關;
--如果 SELECT 語句中使用了GROUP BY 子句, HAVING 將用於GROUP BY 子句建立的那些組。
--如果指定了WHERE 子句,而沒有指定GROUP BY 子句,那麼HAVING 子句將用於WHERE 子句的輸出,並且整個輸出被看成是一個組;
--如果SELECT 語句既沒有指定GROUP BY 也沒有指定WHERE 則HAVING 子句將應用於FROM 子句的輸出,將其看成是一個組;
--SELECT 語句中子句的處理順序 --FROM --WHERE --GROUP BY --HAVING --SELECT --ORDER BY;
如:列出平均薪資大於10000的統計資訊
SELECT JOB,AVG(SAL),SUM(SAL),MAX(SAL),COUNT(*)
FROM EMP GROUP BY JOB HAVING AVG(SAL)>10000;
-----------------多表連線查詢
--1.簡單連線
--基本形式:僅僅通過SELECT 子句和FROM 子句來連線多個表,其查詢結果是一個通過笛卡爾積所生成的表;
笛卡爾積所生成的表,就是由一個基表中每一行與另一個基表的每一行連線在一起所生成的表,其查詢結果的行數是兩個基錶行數的積。
如:SELECT EMPNO,ENAME,DNAME FROM EMP,DEPT;
--條件限定:笛卡爾積產生大量冗餘資訊,所以用WHERE 子句提供連線條件,可以有效避免笛卡爾積的出現;
--WHERE 子句限定時,只有第一個表中的列與第二個表中的相應的列相互匹配後才會在結果集中顯示,這是連線查詢中最常用的形式。
SELECT EMPNO,ENAME,DNAME FROM EMP,DEPT WHERE EMP.DEPTNO=DEPT.DEPTNO;--所要顯示的列名不相同時可以不用顯示其所在表;
SELECT DEPTNO ,ENAME,DNAME FROM EMP,DEPT WHERE EMP.DEPTNO=DEPT.DEPTNO;--ORA-00918: 未明確定義列
SELECT EMPNO,ENAME,DNAME FROM EMP ,DEPT WHERE EMP.DEPTNO=DEPT.DEPTNO AND DEPT.DNAME='SALES';--可以限定多個條件;
SELECT * FROM TAB;--查詢當前使用者所有的表;
SELECT * FROM DEPT;
--表別名
SELECT D.DEPTNO,D.DNAME,E.EMPNO,E.ENAME FROM EMP E,DEPT D WHERE E.DEPTNO=D.DEPTNO;--給表起別名來方便明確定義其中的列;
注意:如果表指定了別名,那麼語句中的所有子句都必須使用別名,而不允許再使用實際的表名;
如:
SELECT DEPT.DEPTNO, DEPT.DNAME, E.EMPNO, E.ENAME
  FROM EMP E, DEPT D
 WHERE E.DEPTNO = D.DEPTNO
   AND D.DNAME = 'SALES'; --ORA-00904: "DEPT"."DNAME": 識別符號無效
因為ORACLE各子句執行順序是FROM,WHERE,SELECT,當 FROM指定了表別名後,表的真實名稱將被替換。SELECT用原名選擇的列將無法被找到;
--2.JOIN 連線
語法格式:--FROM JOIN_TABLE1 JOIN_TYPE JOIN_TABLE2
           --[ON(JOIN_CONDITION)]
--JOIN_TYPE 為連線型別,包括內連線,外連結和自連線。連線查詢中的ON(JOIN_CONDITION)指出連線條件,它由
--被連線表的列和比較運算子、邏輯運算子等構成。
(1)內連線(INNER JOIN)
一般用關鍵字 INNER JOIN,可以省略INNER關鍵字,而只使用JOIN關鍵字表示內連線。
內連線使用比較運算子時,在連線的某些列之間進行比較操作,並列出表中與連線條件相匹配的資料行;
如:
SELECT E.EMPNO,E.ENAME,D.DNAME FROM EMP E INNER JOIN DEPT D ON E.DEPTNO=D.DEPTNO WHERE E.JOB='CLERK';
內連線實現兩個以上表的查詢:
SELECT E.EMPNO,E.ENAME,D.DNAME,J.JOBNAME
FROM EMP E INNER JOIN JOBS J
  ON E.JOBID=J.JOBID
  INNER JOIN DEPT D
  ON E.DEPTNO=D.DEPTNO
  WHERE E.JOBID='IT_PROG';--只是一個例子哦;
(2)自然連線(NATURAL JOIN)
自然連線與內連線的功能相似,在使用自然連線查詢多個表時,ORACLE會將第一個表中的那些列
與第二個表中具有相同名稱的列進行連線。在自然連線中,使用者不需要明確指定進行連線的列,系統
會自動完成這一任務。--內連線有一個條件就是連線的各表之間必須具有相同名稱的列。(但與現實意義脫軌,兩張表的欄位名也許相同但所包含的意思卻是會不同的)
自然連線的規律:存在相同的列,列中資料不一致,則連線資料一致的記錄;
                 顯示相同列所對應表的其他欄位資訊;
                 存在多個相同的列,對應的行的相關列的資料必須完全一致;
                 NULL<>NULL 空值不等於空值。  
SELECT E.ENAME,D.DNAME
FROM EMP E NATURAL JOIN DEPT D
WHERE D.DNAME='SALES';
(3)外連線(LEFT/RIGHT/FULL JOIN)
內連線消除了與另一個表中的任何行不匹配的行,而外連線擴充套件了內連線的結果集,除返回所有匹配
的行外,還會返回一部分或全部不匹配的行,這主要取決於外連線的種類。
外連線分為左連線和右連線——LEFT JOIN(或 LEFT OUTER JOIN)和 RIGHT JOIN(或 RIGHT OUTER JOIN) 。
全外連線——FULL JOIN 。
SELECT E.EMPNO,E.ENAME,D.DNAME,D.DEPTNO 
FROM EMP E LEFT JOIN DEPT D ON E.DEPTNO=D.DEPTNO;
(左外連線以EMP表為主-沒有40部門號)
SELECT E.EMPNO,E.ENAME,D.DNAME,D.DEPTNO 
FROM EMP E RIGHT JOIN DEPT D ON E.DEPTNO=D.DEPTNO;
(右外連線以DEPT表為主-有40部門)
完全外連線相當於同時執行了一個左外連線和一個右外連線; 
(4)自連線
有時使用者可能會擁有自引用式外來鍵。自引用式外來鍵意味著表中的一個列可以是該表主鍵的一個外來鍵。
如EMP 表的EMP.MGR列可以是另一行的EMP.EMPNO;
語句如下:
SELECT E.EMPNO,E.ENAME,M.ENAME
FROM EMP E,EMP M
WHERE E.MGR=M.EMPNO;
再如:
SELECT E.ENAME,M.ENAME,D.DNAME,D.DEPTNO
FROM EMP E,EMP M,DEPT D
WHERE E.MGR=M.EMPNO AND E.DEPTNO=D.DEPTNO;
(5)交叉連線(CROSS JOIN)——相當於產生笛卡爾積
SELECT * FROM EMP CROSS JOIN DEPT;
(6)(+)來進行左右外連線——一般不用這個
D.DEPTNO=E.DEPTNO(+)--則以DEPT 的 DEPTNO 為基準
D.DEPTNO(+)=E.DEPTNO--則以EMP 的 DEPTNO 為基準
(+)寫左邊為左連線,寫右邊為右連線;
SELECT E.ENAME,E.EMPNO,D.DEPTNO
FROM EMP E,DEPT D
WHERE D.DEPTNO=E.DEPTNO(+);--以DEPT 為基準


SELECT E.ENAME,E.EMPNO,D.DEPTNO
FROM EMP E,DEPT D
WHERE D.DEPTNO(+)=E.DEPTNO;--以EMP 為基準
-------------------查詢的集合操作
--集合操作就是將兩個或多個SQL 查詢結果合併構成複合查詢,以完成一些特殊的任務需求;
1. UNION--將多個查詢結果相加,形成一個結果集。
       --UNION 運算會將集合中的重複記錄慮除。
SELECT * FROM DEPT
UNION 
SELECT 50,'教學','北京' FROM DUAL;


SELECT 50 AS DEPTNO,'教學' AS DNAME,'北京' AS LOC FROM DEPT 
UNION 
SELECT * FROM DEPT;


SELECT 50,'教學','北京' FROM DEPT/DUAL
UNION
SELECT * FROM DEPT;--這個就不對了,表頭也變了;


SELECT DEPTNO AS 部門號,DNAME AS 部門名稱,LOC AS 地址 FROM DEPT;
SELECT DEPTNO AS "部門號",DNAME AS "部門名稱",LOC AS "地址" FROM DEPT;
SELECT '部門號' AS DEPTNO,'部門名稱'AS DNAME,'地址'AS LOC FROM DEPT WHERE DEPTNO=40;--這種是給欄位列表賦予了一個臨時值的感覺
SELECT DEPTNO AS '部門號',DNAME AS '部門名稱',LOC AS '地址' FROM DEPT;--給列建立別名只能用雙引號或不用
2. UNION ALL--將多個查詢結果相加,形成一個結果集。
            --與UNION 不同的是UNION ALL 操作符形成的結果集中包含有兩個子結果集重複的行。
3. INTERSECT --也用於對兩個SQL 語句所產生的結果集進行處理。
          --不同的是UNION 相當於OR 運算,即並運算;
          --而INTERSECT 相當於AND 運算,即交集運算。           
SELECT EMPNO,ENAME FROM EMP WHERE ENAME LIKE 'S%' OR ENAME LIKE 'C%'
INTERSECT
SELECT EMPNO,ENAME FROM EMP WHERE ENAME LIKE 'S%' OR ENAME LIKE 'B%';
(這個只有以S開頭的員工姓名)
SELECT EMPNO,ENAME FROM EMP WHERE ENAME LIKE 'S%' OR ENAME LIKE 'C%'
UNION
SELECT EMPNO,ENAME FROM EMP WHERE ENAME LIKE 'S%' OR ENAME LIKE 'B%';
(這個以S,C,D開頭的員工姓名都有)
4. MINUS--它可以找到兩個給定的集合之間的差集,即該操作符會返回所有從第一個查詢中返回,但是沒有在第二個查詢中返回的記錄。
        --MINUS相當於差集運算。
SELECT EMPNO,ENAME FROM EMP WHERE ENAME LIKE 'S%' OR ENAME LIKE 'C%'
MINUS
SELECT EMPNO,ENAME FROM EMP WHERE ENAME LIKE 'S%' OR ENAME LIKE 'B%';
(這個就只有以C開頭的員工姓名了)


----------------ORACLE 查詢的子查詢
  子查詢和連線查詢一樣,都提供了使用單個查詢訪問多個表中資料的方法,
子查詢提供了一種進一步的有效方法來表示WHERE子句中的條件。子查詢是一個SELECT語句,
它可以在 SELECT、INSERT、UPDATE 或 DELETE 語句中使用。
SELECT E.* FROM (SELECT * FROM EMP WHERE EMPNO=7654) M,EMP E WHERE M.SAL<E.SAL;
SELECT * FROM EMP WHERE SAL>(SELECT SAL,COMM FROM EMP WHERE EMPNO=7654);--ORA-00913: 值過多
SELECT * FROM EMP WHERE SAL>(SELECT HIREDATE FROM EMP WHERE EMPNO=7654);--ORA-00932: 資料型別不一致: 應為 NUMBER, 但卻獲得 DATE
SELECT * FROM EMP WHERE SAL>(SELECT COMM FROM EMP WHERE EMPNO=7654);--看來只要資料一致就會有結果的,資料型別一致可以進行比較。
SELECT * FROM EMP WHERE SAL>(SELECT SAL FROM EMP WHERE EMPNO=7654);
1. IN 關鍵字
-- 可以將原表中特定列的值與子查詢返回的結果集中的值進行比較,如果莫航的特定列的值存在,則
--在SELECT 語句的查詢結果中就包含這一行。
SELECT EMPNO,ENAME,DEPTNO FROM EMP WHERE DEPTNO IN(SELECT DEPTNO FROM DEPT WHERE DEPTNO=20); 
注意:在使用子查詢時,子查詢返回的結果必須和外層引用列的值在邏輯上具有可比較性。
2. ALL 關鍵字
  =ALL 查詢等於子查詢中所有值的值;
  >ALL 大於子查詢中的所有值,即大於最大值;
  <ALL 小於子查詢中的所有值,即小於最小值;
3. ANY 關鍵字
  =ANY 與 IN 關鍵字的效果一致;
  >ANY 大於子查詢中的任何一個值即可,即大於最小值;
  <ALL 小於子查詢中的任何一個值即可,即小於最大值;
4. EXISTS 關鍵字
--EXISTS 關鍵字只注重子查詢是否返回行,如果子查詢返回一個或多個行,那麼EXISTS 便返回TRUE ,否則返回FALSE 。
--要使EXISTS 關鍵字有意義,則應在子查詢中建立搜尋條件。
SELECT EMPNO, ENAME
  FROM EMP E
 WHERE EXISTS (SELECT *
          FROM DEPT D
         WHERE E.DEPTNO = D.DEPTNO
           AND DEPTNO = 20);
在該語句中外層的SELECT語句返回的每一行資料都要由子查詢來評估。
如果EXISTS關鍵字裡的條件為真則查詢結果中就包含這一行,否則該行被丟棄。因此整個的查詢結果取決於內層的子查詢。
小提示:EXISTS關鍵字的返回值取決於查詢是否會返回行,而不是行的內容,所以子查詢中,輸出列表可以用‘*’代替。
5. 比較運算子
‘=’‘<’‘>’‘<=’‘>=’‘<>’‘!=’
注意:使用比較運算子必須保證子查詢的返回結果只包含一個值。