1. 程式人生 > >Oracle:資料查詢語言-DQL-select

Oracle:資料查詢語言-DQL-select

SELECT語句功能

投影操作:結果集是源表中的部分列。

選擇操作:結果集是源表中的部分行。

連線操作:將兩張表裡的行按某種條件組合成一條長長的行放入結果集。

最基本的用法:SELECT ……FROM……

SELECT子句

用於指定欄位名,多個欄位名用逗號隔開,*代表所有列。

SELECT後面可以跟列,字元,表示式,DISTINCT關鍵字(去掉重複行),函式,常量,組標識。完成對資料的處理。

FROM子句

用於指定表名。

例如:SELECT DISTINCT NAME FROM TEST;  

WHERE子句

根據條件過濾出需要處理的資料,對行過濾。後面跟條件表示式(列名,常量,比較運算子,文字值,不能跟列別名),可以用AND,OR連線多個條件表示式。

語法順序:SELECT……FROM……WHERE……

例如:SELECT NAME FROM TEST WHERE ID = 10001;  

ORDER BY子句

SELECT語句的最後一個子句,也是最後執行的子句,功能是改變記錄的輸出順序,排序。

ASC(預設/預設) 升序,DESC降序。

ORDER BY後面可以跟列名,表示式,列別名,列在結果集中的位置值。

ORDER BY 後面可以跟多列,用逗號隔開。

NULL值在ORDER BY 子句中排序的順序是:降序排在最上,升序排在最下。

語法順序:SELECT ——> FROM ——> WHERE ——> ORDER BY

執行順序:FROM ——> WHERE ——> SELECT ——> ORDER BY

例如:SELECT * FROM TEST ORDER BY NAME DESC;  

GROUP BY子句

功能是根據指定的列對行進行分組

語法順序:SELECT……FROM……WHERE……GROUP BY……ORDER BY……

執行順序:FROM……WHERE……GROUP BY……SELECT……ORDER BY……

例如:SELECT NAME FROM SERVICE GROUP BY NAME;  

注意:

在SELECT語句中,如果沒有GROUP BY子句,若在SELECT子句中有一個組函式,那麼其他都必須是組函式,否則會報錯。

在SELECT語句中,如果有GROUP BY子句,SELECT子句中可跟組函式,或GROUP BY後面的表示式、組標識,其他會報錯。

GROUP BY中包含多列的情況,用逗號隔開,分組的粒度更細,每組的記錄少了,但組多了。

行級資訊和組級資訊不可以同時顯示出來。

HAVING 子句

功能是對組過濾,後面接條件表示式。

語法順序:SELECT……FROM……WHERE……GROUP BY……HAVING……ORDER BY……

執行順序:FROM……WHERE……GROUP BY……HAVING……SELECT……ORDER BY……

WHERE和HAVING 的區別:

1、WHERE過濾的是行(記錄)

2、HAVING過濾的是分組(組標識,每組資料的聚合結果)

3、WHERE後面可以跟任意列名,單行函式,不能跟組函式

4、HAVING後面只能跟組函式、組標識、GROUP BY後面的表示式

5、WHERE子句執行在前,HAVING子句執行在後

6、WHERE子句和HAVING子句都不允許有列別名

設定結果集每頁顯示的記錄數

SET PAGESIZE 記錄數;  

設定顯示結果集時每行的長度

SET LINESIZE 長度;  

設定當前會話的日期格式

ALTER SESSION SET NLS_DATE_FORMAT='格式';  

例如:  

ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS';  

把SELECT出來的結果導到一個文字檔案中

SPOOL 路徑\檔名.TXT;   

SELECT * FROM 表名;   

SPOOL OFF;   

新建兩個表,並插入一些資料:
CREATE TABLE CUSTOMER_TEST(ID VARCHAR2(48),
                           CODE VARCHAR2(48),
                           NAME VARCHAR2(58),
                           TEL VARCHAR2(16),
                           ADDRESS VARCHAR2(80),
                           CREATETIME TIMESTAMP DEFAULT SYSDATE,
                           REMARK VARCHAR2(80));

