SQL初階教學

此教學以Oracle環境為主,但基本SQL語法在大部分資料庫寫法都差異不大

以下教學內容可以在SQL Fiddle進行練習,或是自行準備資料庫環境

以SQL為基礎的其他延伸語言

  • Transact-SQL
    微軟MS SQL-Server,以及Sybase Adaptive Server系列資料庫所用的SQL

  • PL-SQL
    Oracle 資料庫所使用的SQL

SQL Fiddle 練習環境

SQL Fiddle

參考下圖,左上角紅色部分可以選擇要進行測試的DB環境是哪一種,中間藍色以及綠色為建立Table和執行SQL,下方橘色為執行結果以及查看執行計畫。

SQL Fiddle

範例資料

可以直接複製到SQL Fiddle左邊區塊然後點選Build Schema後,下方會看見schema ready的成功訊息


CREATE TABLE CUSTOMER
    ("ACCOUNT" varchar2(4), "NAME" varchar2(6), "AGE" int, "GENDER" char(1))
//

INSERT ALL 
    INTO CUSTOMER ("ACCOUNT", "NAME", "AGE", "GENDER")
         VALUES ('A001', 'Olivia', 18, '0')
    INTO CUSTOMER ("ACCOUNT", "NAME", "AGE", "GENDER")
         VALUES ('A002', 'Lily', 22, '0')
    INTO CUSTOMER ("ACCOUNT", "NAME", "AGE", "GENDER")
         VALUES ('A003', 'Emily', 50, '0')
    INTO CUSTOMER ("ACCOUNT", "NAME", "AGE", "GENDER")
         VALUES ('A004', 'Grace', 40, '0')
    INTO CUSTOMER ("ACCOUNT", "NAME", "AGE", "GENDER")
         VALUES ('A005', 'Ruby', 33, '0')
    INTO CUSTOMER ("ACCOUNT", "NAME", "AGE", "GENDER")
         VALUES ('A006', 'Ella', 22, '0')
    INTO CUSTOMER ("ACCOUNT", "NAME", "AGE", "GENDER")
         VALUES ('A007', 'Jack', 16, '1')
    INTO CUSTOMER ("ACCOUNT", "NAME", "AGE", "GENDER")
         VALUES ('A008', 'Teddy', 38, '1')
    INTO CUSTOMER ("ACCOUNT", "NAME", "AGE", "GENDER")
         VALUES ('A009', 'Oscar', 42, '1')
    INTO CUSTOMER ("ACCOUNT", "NAME", "AGE", "GENDER")
         VALUES ('A010', 'Leo', 55, '1')
SELECT * FROM dual
//


CREATE TABLE PRODUCT
    ("ID" varchar2(4), "PRICE" int, "NAME" varchar2(8))
//

INSERT ALL 
    INTO PRODUCT ("ID", "PRICE", "NAME")
         VALUES ('P001', 100, 'Apple')
    INTO PRODUCT ("ID", "PRICE", "NAME")
         VALUES ('P002', 200, 'Book')
    INTO PRODUCT ("ID", "PRICE", "NAME")
         VALUES ('P003', 300, 'Car')
    INTO PRODUCT ("ID", "PRICE", "NAME")
         VALUES ('P004', 400, 'Computer')
    INTO PRODUCT ("ID", "PRICE", "NAME")
         VALUES ('P005', 500, 'Phone')
    INTO PRODUCT ("ID", "PRICE", "NAME")
         VALUES ('P006', 700, 'House')
SELECT * FROM dual
//


CREATE TABLE ORDERS
    ("PRODUCT_ID" varchar2(4), "QUANTITY" int, "CUSTOMER_ACCOUNT" varchar2(4), "CREATEDTIME" timestamp)
//

