《SQL初學(xué)者指南》讀書筆記

關(guān)系型數(shù)據(jù)庫和SQL

  • SQL語言的三個部分
    • DML:Data Manipulation Language深夯,數(shù)據(jù)操縱語言,檢索钝腺、修改谦铃、增加耘成、刪除數(shù)據(jù)庫(表)中的數(shù)據(jù)
    • DDL:Data Definition Language,數(shù)據(jù)定義語言荷辕,創(chuàng)建和修改數(shù)據(jù)庫(表)本身
    • DCL:Data Control Language亡蓉,維護(hù)數(shù)據(jù)庫安全
  • 關(guān)系型數(shù)據(jù)庫基本術(shù)語
    • relational(關(guān)系):表示各表彼此關(guān)聯(lián)
    • record(記錄):表中的行(row)
    • field(字段):表中的列(column)
    • primary key:表的主鍵搭综,通常為自增型(auto-increment)就斤,本身沒有特殊含義唁毒,只用于保證每一行都有一個唯一的值
    • foreign key:表的外鍵,確保這一列有一個有效的值骡显,通常會把某個其他表的共同列疆栏,通常是主鍵作為外鍵曾掂,比如訂單表中的客戶列
    • column(field)的數(shù)據(jù)類型(更詳細(xì)的數(shù)據(jù)類型介紹參見SQL數(shù)據(jù)類型
      • 數(shù)字
      • bit:位,只允許0和1
      • integer:整數(shù)壁顶,不含小數(shù)位
      • decimal:浮點(diǎn)數(shù)珠洗,含小數(shù)位
      • real number:實數(shù)
    • 字符:string/character string類型,在SQL語句中需要用引號括起來
    • 日期/時間:用于表示日期和時間若专,在SQL語句中需要用引號括起來许蓖,允許對所涉及的日期進(jìn)行特殊運(yùn)算
    • NULL:空值,非數(shù)據(jù)類型调衰,而是在允許包含空值的列中表示空置

基本數(shù)據(jù)檢索

  • SQL語句不區(qū)分大小寫膊爪,且可以寫成任意多行
  • 可以把重要關(guān)鍵字作為單獨(dú)一行凸顯語義
  • 從表中選擇所有:SELECT * FROM tablename
  • 指定列:SELECT columnname FROM tablename
  • 指定多個列:SELECT column1, column2 FROM tablename
  • 帶空格的列名:Microsoft SQL Server使用方括號[],MySQL使用重音符`嚎莉,Oracle使用雙引號

計算字段和別名

  • 計算字段
    • 直接量:與表中數(shù)據(jù)沒有任何關(guān)系的值叫做literal value(直接量)米酬,字符串直接量需要加引號,數(shù)字直接量不需要
    • 算數(shù)運(yùn)算:允許使用列數(shù)據(jù)與直接量或其它列數(shù)據(jù)進(jìn)行加減乘除運(yùn)算趋箩,比如SELECT QuantityPurchased * PricePerItem FROM Orders
    • 連接字段:把字符數(shù)據(jù)連接或組合到一起赃额,Microsoft SQL Server使用加號+,MySQL使用CONCAT()函數(shù)連接字符串叫确,Oracle使用雙豎線||
  • 別名
    • 列的別名:用于修改列(表頭)標(biāo)題或為計算字段提供列(表頭)標(biāo)題跳芳,比如SELECT f_n AS 'first_name' from customers
    • 表的別名:通常有三種情況需要修改表名稱,a.不好理解或復(fù)雜的表名竹勉,b.從多個表中進(jìn)行選擇筛严,c.使用子查詢;SELECE something from someshittablename AS another_table_name

使用函數(shù)

  • Scalar function:標(biāo)量函數(shù)饶米,針對單行中的數(shù)據(jù)執(zhí)行
  • Aggregate function:聚合函數(shù),針對較大的數(shù)據(jù)集合進(jìn)行操作
  • 字符函數(shù)
    • LEFT/RIGHT (string, numberOfCharactors):從左/右取字符串?dāng)?shù)據(jù)的指定位數(shù)车胡,在Oracle中以SUBSTR替代
    • SUBSTRING (string, start, end):取得字符串?dāng)?shù)據(jù)的子字符串檬输,在Oracle中以SUBSTR替代
    • LTRIM/RTRIM (string):刪除字符串?dāng)?shù)據(jù)左側(cè)/右側(cè)的空格
    • CONCAT (string1, string2, string3 ...):拼接多個字符串,Oracle中只允許拼接兩個字符串
    • UPPER/LOWER (string):返回字符串的大/小寫
  • 復(fù)合函數(shù):函數(shù)的嵌套使用被稱為復(fù)合函數(shù)匈棘,比如RIGHT(RTRIM(something)) AS 'something'
  • 日期時間函數(shù)
    • GETDATE/NOW/CURRENT_DATE ():三個函數(shù)都用于獲取當(dāng)前時間丧慈,對應(yīng)Microsoft SQL Server/MySql/Oracle三家數(shù)據(jù)庫的實現(xiàn)
    • DATEPART (date_part, date_value):單獨(dú)返回某個部分的時間,date_part為需要返回的時間部分主卫,date_value為原始時間逃默,MySQL的實現(xiàn)為DATE_FORMAT(date_value, date_format),date_value為原始時間,date_format為類似于%d這樣的格式用于告訴函數(shù)需要返回哪部分時間簇搅,date_part的有效值為:year/quarter/month/dayofyear/day/month/hour/minute/second
    • DATEDIFF (date_part, start_date, end_date):用于計算任意兩個不同日期間相差的時間完域,在MySQL中該函數(shù)之允許計算天數(shù)差異,所以date_part參數(shù)不可用瘩将,僅需要傳入兩個日期即可
  • 數(shù)值函數(shù)(數(shù)學(xué)函數(shù))
    • ROUND (NumbericValue, DecimalPlaces):對任意數(shù)進(jìn)行四舍五入吟税,NumbericValue表示要四舍五入的數(shù)凹耙,DecimalPlaces表示從第幾位開始四舍五入(即需要保留到第幾位),以十分位為0肠仪,向左為負(fù)數(shù)肖抱,向右為正數(shù)
    • RAND ([seed]):產(chǎn)生一個隨機(jī)數(shù) ,可選的seed參數(shù)為一個整數(shù)异旧,用于每次返回相同的值
    • PI ():返回數(shù)學(xué)運(yùn)算中的pi值
  • 轉(zhuǎn)換函數(shù)
    • CAST (expression AS data_type):將數(shù)據(jù)從一種類型轉(zhuǎn)換為另一種類型意述,expression表示數(shù)據(jù)或函數(shù)表達(dá)式,data_type表示需要轉(zhuǎn)換到的數(shù)據(jù)類型吮蛹,一般情況下SQL在做計算時會進(jìn)行自動的類型轉(zhuǎn)換荤崇,所以很少用到這個函數(shù),它的典型使用場景是當(dāng)一個日期被保存成了字符串匹涮,需要轉(zhuǎn)換為真正的日期數(shù)據(jù):CAST('2017-5-1', AS DATETIME)天试,Oracle中該函數(shù)的參數(shù)形式會不一樣
    • ISNULL/IFNULL/NVL (column_data_maybe_null, if_null_will_use_this_data ):將NULL值轉(zhuǎn)換為一個有意義的值,對應(yīng)Microsoft SQL Server/MySql/Oracle三家數(shù)據(jù)庫的實現(xiàn)

排序數(shù)據(jù)

排序數(shù)據(jù)的語法如下:

SELECT
column1,
column2
FROM table1, table2
ORDER BY column3, column2 DESC
  • ORDER BY 句子總是在FROM子句之后然低,FROM子句總是在SELECT關(guān)鍵字之后
  • SELECTORDER BY后面指定的列喜每,可能是完全不同的一些列
  • 使用關(guān)鍵字ASCDESC來升序/降序排列
  • ORDER BY后指定了多列,則首先按照第一列排序雳攘,如遇相同則相同的行按第二列排序带兜,以此類推
  • 根據(jù)計算字段排序時,如果計算字段已經(jīng)出現(xiàn)在SELECT關(guān)鍵字后吨灭,則只需要在ORDER BY子句中指定計算字段的別名即可(經(jīng)測試在MySQL中如果計算字段別名帶有空格則暫時無法在此引用刚照,因為不能使用引號),如果計算字段沒有出現(xiàn)在SELECT關(guān)鍵字后喧兄,則可直接在ORDER BY子句中指定一個計算字段无畔,例如:
    SELECT
    title,
    rental_duration,
    rental_rate
    FROM film
    ORDER BY rental_duration * rental_rate DESC
    
  • 按升序排列時,大部分的SQL數(shù)據(jù)庫都會是按NULL(Oracle中排在最后吠冤,可使用NULLS FIRST關(guān)鍵字來強(qiáng)制最先)-數(shù)字-字符(字符中首先顯示數(shù)字字符浑彰,再顯示普通字符,除Oracle外不區(qū)分大小寫)來進(jìn)行排序拯辙,反之亦然郭变。

基于列的邏輯

  • 基于列的邏輯主要用于根據(jù)邏輯條件改變想要展現(xiàn)給用戶的輸出
  • 簡單格式:判斷某列的值為某個具體值后將其轉(zhuǎn)換為一個其它值
SELECT column1, column2
CASE column3
WHEN value1 THEN result1
WHEN value2 THEN value2
(repeat WHEN-THEN any number of times)
[ELSE defaul_result]
END
column4
FROM tablename
  • 查詢格式:判斷一列或多列中的某個值是否符合某個條件而將其轉(zhuǎn)換為一個其它值并顯示在一列中
SELECT
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN  result2
(repeat WHEN-THEN any number of times)
[ELSE defaul_result]
END AS custom_column_name,
FROM tablename

# 最新版的MySQL語法與書中的語法有細(xì)微差別:
# ELSE子句最后不需要逗號

SELECT
title,
CASE
WHEN rental_duration = 3 THEN 'Three Day Left'
WHEN rental_rate = 0.99 THEN 'Cheapest'
ELSE 'Normal'
END AS 'Rental Status'
FROM film

基于行的邏輯

  • 基于行的邏輯主要用于獲取滿足特定條件的數(shù)據(jù)
  • 應(yīng)用查詢條件
    • SQL中的查詢條件從WHERE子句開始
    • WHERE子句總是在FROMORDER BY 子句之間,實際上任何“子句”都必須按照這個順序來
      SELECT columnList
      FROM tableList
      WHERE condition
      ORDER BY columnList
      
  • WHERE子句操作符涯保,以下這些操作符都可以在基于列的邏輯CASE WHEN condition語句中使用
    • 等于:=
    • 不等于:<>
    • 大于:>
    • 小于:<
    • 大于等于:>=
    • 小于等于:<=
    SELECT
    first_name,
    last_name
    FROM actor
    WHERE age > 18
    
  • 限制行
    • 使用TOP/LIMIT/ROWNUM(對應(yīng)Microsoft SQL Server诉濒、MySQL和Oracle)限制行數(shù)(關(guān)鍵字TOP返回的行,并不是真的隨機(jī)樣本夕春,而是根據(jù)數(shù)據(jù)庫中的物理存儲方式限定了前幾行數(shù)據(jù)而已)
      # Microsoft SQL Server
      SELECT
      TOP number
      columnList
      FROM table
      
      # MySQL
      SELECT
      columnList
      FROM table
      LIMIT number
      
      # Oracle
      SELECT
      columnList
      FROM table
      WHERE ROWNUM <= number
      
    • 結(jié)合SORT BY子句做“Top N”查詢(基于特定分類未荒,得到帶有最大/小值的一定數(shù)量的行)
      # 本月賣得最好的莎士比亞的三本書
      # MySQL
      SELECT
      title AS 'Book Title',
      current_month_sale AS 'Quantity Sold'
      FROM books
      WHERE author = 'Shakespear'
      LIMIT 3
      ORDER BY current_month_sale DESC
      
      # Oracle中的TOP N查詢需要用到子查詢,后文會細(xì)講
      SELECT * FROM
      (SELECT
      title AS 'Book Title',
      current_month_sale AS 'Quantity Sold'
      FROM books
      ORDER BY current_month_sale)
      WHERE ROWNUM <= 3
      

布爾邏輯(更復(fù)雜的基于行的邏輯)

  • 使用與AND及志、或OR茄猫、非NOT三個關(guān)鍵字在WHERE子句中表示布爾邏輯狈蚤。與其它語言的計算順序一樣,AND的優(yōu)先級最高划纽,OR其次脆侮,NOT優(yōu)先級最低,也可以使用()來改變?nèi)叩挠嬎沩樞?
    # 這個例子僅為展示布爾邏輯勇劣,實際使用不應(yīng)該這么繞
    SELECT
    first_name,
    last_name,
    age
    FROM actors
    WHERE
    NOT(
    (age < 18 OR age > 60)
    AND last_name = 'Jhon'
    )
    
  • 還有兩個表示范圍的操作符BETWEENIN靖避,用于替代column >= range_bottom AND column <= range_topcolumn = value1 OR column = value2這樣的特例,簡化SQL語句的編寫
    # BETWEEN比默,等價于 age >= 18 AND age <= 60
    SELECT
    first_name,
    last_name,
    age
    FROM actors
    WHERE
    age BETWEEN 18 AND 60
    
    # IN幻捏,等價于 state = 'IL' AND state = 'NY'
    SELECT
    customer_name,
    state
    FROM orders
    WHERE state IN ('IL', 'NY')
    
  • 使用IS NULLWHERE子句中判斷一個列是否為空,也可以與函數(shù)ISNULL(column, value)結(jié)合使用
    # 選取重量為0或者沒有填寫重量的產(chǎn)品
    SELECT
    product_description,
    weight
    FROM products
    WHERE weight = 0
    OR weight IS NULL
    
    # 使用ISNULL等價的寫法
    SELECE
    product_description,
    weight
    FROM products
    WHERE ISNULL(weight, 0) = 0
    
    # IS NULL和ISNULL
    SELECT
    product_description,
    ISNULL(weight, 0) AS 'weight'
    FROM products
    WHERE weight = 0
    OR weight IS NULL
    

模糊匹配

  • WHERE子句可以使用LIKE操作符來查找針對列值的某部分匹配
    • 包含某關(guān)鍵字:
      SELECT 
        title
      FROM
        film
      WHERE
        title LIKE '%love%'
      
    • 以某關(guān)鍵字開頭:
      SELECT
        title
      FROM
        film
      WHERE
        title LIKE 'love%'
      
    • 以某關(guān)鍵字結(jié)尾
      SELECT
        title
      FROM
        film
      WHERE
        title LIKE '%love'
      
    • 包含某關(guān)鍵字但不以其開頭也不以其結(jié)尾(未能在MySQL 4中驗證命咐,只驗證通過了單獨(dú)的不以某字符串開頭篡九,或者不以某字符串結(jié)尾兩種情況)
      SELECT
        title
      FROM
        film
      WHERE
        title LIKE '% love %'
      
  • 符號 含義
    % 任意個任意字符
    _ 一個任意字符
    [characterlist] 一個指定字符列表中的字符(在MySQL和Oracle中沒有)
    [^charactorlist] 一個非指定字符列表中的字符(在MySQL和Oracle中沒有)
    通配符
    符號 含義
    % 任意個任意字符
    _ 一個任意字符
    [characterlist] 一個指定字符列表中的字符(在MySQL和Oracle中沒有)
    [^charactorlist] 一個非指定字符列表中的字符(在MySQL和Oracle中沒有)
  • NOT操作符可以和LIKE操作符組合使用,例如
    SELECT
    first_name,
    last_name
    FROM actor
    WHERE first_name LIKE '%ARY%'
    AND last_name NOT LIKE '[MG]ARY'
    
  • 按照讀音匹配(不常用也不好用)
    • SOUNDEX函數(shù):能夠輸出一個表示字符讀音的四字代碼(以首字母開頭醋奠,然后刪去剩余字符中所有元音和字母y榛臼,最后轉(zhuǎn)換為一個三位數(shù)的數(shù)字用于表示讀音,最后輸出類似S530
    • DIFFERENCE函數(shù):可以和SOUNDEX函數(shù)一起使用(僅Microsoft SQL Server支持)窜司,檢查兩個字符的SOUNDEX相似度并返回一個表示讀音相近度的數(shù)字沛善,(兩個字符的SOUNDEX值共有四個字符,每有一個位置的字符相等塞祈,則結(jié)果自增1金刁,所以DIFFERENCE函數(shù)的返回值只有0到4五個可能的數(shù)字,越大越相近议薪,越小越不同

匯總數(shù)據(jù)

  • 消除重復(fù):使用DISTINCT關(guān)鍵字來刪除輸出重復(fù)的行
    # 查看所有藝術(shù)家(沒有顯示相同藝術(shù)家的行)
    SELECT
    DISTINCT
    artist
    FROM songs
    ORDER BY artist
    
    # 查看所有藝術(shù)家和專輯的唯一組合(沒有顯示同一藝術(shù)家和同一專輯的行尤蛮,每一行中藝術(shù)家和專輯的組合是唯一的)
    SELECT
    DISTINCT
    artist,
    album
    FROM songs
    ORDER BY artist, album
    
  • 函數(shù) 解釋
    SUM 合計、加總
    AVG 平均值
    MIN 最小值
    MAX 最大值
    COUNT 數(shù)量
    聚合函數(shù):標(biāo)量函數(shù)只能針對單個的數(shù)字或值進(jìn)行計算斯议,而聚合函數(shù)則可以用于分組數(shù)據(jù)
    函數(shù) 解釋
    SUM 合計抵屿、加總
    AVG 平均值
    MIN 最小值
    MAX 最大值
    COUNT 數(shù)量
    # 總值、均值捅位、最大值、最小值
    SELECT
    SUN(fee) AS 'Total Gym Fees'
    AVG(grade) AS 'Average Quiz Score'
    MIN(grade) AS 'Minimum Quiz Score'
    MAX(grade) AS 'Maximum Quiz Score'
    FROM grades
    WHERE grade_type = 'quiz'
    
    # 返回所有選中行的數(shù)目
    SELECT
    COUNT(*) AS 'Count of Homework Rows'
    FROM grades
    WHERE grade_type = 'homework'
    
    # 返回指定列中存在值的行的數(shù)目
    SELECT
    COUNT(grade) AS 'Count of Homework Rows'
    FROM grades
    WHERE grade_type = 'homework'
    
    # 與DISTINCT配合返回指定列中唯一值的行數(shù)
    SELECT
    COUNT(DISTINCT fee_type) AS 'Number of Fee Types'
    FROM Fees   
    
  • 分組數(shù)據(jù):以指定列為依據(jù)對所有選中行進(jìn)行分組搂抒,重新劃分了行的顯示規(guī)則
    • 單列分組
      # 統(tǒng)計每個分級下的電影數(shù)量
      SELECT 
      rating, COUNT(rating) AS 'Rating Count'
      FROM
      film
      GROUP BY rating
      
    • columnlist中的所有列艇搀,要么是GROUP BY子句中的列,要么是在聚合函數(shù)中使用的列求晶,因為所有內(nèi)容都在組中出現(xiàn)焰雕,不在組中的內(nèi)容沒有辦法處理,這種情況下MySQL與其它兩種數(shù)據(jù)庫不同芳杏,它只會得出錯誤的結(jié)果矩屁,而不會報錯
    • 多列分組:組的概念可以擴(kuò)展辟宗,從而根據(jù)多列進(jìn)行分組
      # 統(tǒng)計不同租金率下的不同分級電影的數(shù)量
      SELECT 
      rating, 
      rental_rate,
      COUNT(rating) AS 'Rating Count'
      FROM film
      GROUP BY rating, rental_rate    
      
    • 在沒有分組的情況下,聚合函數(shù)(SUM吝秕、AVG泊脐、MINMAX烁峭、COUNT)統(tǒng)計的是所有行的數(shù)據(jù)容客,在有分組的情況下,這些聚合函數(shù)則僅會統(tǒng)計組內(nèi)的數(shù)據(jù)约郁,當(dāng)然實際上也是最終顯示的表的每一行的聚合
    • GROUP BY子句中的columnlist順序沒有意義缩挑,但ORDER BY子句中的順序是有意義的,一般按照排序的優(yōu)先順序來列出這些列會很有幫助(也即SELECT中的columnlist與ORDER BY中的columnlist保持一致)
  • 基于分組應(yīng)用查詢條件:WHERE子句中的查詢條件是針對單獨(dú)的行來應(yīng)用的鬓梅,如果存在GROUP BY分組供置,就需要使用HAVING關(guān)鍵字了
    # 查看分級中所有電影平均時長大于100分鐘的分級中電影的數(shù)量
    SELECT 
      rating AS '分級',
      COUNT(title) AS '電影數(shù)量',
      AVG(length) AS '平均時長'
    FROM
      film
    GROUP BY rating
    HAVING AVG(length) > 100
    ORDER BY 電影數(shù)量 DESC
    
  • 至此,SELECT語句的一般格式如下:
    SELECT
      columnlist
    FROM
      tablelist
    WHERE
      condition
    GROUP BY
      columnlist
    HAVING
      condition
    ORDER BY
      COLUMNLIST
    

用內(nèi)連接來組合表

  • 關(guān)系型數(shù)據(jù)庫最重要的成就是能夠把數(shù)據(jù)組織到任意多個相互關(guān)聯(lián)的表中绽快,但同時這些又是彼此獨(dú)立的芥丧;人們可以分析業(yè)務(wù)實體然后進(jìn)行適當(dāng)?shù)臄?shù)據(jù)庫設(shè)計,這樣就可以具有最大的靈活性谎僻;關(guān)系型數(shù)據(jù)庫可以以任何你想要的方式把代表業(yè)務(wù)實體的表連接到一起娄柳,從而實現(xiàn)“關(guān)系”
  • 類似“客戶”和“訂單”這樣兩個獨(dú)立的實體信息,至少應(yīng)該要拆分到兩個表中(訂單表很有可能需要繼續(xù)拆分成多個表)艘绍,可以使用實體關(guān)系圖(entity-relationship diagram)來表示可視化地表示兩個表以及他們之間存在的隱性關(guān)系赤拒,實體(entity)指的是表,關(guān)系(relationship)指的是這些表中數(shù)據(jù)元素之間所畫的線


    實體關(guān)系圖
  • 內(nèi)連接
    • 使用關(guān)鍵字INNER JOIN來指定想要連接的第二個表诱鞠,使用ON來指定兩個表的共同列由于共同列名稱是一樣的挎挖,所以需要在列名前面使用表名作為命名空間來區(qū)分兩個表中獨(dú)立的列
      # 簡單地依據(jù)customer_id將顧客表和訂單表拼接到一個表中
      SELECT *
      FROM customers
      INNER JOIN orders
      ON customers.customer_id = orders.customer_id
      
    • 內(nèi)連接只會返回關(guān)聯(lián)的兩個表之間相匹配的數(shù)據(jù),表在FROMINNER JOIN之間的順序僅會影響哪個表的列先顯示航夺,不會影響行的順序
    • SQL不是過程式語言蕉朵,不會指定任務(wù)的先后順序,而只是指定需要的邏輯并讓數(shù)據(jù)庫內(nèi)部機(jī)制去決定如何執(zhí)行任務(wù)阳掐。
    • 僅使用FROMWHERE也可以指定表的內(nèi)連接始衅,這是內(nèi)連接的另一種范式,但因其沒有顯示地表示出連接的邏輯缭保,所以不推薦使用(所以其實INNER JOIN ON的唯一作用僅僅是表達(dá)語義而已)
      SELECT *
      FROM customers, orders
      WHERE customers.customer_id = orders.customer_id
      
    • 可以通過顯式地指定表的別名和列的別名(注意Oracle中表的別名與其他兩個庫的區(qū)別汛闸,前文有提及),來去除內(nèi)連接后的重復(fù)列或者只顯示需要的列艺骂,這是推薦的做法:
      SELECT
      c.customer_id AS 'Customer Id',
      c.first_name AS 'First Name',
      c.last_name AS 'Last Name',
      o.order_id AS 'Order Id',
      o.quantity AS 'Quantity',
      o.price_per_item AS 'Price'
      FROM customers AS 'c',
      INNER JOIN
      

用外連接來組合表

  • SQL中表連接的默認(rèn)類型就是內(nèi)連接诸老,所以可以只使用JOIN來指定一個內(nèi)連接
  • 外連接有三種類型:左連接LEFT OUTER JOIN,右連接RIGHT OUTER JOIN钳恕,全連接FULL OUTER JOIN别伏,其中關(guān)鍵字OUTER并不是必須的蹄衷。
  • 連接類型 全稱 簡寫 用途
    內(nèi)連接 INNER JOIN JOIN 兩個表都是主表(primary table),共同列中所有的行都必須同時在這兩個表中才會被選中
    左連接 LEFT OUTER JOIN LEFT JOIN 左表為主表厘肮,右表為從表(secondary table)愧口,選中共同列中所有在主表中的行,不管它是否出現(xiàn)在從表
    右連接 RIGHT OUTER JOIN RIGHT JOIN 左表為從表轴脐,右表為主表调卑,規(guī)則同左連接
    全連接 FULL OUTER JOIN FULL JOIN 兩個表都是從表,共同列中的行只要出現(xiàn)在任意一個表中都會被選中
    所以總結(jié)起來有4種類型的連接:
    連接類型 全稱 簡寫 用途
    內(nèi)連接 INNER JOIN JOIN 兩個表都是主表(primary table)大咱,共同列中所有的行都必須同時在這兩個表中才會被選中
    左連接 LEFT OUTER JOIN LEFT JOIN 左表為主表恬涧,右表為從表(secondary table),選中共同列中所有在主表中的行碴巾,不管它是否出現(xiàn)在從表
    右連接 RIGHT OUTER JOIN RIGHT JOIN 左表為從表溯捆,右表為主表,規(guī)則同左連接
    全連接 FULL OUTER JOIN FULL JOIN 兩個表都是從表厦瓢,共同列中的行只要出現(xiàn)在任意一個表中都會被選中
  • 在實體關(guān)系圖中提揍,單向箭頭表示表之間的連接是單向的,箭頭終點(diǎn)的表中有一列所有行都能在箭頭起點(diǎn)的表中找到煮仇,但反過來則不一定劳跃,比如,不是所有的客戶都有訂單浙垫,且一個客戶可能有多個訂單刨仑,但所有的訂單都會有客戶信息(甚至可以說所有的訂單有且只有一個客戶信息),退貨信息與訂單的關(guān)系類似
  • 當(dāng)連接主表和從表時夹姥,我們需要主表中所有的行杉武,即使在從表中的共同列沒有任何行與之匹配
  • 使用IS NOT NULLIS NULL來過濾空行或顯示空行
    # 過濾了沒有訂單的客戶和有退貨的訂單
    SELECT
    customers.first_name AS 'First Name',
    customers.last_name AS 'Last Name',
    orders.order_date AS 'Order Date',
    orders.order_amount AS 'Order Amt'
    FROM customers
    LEFT JOIN orders
    ON orders.customer_id = customers.customre_id
    LEFT JOIN refunds
    ON orders.order_id = refunds.order_id
    WHERE orders.order_id IS NOT NULL
    AND refunds.refund_id IS NULL
    ORDER BY customers.customer_id, orders.order_id
    
  • 右連接與左連接唯一的不同就是主從表在關(guān)鍵字前后的位置,所以基本上沒有必要使用右連接辙售,建議只使用左連接轻抱,因為人直覺上往往認(rèn)為先列出的表更為重要
  • 當(dāng)設(shè)計有多個表的復(fù)雜FROM子句時,建議僅使用關(guān)鍵字LEFT JOIN并且避免使用圓括號
  • 全連接會顯示所有行旦部,即使沒有在其他表中找到任何一個匹配祈搜。但在實際工作中很少會用到全連接,因為表之間的這種類型的關(guān)系是非常少見的士八。

自連接和視圖

  • 自連接:處理那些本質(zhì)上是自引用的表(表中的一列指向自己的另一列容燕,比如員工表中的manager列指向自己的employee_id,員工的經(jīng)理也是員工)曹铃,為其創(chuàng)建多個視圖
    • 可以使用四種表連接中的任意一種來實現(xiàn)自連接,唯二的區(qū)別就是ON子句中捧杉,非自連接的共同列來自兩個表陕见,自連接的共同列來自同一個表秘血,所以這時候需要在FROM關(guān)鍵字和JOIN關(guān)鍵字后為該表各自創(chuàng)建一個別名用以在ON子句中進(jìn)行區(qū)分
    # 列出personnel表中所有員工的經(jīng)理名字
    SELECT
    employees.employee_name AS 'Employee Name',
    managers.employee_name AS 'Maneger Name'
    FROM personnel AS 'employees'
    LEFT JOIN personnel AS 'managers'
    ON employees.manager_id = managers._employee_id
    ORDER BY employee.employee_id
    
  • 視圖
    • 視圖只是保存在數(shù)據(jù)庫中的SELECT語句,它不包含任何數(shù)據(jù)评甜。
    • 隨著時間的流逝灰粮,訪問數(shù)據(jù)的需求會有所變化,但有時很難去重新組織數(shù)據(jù)庫中的數(shù)據(jù)以滿足新的需求忍坷。視圖允許為數(shù)據(jù)庫中已經(jīng)存在的數(shù)據(jù)創(chuàng)建新的虛擬視圖(或理解為虛擬的表)而無需重新組織數(shù)據(jù)粘舟,這為我們增加了始終能保持?jǐn)?shù)據(jù)庫設(shè)計不斷更新的能力。
    • 因為視圖沒有保存物理數(shù)據(jù)佩研,所以在視圖中不能包含ORDER BY子句
  • 創(chuàng)建視圖
    # 創(chuàng)建視圖的語法:
    CREATE VIEW view_name AS
    select_statement
    
    # 一個創(chuàng)建視圖的例子柑肴,注意不能有ORDER BY子句
    CREATE VIEW customers_orders_refunds AS
    SELECT
    customers.first_name AS 'First Name',
    customers.last_name AS 'Last Name',
    orders.order_date AS 'Order Date',
    orders.order_amount AS 'Order Amt'
    FROM customers
    LEFT JOIN orders
    ON orders.customer_id = customers.customre_id
    LEFT JOIN refunds
    ON orders.order_id = refunds.order_id
    WHERE orders.order_id IS NOT NULL
    AND refunds.refund_id IS NULL
    
  • 引用視圖
    # 創(chuàng)建視圖
    CREATE VIEW view_name AS
    select_statement
    
    # 引用視圖
    SELECT * from view_name
    
    • 當(dāng)引用視圖中的列的時候,需要指定列的別名旬薯,而列的別名是在創(chuàng)建視圖時指定的
      # 創(chuàng)建視圖
      CREATE VIEW customers_view AS
      SELECT
      first_name AS 'First Name',
      last_name AS 'Last Name'
      FROM customers
      
      # 引用視圖中的列
      SELECT
      `First Name`,
      `Last Name`,
      FROM customers_view
      WHERE `Last Name` = 'Lopez'
      
  • 視圖的優(yōu)點(diǎn)
    • 視圖可以減少復(fù)雜度:將復(fù)雜的SELECT語句封裝為一個視圖
    • 視圖可以增加復(fù)用性:封裝那些總是相連的表
    • 視圖可以正確地格式化數(shù)據(jù):如果一個表中的某些數(shù)據(jù)總是需要格式化晰骑,可以將其封裝到視圖中
    • 視圖可以創(chuàng)建計算的列:如果需要一個含有大量的計算字段的表,也可將其封裝到視圖中
    • 視圖可以用來重新命名列的名稱:如果一個表中的列名總是需要重命名绊序,可以將其封裝到視圖中
    • 視圖可以創(chuàng)建數(shù)據(jù)子集:如果總是只需要看到某個表的某些子集硕舆,可以將它們封裝到不同的視圖
    • 視圖可以用來加強(qiáng)安全性限制:如果一個表中的某些數(shù)據(jù)希望對某些用戶做訪問限制,可以使用視圖將它們挑出來然后僅將視圖的權(quán)限給那些用戶而不是整個表的權(quán)限
  • 修改視圖:使用ALTER關(guān)鍵字修改一個已經(jīng)創(chuàng)建的視圖骤公,重新指定被封裝到其中的SELECT語句
    # 整個被封裝到視圖的select語句都需要重新指定
    ALTER VIEW view_name AS
    new_select_statement
    
    # 與Microsoft SQL Server和MySQL不同抚官,Oracle在修改視圖之前,需要使用DROP VIEW view_name先刪除視圖
    
    • 同樣阶捆,修改視圖與創(chuàng)建視圖一樣凌节,只是修改了視圖的定義,它本身不會返回任何數(shù)據(jù)
  • 刪除視圖:使用DROP VIEW view_name來刪除視圖

子查詢

  • 包含在其他查詢中的查詢叫做子查詢趁猴,子查詢可以用在SELECT刊咳、INSERTUPDATE儡司、DELETE語句
  • SELECT語句中子查詢可以有三種用法:
    • 一個一般的SELECT語句格式如下:
      SELECT column_list
      FROM table_list
      WHERE condition
      GROUP BY column_list
      HAVING condition
      ORDER BY column_list
      
    • 當(dāng)子查詢是table_list的一部分時娱挨,它指定了一個數(shù)據(jù)源
    • 當(dāng)子查詢時condition的一部分時,它成為查詢條件的一部分
    • 當(dāng)子查詢是column_list的一部分時捕犬,它創(chuàng)建了一個單個的計算的列
  • 使用子查詢指定數(shù)據(jù)源:把一個子查詢指定為FROM子句的一部分時跷坝,它立即創(chuàng)建了一個新的數(shù)據(jù)源,并被當(dāng)做一個獨(dú)立的表或視圖來引用碉碉,與視圖的區(qū)別是視圖是永久保存在數(shù)據(jù)庫中的柴钻,而子查詢只是臨時的
    # 使用子查詢指定數(shù)據(jù)源的一般格式
    SELECT column_list
    FROM [table_list]
    [JOIN] subquery
    AS custom_subquery_name
    
    # 從address表,city表和country表中列出五個地址對應(yīng)的城市和國家
    SELECT 
      address AS 'Address',
      city AS 'City',
      country AS 'Country'
    FROM address
    LEFT JOIN(
      SELECT 
          city.city,
          city.city_id,
          country.country,
          country.country_id
      FROM city
      LEFT JOIN country
      ON city.country_id = country.country_id
    ) AS city_and_country ON address.city_id = city_and_country.city_id
    ORDER BY address
    LIMIT 5
    
  • 使用子查詢指定查詢條件:把一個子查詢指定為WHERE子句中IN操作符的右值垢粮,可以以更復(fù)雜的邏輯來為IN操作符創(chuàng)建一個可選列表;注意贴届,當(dāng)子查詢用于指定查詢條件時,僅能返回單一的列
    # 使用子查詢指定查詢條件的一般格式
    SELECT column_list
    FROM table_list
    WHERE column IN subquery
    
    SELECT column_list
    FROM table_list
    WHERE subquery match_some_comdition
    
    # 列出所有使用現(xiàn)金支付的客戶名稱
    SEELCT customer_name AS 'Customer Name'
    FROM costomers
    WHERE customer_id IN
    (
      SELECT customer_id
      FROM orders
      WHERE order_type = 'cash'
    )
    
    # 列出訂單金額少于20美元的客戶列表
    SELECT customer_name AS 'Customer Name'
    FROM customers
    WHERE
    (
      SELECT SUM(orderAmount)
      FROM orders
      WHERE customers.customer_id = orders.customer_id
    ) < 20
    
  • 使用子查詢作為計算列:把一個子查詢作為column_list中的一項,將其用作一個計算的列
    # 使用子查詢作為計算列的一般格式
    SELECT column_list,
    subquery_result AS 'Result Alia'
    FROM table_list
    
    # 查詢客戶及其訂單數(shù)量
    SELECT
    customer_name AS 'Customer Name',
    (
      SELECT COUNT(order_id)
      FROM orders
      WHERE customers.customer_id = orders.customer_id
    ) AS 'Number of Orders'
    FROM customers
    ORDER BY customers.customer_id
    
  • 關(guān)聯(lián)子查詢:無法獨(dú)立運(yùn)行的子查詢?yōu)殛P(guān)聯(lián)子查詢毫蚓,可以獨(dú)立運(yùn)行的子查詢?yōu)榉顷P(guān)聯(lián)子查詢占键。非關(guān)聯(lián)子查詢完全獨(dú)立與外圍查詢語句,只會計算和執(zhí)行一次元潘,而關(guān)聯(lián)子查詢需要針對返回的每一行逐行計算畔乙,且每次執(zhí)行子查詢的時候得到的結(jié)果可能都不一樣,上文中查詢客戶及其訂單數(shù)量中的子查詢即為關(guān)聯(lián)子查詢翩概,它使用了外圍查詢的數(shù)據(jù)來源customers
  • EXISTS操作符:用于確定一個關(guān)聯(lián)子查詢中是否存在數(shù)據(jù)
    # 查詢下過訂單的用戶
    SELECT
    customer_name AS 'Customer'
    FROM customers
    WHERE EXISTS
    (
      SELECT * FROM orders
      WHERE customers.customer_id = orders.customer_id
    )
    

集合邏輯

在前文中牲距,連接JOIN可以將來自兩個表的列組合到一個表中,子查詢則是將一條SELECT語句的結(jié)果提供給第另一條SELECT語句使用钥庇。然而有時候我們希望將來自兩個表的行組合到一個表中牍鞠,這時候就需要使用SQL中的集合邏輯UNION,來做合并查詢上沐。

  • UNION-合并兩條SELECT語句皮服,選取在A或B中的數(shù)據(jù),如果同時存在在A或B中参咙,僅顯示一條
    SELECT
    order_date AS 'Date',
    'order' AS 'Type',
    order_amount AS 'amount'
    FROM orders
    WHERE custom_id = 2
    
    UNION
    
    SELECT
    return_date AS 'Date',
    'return' AS 'type',
    return_amount AS 'amount'
    FROM returns
    WHERE custom_id = 2
    
    ORDER BY date
    
    
    使用UNION需要遵守3個規(guī)則(實際就一條規(guī)則:相同列):
    • 兩個SELECT語句中的列的數(shù)量必須相等
    • 兩個SELECT語句中的列排列順序必須相同
    • 兩個SELECT語句中的列數(shù)據(jù)類型必須相同
  • UNION ALL-合并兩條SELECT語句龄广,選取在A或B中的數(shù)據(jù),即使同時存在在A或B中蕴侧,都將顯示在結(jié)果中
    SELECT
    DISTINCT
    order_date AS 'Date'
    FROM orders
    
    UNION ALL
    
    SELECT
    DISTINCT
    return_date AS 'Date'
    FROM returns
    ORDER BY Date
    
    # UNION 確保來自兩個表的行沒有重復(fù)數(shù)據(jù)择同,但 UNION ALL 允許來自兩個表的行可以有相同數(shù)據(jù)
    # DISTINCT 確保來自同一個表(或者說同一個SELECT語句)的行沒有重復(fù)數(shù)據(jù)
    # 所以上面的語句選取的數(shù)據(jù)可能會存在重復(fù)數(shù)據(jù),但重復(fù)的數(shù)據(jù)并不來自兩個表而是來自同一個表净宵,并且僅會重復(fù)一次
    
  • INTERSECT-合并兩條SELECT語句敲才,選取同時出現(xiàn)在A和B中的行(MySql不支持該操作符)
    SELECT order_date AS 'Date'
    FROM orders
    
    INTERSECT
    
    SELECT return_date As 'Date'
    FROM returns
    
    ORDER BY Date
    
  • EXCEPT-合并兩條SELECT語句,選取僅出現(xiàn)在A或僅出現(xiàn)在B中的的數(shù)據(jù)(MySql和Oracle不支持該操作符择葡,但Oracle提供了等價的MINUS操作符)
    SELECT order_date AS 'Date' FROM orders
    
    EXCEPT
    
    SELECT return_date AS 'Date' FROM returns
    
    ORDER BY Date
    

存儲過程和參數(shù)

到目前為止紧武,前文所有的SQL語句都是單獨(dú)使用,然而很多時候敏储,你會希望SQL語句能夠像函數(shù)一樣阻星,定義一次,然后重復(fù)調(diào)用已添,并且可以使用參數(shù)來增加靈活性妥箕。這時,你就可以使用存儲過程來實現(xiàn)這一目的更舞。

  • 創(chuàng)建存儲過程:創(chuàng)建存儲過程不會執(zhí)行任何內(nèi)容畦幢,只是直接創(chuàng)建了一個過程,以便后續(xù)執(zhí)行它缆蝉。與表和視圖一樣宇葱,創(chuàng)建好的存儲過程在管理工具中是可以查看的
    -- Microsoft SQL Server
    CREATE PROCEDURE ProcedureName (OptionalPrameterDeclarations)
    AS
    BEGIN
    SQLStatements
    END
    
    -- MySQL
    DELIMITER $$ -- 規(guī)定END語句使用的分隔符瘦真,默認(rèn)為分號
    CREATE PROCEDURE ProcedureName (OptionalPrameterDeclarations)
    BEGIN
    SQLStatements; -- 每一條SQL語句都必須使用分號分隔,即使只有一條
    END$$
    DELIMITER ; -- 將分隔符改回分號
    
  • 存儲過程的參數(shù):例如存儲一個選取特定用戶的SQL過程黍瞧,可以使用參數(shù)來指定用戶的ID
    -- Microsoft SQL Server
    CREATE PROCUDURE CustomerProcudure (@custId INT)
    AS
    BEGIN
      SELECT * FROM customers
      WHERE customer_id = @custId
    END
    
    -- MySQL
    DELIMITER $$
    CREATE PROCEDURE CustomerProcudure (custId INT)
    BEGIN
      SELECT * FROM customers
      WHERE CUSTOMER_ID = custId;
    END
    DELEMITER ;
    
  • 執(zhí)行存儲過程
    -- Microsoft SQL Server
    EXEC CustomerProcudure @custId = 2
    
    -- MySQL
    CALL CustomerProcudure (2)
    
  • 修改和刪除存儲過程:在Microsoft SQL Server中吗氏,修改過程和創(chuàng)建過程幾乎一樣,只需要把CREATE關(guān)鍵字替換為ALTER關(guān)鍵字即可雷逆;然而在MySQL中,雖然也存在ALTER命令污尉,但它的功能十分簡單膀哲,所以一般我們選擇先刪除存儲過程然后再重新創(chuàng)建
    -- 刪除存儲過程
    DROP PROCEDURE ProcedureName
    
  • 函數(shù)與存儲過程的兩點(diǎn)區(qū)別
    • 存儲過程可以有任意數(shù)目的輸出,而函數(shù)只有單一的返回值
    • 只能通過調(diào)用程序來執(zhí)行存儲過程被碗,而函數(shù)可以在SQL語句中使用

修改數(shù)據(jù)

  • 修改策略:使用“軟刪除(使用表中特定的列來標(biāo)記該行數(shù)據(jù)是否有效)”技術(shù)替代真正的刪除某宪;插入新行時在特定列中標(biāo)記準(zhǔn)確的插入日期和時間以便出錯時對其進(jìn)行刪除;使用單獨(dú)的表來保存事務(wù)所要更新的數(shù)據(jù)通常是明智的選擇锐朴。請永遠(yuǎn)記住兴喂,SQL中沒有撤銷命令。
  • 插入數(shù)據(jù):使用INSERT命令來插入指定數(shù)據(jù)焚志,注意不需要為自增型的列指定數(shù)據(jù)衣迷,數(shù)據(jù)庫會自動處理它;另外酱酬,Oracle不允許一次插入多行數(shù)據(jù)壶谒,需要分開書寫
    • 插入INSERT語句中指定的具體數(shù)據(jù)
      -- 向customer表插入兩條新數(shù)據(jù)
      INSERT INTO customers
      (first_name, last_name, state) -- 只要列名是正確的,它們的順序無所謂
      -- 當(dāng)這里的列名順序與數(shù)據(jù)庫中的物理順序一致時可省略它們膳沽,但強(qiáng)烈不建議這么做
      VALUES
      ('Virginia', 'Jones', 'OH'), -- VALUES關(guān)鍵字后的數(shù)據(jù)列汗菜,要與INSERT INTO后的列相對應(yīng)
      ('Clark', 'Woodland', 'CA')
      
    • 插入用一條SELECT語句指定的數(shù)據(jù)
      -- 將customer_transaction中的RI州的用戶插入到customer表中
      INSERT INTO customer
      (first_name, last_name, state)
      SELECT
      fn, ln, state -- 這里選中列的順序需要與INSERT INTO 語句中的順序一致
      FROM customer_transactions
      WHERE state = 'RI'
      
  • 刪除數(shù)據(jù):使用DELETE命令來刪除一條數(shù)據(jù),通常是一整行(刪除某行中的列沒有意義挑社,那屬于修改數(shù)據(jù)的范疇)
    -- 刪除數(shù)據(jù)的一般寫法
    DELETE
    FROM table_name
    WHERE conditions
    
    -- 可以使用SELECT語句來驗證刪除結(jié)果
    SELECT
    COUNT (*) -- 使用聚合函數(shù)COUNT來統(tǒng)計被刪除數(shù)據(jù)的數(shù)量以確認(rèn)是否全部都被刪除了
    FROM table_name
    WHERE conditions
    
    -- 清空一個表中的所有數(shù)據(jù)陨界,可以使用TRUNCATE TABLE語句
    TRUNCATE TABLE customers
    -- 上面的語句與下面的DELETE語句效果基本相同
    DELETE FROM customers
    -- 唯一不同在于,TRUNCATE TABLE語句重置了自增列痛阻,而DELETE語句沒有
    
  • 更新(修改)數(shù)據(jù):刪除數(shù)據(jù)只需要指定刪除的行即可菌瘪,但更新數(shù)據(jù)是針對具體行中的具體列,所以需要首先指定更新哪些列录平,然后指定更新這些列中的哪些行
    • 使用指定的具體數(shù)據(jù)更新數(shù)據(jù)
      -- 更新數(shù)據(jù)的一般格式
      UPDATE table
      SET
        column1 = expression1,
        column2 = expression2
        -- repeat any number of time
      WHERE conditions -- 如果沒有指定行麻车,該句會把所有行的指定列都更新一次
      
    • 使用子查詢中的數(shù)據(jù)修改數(shù)據(jù)(使用一個表中的數(shù)據(jù)來更新另一個表中的數(shù)據(jù))
      -- 一般格式
      UPDATE table -- 指定要更新的表
      SET table.column_1 = -- 指定需要更新的列1
        (
          SELECT another_table.column_1 -- 子查詢從另一表中獲取數(shù)據(jù),并通過主鍵(也可是其它)來進(jìn)行匹配
          FROM another_table
          WHERE another_table.auto_increment_primary_key = table.auto_increment_primary_key
        )
      SET table.column_2 = -- 指定需要更新的列2
        (
          SELECT another_table.column_2
          FROM another_table
          WHERE another_table.auto_increment_primary_key = auto_increment_primary_key.column_2
        )
      WHERE EXISTS -- 指定需要更新的行斗这,使用子查詢指定只更新table中存在于another_table中的行
        (
          SELECT *
          FROM another_table
          WHERE another_table.auto_increment_primary_key = table.auto_increment_primary_key
        )
      

維護(hù)表

  • 回顧SQL語言的三種組成部分:數(shù)據(jù)操縱語言(Data Manipulation Language动猬,DML,對數(shù)據(jù)庫中或者更詳細(xì)地說是表中的數(shù)據(jù)進(jìn)行增刪改查操作)表箭、數(shù)據(jù)定義語言(Data Definition Language赁咙,DDL,對數(shù)據(jù)庫中的表及其索引進(jìn)行增刪改查)、和數(shù)據(jù)控制語言(Data Control Language彼水,DCL崔拥,維護(hù)數(shù)據(jù)庫安全)。本章主要講述DDL凤覆,但前文也已經(jīng)用到過DDL链瓦,視圖VIEW、過程PROCEDURE需要用到的都是DDL
  • 添加或修改表和索引的SQL語句很復(fù)雜盯桦,但是我們無需了解細(xì)節(jié)慈俯,數(shù)據(jù)庫軟件通常提供了圖形化的工具來修改表的結(jié)構(gòu),而不一定需要使用SQL語句
  • 表屬性:表(Table)是數(shù)據(jù)庫中最重要的對象拥峦,數(shù)據(jù)庫中所有數(shù)據(jù)物理地存儲在表中贴膘,沒有了表數(shù)據(jù)庫中的一切也就沒有意義了。前文已經(jīng)介紹過一些表的屬性略号,主鍵刑峡、外鍵、數(shù)據(jù)類型玄柠、自增型列等等
    • 表的列
      • 列名:表中的每個列都必須有唯一的列名
      • 數(shù)據(jù)類型:決定列可以包含什么樣的數(shù)據(jù)
      • 是否自增型:表中每增加一行突梦,該列會以升序序列自動賦值(術(shù)語auto-increment是MySQL中的的特定用法,Oracle沒有自增型屬性)
      • 默認(rèn)值
  • 主鍵和索引
    • 主鍵:只能指定一個列作為主鍵羽利,目的是保證這個列包含唯一值(所以不允許它們包含NULL值)阳似;實際上主鍵可以跨越多個列,叫做復(fù)合主鍵(當(dāng)希望使用電影名稱列來作為主鍵時可能會存在重復(fù)名稱铐伴, 這時可以使用電影名稱+年份兩個列作為復(fù)合主鍵來唯一地定義每部電影)
    • 索引:索引是一種物理結(jié)構(gòu)撮奏,目的是當(dāng)SQL語句中包含該列的時候,可以加速數(shù)據(jù)檢索当宴,缺點(diǎn)是需要更多的磁盤空間畜吊,并且會減慢更新數(shù)據(jù)時的速度
  • 外鍵:
    • 外鍵定義:外鍵是從一個表中的一個列到另一個不同的表中的列的直接引用,含有外鍵的表為“子表”户矢,被外鍵引用的表被稱為“父表”
    • 外鍵級聯(lián)(Cascade):當(dāng)父表有更新或刪除時玲献,會自動更新或刪除子表中的關(guān)聯(lián)行
    • Set Null:當(dāng)父表有更新或刪除時,如果影響到子表梯浪,是否把子表中關(guān)聯(lián)行的外鍵設(shè)置為NULL
  • 創(chuàng)建表:使用CREATE TABLE語句來創(chuàng)建表及其屬性(列)捌年,不同數(shù)據(jù)庫之間存在差異:
    -- Microsoft SQL Server
    CREATE TABLE my_table
    (
      column_1 INT IDENTITY (1, 1) PRIMARY KEY NOT NULL, -- 列名column_1,INT類型挂洛,自增型礼预,主鍵,不能為NULL
      column_2 NOT NULL REFERENCES related_table (first_column), -- 列名column_2虏劲,INT類型托酸,不能為NULL褒颈,外鍵,關(guān)聯(lián)到related_table表的first_column列
      column_3 VARCHAR (25) NULL, -- 列名column_3励堡,VARCHART類型谷丸,可以是NULL
      column_4 FLOAT NULL DEFAULT (10) -- 列名column_4,F(xiàn)LOAT類型应结,可以是NULL
    )
    
    
    -- My SQL
    CRAET TABLE my_table
      column_1 INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
      column_2 INT NOT NULL,
      column_3 VARCHAR (25) NULL,
      column_4 FLOAT NULL DEFAULT 10 NULL,
      CONSTRAINT FOREIGN KEY (column_2) REFERENCE 'related_table' (first_column) -- 指定外鍵
      
    -- Oracle
    CREATE TABLE my_table
    (
      column_1 INT PRIMARY KEY NOT NULL, -- Oracle不允許有自增型的列
      column_2 INT NOT NULL,
      column_3 VARCHAR2 (25) null,
      column_4 FLOAT DEFAULT 10 NULL
      CONSTRAINT "foreign_key" FOREIGN KEY (column_2) REFERENCES related_table (first_column)
    )
    
    使用ALTER TABLE語句修改表的具體屬性刨疼,該語句的復(fù)雜性及數(shù)據(jù)庫差異巨大,這里不再展開鹅龄;使用DROP TABLE table_name語句來刪除一個表
    -- 修改表
    ALTER TABLE my_table
    DROP COLUMN column_3
    
    -- 刪除表
    DROP TABLE my_table
    
  • 創(chuàng)建索引:使用CREATE INDEX語句币狠,用來在創(chuàng)建表之后創(chuàng)建索引,使用ALTER INDEX語句來添加和修改索引
    -- 創(chuàng)建索引
    CREATE INDEX index_2
    ON my_table (column_4)
    
    -- 刪除索引
    DROP INDEX index_2
    ON my_table
    

數(shù)據(jù)庫設(shè)計原理與顯示數(shù)據(jù)的策略(略)

  • 關(guān)系型數(shù)據(jù)庫是一個數(shù)據(jù)集合砾层,數(shù)據(jù)庫中的表以某些方式相互關(guān)聯(lián)。
  • SQL語句僅僅是使用數(shù)據(jù)庫的工具贱案,數(shù)據(jù)庫設(shè)計則是另外一個更為重要的話題肛炮。《SQL初學(xué)者指南》中對這個話題進(jìn)行了簡單的概括:規(guī)范化及其替代方法宝踪,這里將不再展開侨糟。
  • 關(guān)于這個話題建議閱讀另外的一些書籍:《SQL必知必會》、《高性能MySQL》
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瘩燥,一起剝皮案震驚了整個濱河市秕重,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌厉膀,老刑警劉巖溶耘,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異服鹅,居然都是意外死亡凳兵,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進(jìn)店門企软,熙熙樓的掌柜王于貴愁眉苦臉地迎上來庐扫,“玉大人,你說我怎么就攤上這事仗哨⌒瓮ィ” “怎么了?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵厌漂,是天一觀的道長萨醒。 經(jīng)常有香客問我,道長苇倡,這世上最難降的妖魔是什么验靡? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任倍宾,我火速辦了婚禮,結(jié)果婚禮上胜嗓,老公的妹妹穿的比我還像新娘高职。我一直安慰自己,他們只是感情好辞州,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布怔锌。 她就那樣靜靜地躺著,像睡著了一般变过。 火紅的嫁衣襯著肌膚如雪埃元。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天媚狰,我揣著相機(jī)與錄音岛杀,去河邊找鬼。 笑死崭孤,一個胖子當(dāng)著我的面吹牛类嗤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播辨宠,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼遗锣,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了嗤形?” 一聲冷哼從身側(cè)響起精偿,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赋兵,沒想到半個月后笔咽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡霹期,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年拓轻,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片经伙。...
    茶點(diǎn)故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡扶叉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出帕膜,到底是詐尸還是另有隱情枣氧,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布垮刹,位于F島的核電站达吞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏荒典。R本人自食惡果不足惜酪劫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一吞鸭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧覆糟,春花似錦刻剥、人聲如沸甘苍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽迁客。三九已至,卻和暖如春应闯,著一層夾襖步出監(jiān)牢的瞬間茸习,已是汗流浹背柔逼。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工挟裂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留享钞,地道東北人。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓诀蓉,卻偏偏與公主長得像栗竖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子交排,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容