INSERT INTO CUSTOMER_TEST
  (ID, CODE, NAME, TEL, ADDRESS, CREATETIME, REMARK)
VALUES
  ('C000000000000000000001',
   'C000000000000000000001',
   '張三',
   '15044447777',
   '廣東深圳寶安XXXX',
   TO_DATE('2015-01-01 09:30:29', 'yyyy-mm-dd hh24:mi:ss'),
   'ABCDEFG');

INSERT INTO CUSTOMER_TEST
  (ID, CODE, NAME, TEL, ADDRESS, CREATETIME, REMARK)
VALUES
  ('C000000000000000000002',
   'C000000000000000000002',
   '李四',
   '15122336548',
   '廣東深圳寶安XXXX',
   TO_DATE('2015-01-01 11:30:29', 'yyyy-mm-dd hh24:mi:ss'),
   'ABCDEFG');

INSERT INTO CUSTOMER_TEST
  (ID, CODE, NAME, TEL, ADDRESS, CREATETIME, REMARK)
VALUES
  ('C000000000000000000003',
   'C000000000000000000003',
   '王五',
   '13456892112',
   '廣東深圳寶安XXXX',
   TO_DATE('2016-02-01 10:30:29', 'yyyy-mm-dd hh24:mi:ss'),
   'ABCDEFG');

INSERT INTO CUSTOMER_TEST
  (ID, CODE, NAME, TEL, ADDRESS, CREATETIME, REMARK)
VALUES
  ('C000000000000000000004',
   'C000000000000000000004',
   '趙六',
   '17766522233',
   '廣東深圳寶安XXXX',
   TO_DATE('2016-02-10 09:30:29', 'yyyy-mm-dd hh24:mi:ss'),
   'ABCDEFG');

INSERT INTO CUSTOMER_TEST
  (ID, CODE, NAME, TEL, ADDRESS, CREATETIME, REMARK)
VALUES
  ('C000000000000000000005',
   'C000000000000000000005',
   '劉七',
   '13154546666',
   '廣東深圳寶安XXXXX',
   TO_DATE('2016-03-01 09:30:29', 'yyyy-mm-dd hh24:mi:ss'),
   'ABCDEFG');

COMMIT;

CREATE TABLE ORDER_TEST(ID VARCHAR2(48),
                        CUSTOMERID VARCHAR2(48),
                        COMMODITYIDS VARCHAR2(800),
                        ORDERNUMBER VARCHAR2(48),
                        ORDERTIME       TIMESTAMP DEFAULT SYSDATE,
                        REMARK VARCHAR2(80),
                        DELIVERYADDRESS VARCHAR2(80));

INSERT INTO ORDER_TEST
  (ID, CUSTOMERID, COMMODITYIDS, ORDERNUMBER, ORDERTIME, REMARK, DELIVERYADDRESS)
VALUES
  ('O000000000000000000001',
   'C000000000000000000001',
   'C001,C002,C003,C004,C005',
   'O000000000000000000001',
   TO_DATE('2016-01-01 17:09:50', 'yyyy-mm-dd hh24:mi:ss'),
   '不要錯了',
   '廣東廣州白雲XXXXX');

INSERT INTO ORDER_TEST
  (ID, CUSTOMERID, COMMODITYIDS, ORDERNUMBER, ORDERTIME, REMARK, DELIVERYADDRESS)
VALUES
  ('O000000000000000000002',
   'C000000000000000000001',
   'C001,C002,C003,C004,C005',
   'O000000000000000000002',
   TO_DATE('2016-03-10 17:09:50', 'yyyy-mm-dd hh24:mi:ss'),
   '不要錯了',
   '廣東廣州白雲XXXXX');
   