INSERT ALL 
    INTO ORDERS ("PRODUCT_ID", "QUANTITY", "CUSTOMER_ACCOUNT", "CREATEDTIME")
         VALUES ('P001', 1, 'A001', '01-Jan-2018 10:00:00 AM')
    INTO ORDERS ("PRODUCT_ID", "QUANTITY", "CUSTOMER_ACCOUNT", "CREATEDTIME")
         VALUES ('P001', 3, 'A001', '01-Jan-2018 10:00:00 AM')
    INTO ORDERS ("PRODUCT_ID", "QUANTITY", "CUSTOMER_ACCOUNT", "CREATEDTIME")
         VALUES ('P001', 2, 'A004', '03-Jan-2018 10:00:00 AM')
    INTO ORDERS ("PRODUCT_ID", "QUANTITY", "CUSTOMER_ACCOUNT", "CREATEDTIME")
         VALUES ('P001', 4, 'A002', '03-Jan-2018 10:00:00 AM')
    INTO ORDERS ("PRODUCT_ID", "QUANTITY", "CUSTOMER_ACCOUNT", "CREATEDTIME")
         VALUES ('P001', 5, 'A001', '01-Jan-2018 10:00:00 AM')
    INTO ORDERS ("PRODUCT_ID", "QUANTITY", "CUSTOMER_ACCOUNT", "CREATEDTIME")
         VALUES ('P002', 4, 'A003', '02-Jan-2018 08:00:00 PM')
    INTO ORDERS ("PRODUCT_ID", "QUANTITY", "CUSTOMER_ACCOUNT", "CREATEDTIME")
         VALUES ('P002', 1, 'A001', '02-Jan-2018 08:00:00 PM')
    INTO ORDERS ("PRODUCT_ID", "QUANTITY", "CUSTOMER_ACCOUNT", "CREATEDTIME")
         VALUES ('P003', 2, 'A008', '03-Jan-2018 08:00:00 PM')
    INTO ORDERS ("PRODUCT_ID", "QUANTITY", "CUSTOMER_ACCOUNT", "CREATEDTIME")
         VALUES ('P003', 3, 'A007', '03-Jan-2018 08:00:00 PM')
    INTO ORDERS ("PRODUCT_ID", "QUANTITY", "CUSTOMER_ACCOUNT", "CREATEDTIME")
         VALUES ('P003', 1, 'A006', '02-Jan-2018 08:00:00 PM')
    INTO ORDERS ("PRODUCT_ID", "QUANTITY", "CUSTOMER_ACCOUNT", "CREATEDTIME")
         VALUES ('P004', 2, 'A005', '02-Jan-2018 08:00:00 PM')
    INTO ORDERS ("PRODUCT_ID", "QUANTITY", "CUSTOMER_ACCOUNT", "CREATEDTIME")
         VALUES ('P005', 4, 'A001', '04-Jan-2018 08:00:00 PM')
    INTO ORDERS ("PRODUCT_ID", "QUANTITY", "CUSTOMER_ACCOUNT", "CREATEDTIME")
         VALUES ('P002', 2, 'A008', '04-Jan-2018 08:00:00 PM')
    INTO ORDERS ("PRODUCT_ID", "QUANTITY", "CUSTOMER_ACCOUNT", "CREATEDTIME")
         VALUES ('P002', 5, 'A003', '05-Jan-2018 08:00:00 PM')
    INTO ORDERS ("PRODUCT_ID", "QUANTITY", "CUSTOMER_ACCOUNT", "CREATEDTIME")
         VALUES ('P002', 5, 'A100', '05-Jan-2018 08:00:00 PM')
SELECT * FROM dual
//

基本選取條件語法

建立資料表 (Create)

Create 語法格式

[ ]內為option

CREATE TABLE [schema.]table_name
    ( column datatype [DEFAULT value] [in_constraint_caluse] 
      [,column datatype [DEFAULT value] [in_constraint_caluse]...]
      [,out_constraint_caluse] ) 
[partition_caluse]
[TABLESPACE tablespace_name];
  • schema : 結構名稱
  • table_name : 表格名稱
  • column : 欄位名稱
  • datatype : 資料型態
  • value : 欄位預設值
  • tablespace_name : 表空間名稱

Oracle資料型別

字符資料型別

n為引數

  • CHAR[(n [BYTE | CHAR] )] : 固定長度字串資料型別
  • NCHAR[(n)] : 固定長度Unicode字串資料型別
  • VARCHAR2[(n [BYTE | CHAR] )] : 可變長度字串資料型別
  • NVARCHAR2(n) : 可變長度Unicode字串資料型別
  • CLOB : 字元大型物件(bigfile)資料型別
  • NCLOB : Unicode字元大型物件(bigfile)資料型別

數值資料型別

n為引數
n1為整數值幾位
n2為小數點下幾位

  • NUMBER[(n1[,n2])] : 帶有精密度和位數的數值資料型別
  • FLOAT[(n)] : NUMBER的子型別
  • BINARY_FLOAT : 浮點數(32位元)資料型別
  • BINARY_DOUBLE : 浮點數(64位元)資料型別

日期時刻及期間資料型別

n為引數
n1為日期的位數
n2為秒的小數部分位數

  • DATE : 日期格式
  • TIMESTAMP[(n)] : 日期和時間格式
  • TIMESTAMP[(n)] WITH TIME ZONE : 整個TIMESTAMP與時區及個世界地區時差
  • TIMESTAMP[(n)] WITH LOCAL TIME ZONE : 整個TIMESTAMP沒有世界地區時差
  • INTERVAL YEAR[(n)] TO MONTH : 期間(年月單位)
  • INTERVAL DAY[(n1)] TO SECODE[(n2)] : 期間(日時分秒單位)

二進制資料型別

size:RAW資料的位元組數

  • BLOB : 二進制大型物件(例如:影像檔,圖片檔)
  • BFILE : 二進制檔案的定位符
  • RAW(size) : 二進制資料

ROWID資料型別

n為資料型別長度

  • ROWID : 用來表示列位址的BASE64字串
  • UROWID[(n)] : 用來表示索引構成表格列之邏輯位址的BASE64字串

SELECT

從表格中選取出資料

SELECT “欄位名” FROM “表格名”;

SELECT FROM TABLE 代表所有欄位

取出所有客戶的名稱

SELECT NAME FROM CUSTOMER

如果希望取出來的資料可以更換名稱,可以為欄位取別名
用法為欄位後面空一格填上名稱(需注意避開保留字)

SELECT NAME USERNAME 
FROM CUSTOMER AA

DISTINCT

取出資料時排除重複的資料

SELECT DISTINCT “欄位名”

FROM “表格名”;

取出ORDERS中不重複的CREATEDTIME

SELECT DISTINCT CREATEDTIME 
FROM ORDERS

WHERE

選取資料時不一定都需要全部的資料,WHERE可以有條件的選取資料

基本的運算子有 >、>=、<=、<、=、<>(不等於)

常用的還有 IS NULL、 IS NOT NULL

SELECT “欄位名”

FROM “表格名”

WHERE “條件”;

取出ORDERS中CUSTOMER_ACCOUNT為A001的資料

SELECT * 
FROM ORDERS
WHERE CUSTOMER_ACCOUNT = 'A001'

AND、OR

使用WHERE時可能條件不只一個,此時就要使用AND OR將條件串連起來,然後可以搭配( )來表示條件的先後順序

  • AND : 代表雙邊條件都要成立
  • OR : 雙邊條件其中一方成立

SELECT “欄位名”

FROM “表格名”

WHERE “簡單條件”

{[AND|OR] “簡單條件”}+;

取出CUSTOMER為女性且AGE超過40或低於20

SELECT * 
FROM CUSTOMER
WHERE GENDER = '0'
AND (AGE > 40 OR AGE < 20)

IN

當WHERE的條件在同一個欄位一次比對多個值時可以使用IN將要比對的值都放入

SELECT “欄位名”
FROM “表格名”
WHERE “欄位名” IN (‘值一’, ‘值二’, …);

取出CUSTOMER的NAME為Olivia,Lily,Emily的資料

SELECT * 
FROM CUSTOMER
WHERE NAME IN ('Olivia','Lily','Emily')

BETWEEN

當WHERE對一個範圍下條件使用BETWEEN,條件類似>=、<=

SELECT “欄位名”

FROM “表格名”

WHERE “欄位名” BETWEEN ‘值一’ AND ‘值二’;

取出CUSTOMER的AGE在30到50之間的資料

SELECT * 
FROM CUSTOMER
WHERE AGE BETWEEN 30 AND 50