INSERT INTO ORDER_TEST
  (ID, CUSTOMERID, COMMODITYIDS, ORDERNUMBER, ORDERTIME, REMARK, DELIVERYADDRESS)
VALUES
  ('O000000000000000000003',
   'C000000000000000000002',
   'C001,C002,C003,C004,C005',
   'O000000000000000000003',
   TO_DATE('2016-03-11 17:09:50', 'yyyy-mm-dd hh24:mi:ss'),
   '不要錯了',
   '廣東東莞虎門XXXXX');
   
INSERT INTO ORDER_TEST
  (ID, CUSTOMERID, COMMODITYIDS, ORDERNUMBER, ORDERTIME, REMARK, DELIVERYADDRESS)
VALUES
  ('O000000000000000000004',
   'C000000000000000000003',
   'C001,C002,C003,C004,C005',
   'O000000000000000000004',
   TO_DATE('2016-03-11 17:09:50', 'yyyy-mm-dd hh24:mi:ss'),
   '不要錯了',
   '廣東東莞后街XXXXX');   
   
INSERT INTO ORDER_TEST
  (ID, CUSTOMERID, COMMODITYIDS, ORDERNUMBER, ORDERTIME, REMARK, DELIVERYADDRESS)
VALUES
  ('O000000000000000000005',
   'C000000000000000000004',
   'C001,C002,C003,C004,C005',
   'O000000000000000000005',
   TO_DATE('2016-02-11 17:09:50', 'yyyy-mm-dd hh24:mi:ss'),
   '不要錯了',
   '廣東東莞后街XXXXX');   
   
COMMIT;   

非關聯子查詢:在查詢過程中內表不需要引用主表中的列

先執行子查詢,子查詢的結果作為條件,再執行主查詢。子查詢只執行一次。

查詢在2016年2月有訂單的客戶:

SQL> SELECT C.NAME

  2    FROM CUSTOMER_TEST C

  3   WHERE C.ID IN

  4         (SELECT O.CUSTOMERID

  5            FROM ORDER_TEST O

  6           WHERE O.ORDERTIME >=

  7                 TO_DATE('2016-02-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')

  8             AND O.ORDERTIME <=

  9                 TO_DATE('2016-02-29 23:59:59', 'yyyy-mm-dd hh24:mi:ss'));

NAME

-----------------

趙六

關聯子查詢:在子查詢中引用主表中的列

查詢在2016年2月有訂單的客戶:

SQL> SELECT C.NAME

  2    FROM CUSTOMER_TEST C

  3   WHERE EXISTS (SELECT 1

  4            FROM ORDER_TEST O

  5           WHERE O.ORDERTIME >=

  6                 TO_DATE('2016-02-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')

  7             AND O.ORDERTIME <=

  8                 TO_DATE('2016-02-29 23:59:59', 'yyyy-mm-dd hh24:mi:ss')

  9             AND C.ID = O.CUSTOMERID);

NAME

------------------

趙六

多列子查詢:主查詢的where條件中可以用多個列進行過濾(多列條件表示式)

查詢收貨地址相同,且購買商品相同的客戶:

SQL> SELECT C.NAME

  2    FROM CUSTOMER_TEST C

  3   WHERE C.ID IN (SELECT O.CUSTOMERID

  4                    FROM ORDER_TEST O

  5                   WHERE (O.COMMODITYIDS, O.DELIVERYADDRESS) IN

  6                         (SELECT O.COMMODITYIDS, O.DELIVERYADDRESS

  7                            FROM ORDER_TEST O

  8                           GROUP BY O.COMMODITYIDS, O.DELIVERYADDRESS

  9                          HAVING COUNT(DISTINCT O.CUSTOMERID) > 1));

NAME

------------

王五

趙六

EXISTS:用於檢查子查詢是否至少會返回一行資料,實際上並不在乎子查詢返回任何具體資料,而是在乎是否有值返回,有則是True否則為False。