萬用字元

有的時候,我們需要依照由字串模式中找出相符的資料。要滿足這個需求,我們就需要用到萬用字元 (wildcard) 的做法。SQL 中有兩個萬用字元:

% (百分比符號):代表零個、一個、或數個字母。

_ (底線):代表剛好一個字母。

萬用字元是與 LIKE 關鍵字一起使用的。

以下是幾個萬用字元的例子:

  • ‘A_Z’: 所有以 ‘A’ 起頭,另一個任何值的字原,且以 ‘Z’ 為結尾的字串。 ‘ABZ’ 和 ‘A2Z’ 都符合這一個模式,而 ‘AKKZ’ 並不符合 (因為在 A 和 Z 之間有兩個字元,而不是一個字元)。
  • ‘ABC%’: 所有以 ‘ABC’ 起頭的字串。舉例來說,’ABCD’ 和 ‘ABCABC’ 都符合這個模式。
  • ‘%XYZ’: 所有以 ‘XYZ’ 結尾的字串。舉例來說,’WXYZ’ 和 ‘ZZXYZ’ 都符合這個模式。
  • ‘%AN%’: 所有含有 ‘AN’這個模式的字串。舉例來說, ‘LOS ANGELES’ 和 ‘SAN FRANCISCO’ 都符合這個模式。
  • ‘_AN%’: 所有第二個字母為 ‘A’ 和第三個字母為 ‘N’ 的字串。舉例來說,’SAN FRANCISCO’ 符合這個模式,而 ‘LOS ANGELES’ 則不符合這個模式。

取出CUSTOMER中NAME含有’e’的資料

SELECT * 
FROM CUSTOMER
WHERE NAME LIKE '%e%'

ORDER BY

對資料進行排序

  • ASC : 從小到大
  • DESC : 從大到小

沒有寫出的話預設為ASC

SELECT “欄位名”

FROM “表格名”

[WHERE “條件”]

ORDER BY “欄位名” [ASC, DESC];

取出CUSTOMER用AGE從大到小排序

SELECT * 
FROM CUSTOMER
ORDER BY AGE DESC

函數語法

SQL有提供一些可以對數值欄位做計算的函數

  • AVG (平均)
  • COUNT (計數)
  • MAX (最大值)
  • MIN (最小值)
  • SUM (總合)

SELECT “函數名”(“欄位名”)

FROM “表格名”;

AVG

計算CUSTOMER的AGE平均

SELECT AVG(AGE)
FROM CUSTOMER

COUNT

計算CUSTOMER的資料筆數

SELECT COUNT(*)
FROM CUSTOMER

COUNT 常搭配 DISTINCT來使用,用來計算此欄位有多少個不同的值

計算CUSTOMER中有多少筆不相同的NAME

SELECT COUNT(DISTINCT NAME)
FROM CUSTOMER

MAX

取得CUSTOMER的AGE中最大的值

SELECT MAX(AGE)
FROM CUSTOMER

MIN

取得CUSTOMER的AGE中最小的值

SELECT MIN(AGE)
FROM CUSTOMER

SUM

加總CUSTOMER的AGE

SELECT SUM(AGE)
FROM CUSTOMER

GROUP BY

上面那個計算函數都是針對選取出來的資料對全部做計算,我們可以使用GROUP BY將資料進行分組來做計算

SELECT “欄位1”, SUM(“欄位2”)

FROM “表格名”

GROUP BY “欄位1”;

取得CUSTOMER的AGE平均並且用GENDER來分組,這樣就可以看到男女的平均年齡比較

SELECT GENDER, AVG(AGE)
FROM CUSTOMER
GROUP BY GENDER

HAVING

對函數產生的值來設定條件

SELECT “欄位1”, SUM(“欄位2”)

FROM “表格名”

GROUP BY “欄位1”

HAVING (函數條件);

在上面GROUP BY的例子我們可以看到根據GENDER分組計算出來的平均

現在只想看到計算出來結果大於35的資料

SELECT GENDER, AVG(AGE)
FROM CUSTOMER
GROUP BY GENDER
HAVING AVG(AGE) > 35

相關資料

SQL初階教學2