查詢在2016年2月有訂單的客戶:

SQL> SELECT C.NAME

  2    FROM CUSTOMER_TEST C

  3   WHERE EXISTS (SELECT 1

  4            FROM ORDER_TEST O

  5           WHERE O.ORDERTIME >=

  6                 TO_DATE('2016-02-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')

  7             AND O.ORDERTIME <=

  8                 TO_DATE('2016-02-29 23:59:59', 'yyyy-mm-dd hh24:mi:ss')

  9             AND C.ID = O.CUSTOMERID);

NAME

---------------

趙六

NOT EXISTS:與exists相反。

查詢在2016年2月沒有訂單的客戶:

SQL> SELECT C.NAME

  2    FROM CUSTOMER_TEST C

  3   WHERE NOT EXISTS

  4   (SELECT 1

  5            FROM ORDER_TEST O

  6           WHERE O.ORDERTIME >=

  7                 TO_DATE('2016-02-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')

  8             AND O.ORDERTIME <=

  9                 TO_DATE('2016-02-29 23:59:59', 'yyyy-mm-dd hh24:mi:ss')

 10             AND C.ID = O.CUSTOMERID);

NAME

-----------------

王五

張三

李四

劉七

IN與EXISTS的比較

如果子查詢得出的結果集記錄較少,主查詢中的表較大且又有索引時應該用IN。

反之如果外層的主查詢記錄較少,子查詢中的表大,又有索引時使用EXISTS。

其實我們區分IN和EXISTS主要是造成了驅動順序的改變(這是效能變化的關鍵),如果是EXISTS,那麼以外層表為驅動表,先被訪問,如果是IN,那麼先執行子查詢,所以我們會以驅動表的快速返回為目標,那麼就會考慮到索引及結果集的關係了。

表連線查詢

交叉連線(CROSS JOIN)

假設TABLE1中有M條記錄,TABLE2中有N條記錄,那麼交叉連線的結果集為M*N條記錄。該連線產生的結果集稱為笛卡爾集。

SQL> SELECT COUNT(1) FROM CUSTOMER_TEST C, ORDER_TEST O;

  COUNT(1)

----------

        25

SQL> SELECT COUNT(1) FROM CUSTOMER_TEST C CROSS JOIN ORDER_TEST O;

  COUNT(1)

----------

        25

內連線(INNER JOIN)

任何一張表裡的記錄一定要在另一張表中找到匹配的記錄,否則不能出現在結果集中。

查詢在2016年2月有訂單的客戶:

SQL> SELECT C.NAME

  2    FROM CUSTOMER_TEST C

  3   INNER JOIN ORDER_TEST O

  4      ON C.ID = O.CUSTOMERID

  5   WHERE O.ORDERTIME >=

  6         TO_DATE('2016-02-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')

  7     AND O.ORDERTIME <=

  8         TO_DATE('2016-02-29 23:59:59', 'yyyy-mm-dd hh24:mi:ss');

NAME

-------------

趙六

SQL> SELECT C.NAME

  2    FROM CUSTOMER_TEST C, ORDER_TEST O

  3   WHERE C.ID = O.CUSTOMERID

  4     AND O.ORDERTIME >=

  5         TO_DATE('2016-02-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')

  6     AND O.ORDERTIME <=

  7         TO_DATE('2016-02-29 23:59:59', 'yyyy-mm-dd hh24:mi:ss');

NAME

--------------

趙六

外連線(LEFT JOIN, RIGHT JOIN, FULL JOIN)

左連線LEFT OUTER JOIN

查詢每個使用者單號:

SQL> SELECT C.NAME, O.ORDERNUMBER

  2    FROM CUSTOMER_TEST C

  3    LEFT JOIN ORDER_TEST O

  4      ON C.ID = O.CUSTOMERID

  5   ORDER BY C.NAME;

NAME                    ORDERNUMBER

----------------------- ------------------------------------------

劉七                                                       

張三                                                       O000000000000000000001

張三                                                       O000000000000000000002

李四                                                       O000000000000000000003

王五                                                       O000000000000000000004

趙六                                                       O000000000000000000005

RIGHT OUTER JOIN

查詢每個使用者單號:

SQL> SELECT O.ORDERNUMBER, C.NAME

  2    FROM ORDER_TEST O

  3   RIGHT JOIN CUSTOMER_TEST C

  4      ON C.ID = O.CUSTOMERID

  5   ORDER BY C.NAME;

ORDERNUMBER                       NAME

--------------------------------- -------------

                                                                                          劉七

O000000000000000000001            張三

O000000000000000000002            張三

O000000000000000000003            李四

O000000000000000000004            王五

O000000000000000000005            趙六

FULL OUTER JOIN

FROM後面跟子查詢

在表連線過程中,有時候需要先對其中一個表先進行資料過濾在連線,這就是在FROM後面跟子查詢。

這種情況會先執行子查詢,將子查詢的結果集作為一個表與另一個表進行連線。

查詢在2016年2月有訂單的客戶及其訂單號:

SQL> SELECT C.NAME, O.ORDERNUMBER

  2    FROM (SELECT CUSTOMERID, ORDERNUMBER

  3            FROM ORDER_TEST

  4           WHERE ORDERTIME >=

  5                 TO_DATE('2016-02-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')

  6             AND ORDERTIME <=

  7                 TO_DATE('2016-02-29 23:59:59', 'yyyy-mm-dd hh24:mi:ss')) O

  8    JOIN CUSTOMER_TEST C

  9      ON C.ID = O.CUSTOMERID;

NAME           ORDERNUMBER

-------------- ---------------------------

趙六                              O000000000000000000005

結果集運算

UNION/UNION ALL:結果集為兩個查詢結果的並集。UNION會進行對資料進行去重操作;UNION ALL直接將兩個結果集合並在一起,不會去重。

INTERSECT:結果集為兩個查詢結果的交集。

MINUS:結果集屬於第一個查詢結果,但不屬於第二個查詢結果。即為第一個查詢結果集減去與第二個查詢結果集的交集。

集合運算中,要求兩個SELECT語句中列的個數、資料型別是一樣的(即同構的)。

分頁查詢

Oracle的分頁利用ROWNUM

ROWNUM是一個偽列,對查詢返回的行進行編號即行號,從1開始遞增。ORACLE的ROWNUM值是在獲得每行之後才賦予的。

SQL> SELECT ROWNUM, C.NAME FROM CUSTOMER_TEST C;

    ROWNUM NAME

---------- -------------------

         1 張三

         2 李四

         3 王五

         4 趙六

         5 劉七

ROWNUM的產生:

假如有一條查詢語句為SELECT XX,YY FROM TABLE WHERE ZZ > 20 AND ROWNUM < 10。

執行FROM TABLE,從中取出第一條記錄,系統給這條記錄進行ROWNUM編號為1;

執行WHERE子句,判斷記錄是否符合條件表示式,符合則留下,不符合就丟棄;

從TABLE中取出第二條記錄,這條記錄的ROWNUM編號,為前一條符合條件被留下的記錄的ROWNUM + 1;

重複前面的步驟,直到不符合ROWNUM < 10為止。

例如:當前頁碼pageIndex為3,頁容量pageSize為2,查詢當前頁的資料:

SQL> SELECT ROW_.*

  2    FROM (SELECT ROWNUM RN, C.NAME FROM CUSTOMER_TEST C WHERE ROWNUM <= 3 * 2) ROW_

  3   WHERE ROW_.RN > (3 - 1) * 2;

        RN NAME

---------- -----------------

         5 劉七

分頁查詢開始的startRowNum = (pageIndex - 1) * pageSize; 結束endRowNum = pageIndex * pageSize + 1。startRowNum與endRowNum都不包含在當前頁中。