SQL復(fù)雜查詢

參考資料:
《SQL基礎(chǔ)教程》

復(fù)雜查詢

視圖

視圖和表

從SQL的角度來看,視圖就是一張表,兩者的區(qū)別在于是否保存了實(shí)際的數(shù)據(jù)。

  1. 創(chuàng)建表時(shí),會(huì)通過INSERT語句將數(shù)據(jù)保存到數(shù)據(jù)庫中,而數(shù)據(jù)庫中的數(shù)據(jù)實(shí)際上會(huì)保存到計(jì)算機(jī)的存儲(chǔ)設(shè)備。
  2. 使用視圖時(shí),并不會(huì)將數(shù)據(jù)保存到任何地方,實(shí)際上視圖保存的是SELECT語句。從視圖讀取數(shù)據(jù)時(shí),視圖會(huì)在內(nèi)部執(zhí)行該SELECT語句并創(chuàng)建出一張臨時(shí)表。
視圖和表

總結(jié)成一句話:表中存儲(chǔ)的是實(shí)際數(shù)據(jù),視圖本質(zhì)上就是SELECT語句。

視圖的優(yōu)點(diǎn)

  1. 視圖無需保存數(shù)據(jù),節(jié)省存儲(chǔ)設(shè)備容量;
  2. 可以將頻繁使用的SELECT語句保存成視圖,就不用每次都重新書寫了。

創(chuàng)建和使用視圖

創(chuàng)建視圖的CREATE VIEW語句

CREATE VIEW 視圖名稱 (<視圖列名1>, <視圖列名2>, ...)
AS
<SELECT語句>

注意:SELECT語句中列的排列順序和視圖中列的排列順序相同,SELECT語句中的第1列就是視圖中的第1列,以此類推。視圖的列名在視圖名稱之后的列表中定義。

創(chuàng)建ProductSum視圖

CREATE VIEW ProductSum (product_type, cnt_product)
AS
SELECT product_type, COUNT(*)
FROM Product
GROUP BY product_type;

使用視圖

SELECT
    product_type,
    cnt_product
FROM ProductSum;

執(zhí)行結(jié)果:


FROM子句中使用視圖查詢的兩個(gè)步驟

  1. 創(chuàng)建視圖:執(zhí)行定義視圖的SELECT語句;
  2. 使用視圖:根據(jù)得到的結(jié)果,再執(zhí)行在FROM子句中使用視圖的SELECT語句。

當(dāng)然,我們還可以以視圖為基礎(chǔ)再創(chuàng)建視圖,因此,使用視圖的查詢通常需要執(zhí)行2條以上的SELECT語句。但是,多重視圖會(huì)降低SQL的性能,因此希望大家使用單一視圖。

視圖的限制

定義視圖時(shí)不能使用ORDER BY子句

為什么不能使用ORDER BY子句?
因?yàn)橐晥D和表一樣,數(shù)據(jù)行都是沒有順序的。

對(duì)視圖進(jìn)行更新

SELECT語句中,視圖可以和表一樣使用,那么,更新語句(INSERT、DELETE、UPDATE)呢?
標(biāo)準(zhǔn)SQL中規(guī)定:如果定義視圖的SELECT語句能夠滿足某些條件,那么這個(gè)視圖就可以被更新。
幾個(gè)具有代表性的條件:

  1. SELECT子句中未使用DISTINCT
  2. FROM子句中只有一張表
  3. 未使用GROUP BY子句
  4. 未使用HAVING子句

刪除視圖

刪除視圖的DROP VIEW語句

DROP VIEW 視圖名稱

刪除視圖ProductSum

DROP VIEW ProductSum;

子查詢

子查詢和視圖

子查詢就是一次性的視圖(SELECT語句),子查詢?cè)?code>SELECT語句執(zhí)行完畢之后就會(huì)消失。

子查詢

-- 和上面使用ProductSum視圖實(shí)現(xiàn)相同功能的子查詢語句
SELECT
    product_type,
    cnt_product
FROM (
SELECT
    product_type,
    COUNT(*) AS cnt_product
FROM Product
GROUP BY product_type
) AS ProductSum;

執(zhí)行結(jié)果:


子查詢SELECT語句的執(zhí)行順序


由內(nèi)到外:

  1. 首先執(zhí)行FROM子句中的SELECT語句;
  2. 根據(jù)1的結(jié)果執(zhí)行外層的SELECT語句。

注意:子查詢的層數(shù)原則上沒有限制,可以無限嵌套下去,但是,隨著層數(shù)增加,SQL語句會(huì)變得越來越難讀懂,性能也會(huì)越來越差。因此,盡量避免使用多層嵌套的子查詢。

子查詢的名稱
原則上子查詢必須設(shè)定名稱,設(shè)定名稱是需要使用AS關(guān)鍵字,有時(shí)也可以省略。

標(biāo)量子查詢

標(biāo)量子查詢就是返回單一值的子查詢,必須而且只能返回表中某一行的某一列的值。

WHERE子句中使用標(biāo)量子查詢

如何查詢出銷售單價(jià)高于平均銷售單價(jià)的商品?
我們可能會(huì)想到以下錯(cuò)誤的SQL語句

-- 在WHERE子句中不能使用聚合函數(shù)
SELECT
    product_id,
    product_name,
    sale_price
FROM Product
WHERE sale_price > AVG(sale_price);

雖然這樣的SELECT語句看上去能夠滿足我們的要求,但是由于在WHERE子句中不能使用聚合函數(shù),因此這樣的SELECT語句是錯(cuò)誤的。
這時(shí),標(biāo)量子查詢就可以發(fā)揮它的功效了。

計(jì)算平均銷售單價(jià)的標(biāo)量子查詢

SELECT AVG(sale_price)
FROM Product;

執(zhí)行結(jié)果:


選出銷售單價(jià)高于平均單價(jià)的商品

SELECT
    product_id,
    product_name,
    sale_price
FROM Product
WHERE sale_price > (SELECT AVG(sale_price)
                    FROM Product);

執(zhí)行結(jié)果:


標(biāo)量子查詢的書寫位置

通常任何可以使用單一值的位置都可以使用標(biāo)量子查詢,也就是說,能夠使用常數(shù)或者列名的地方,無論是SELECT子句、GROUP BY子句、HAVING子句,還是ORDER BY子句,都可以使用。

注意:如果子查詢返回了多行結(jié)果,那么它就不再是標(biāo)量子查詢,而僅僅只是一個(gè)普通的子查詢,因此不能被用在需要單一輸入值的地方。

關(guān)聯(lián)子查詢

通過關(guān)聯(lián)子查詢按照商品種類對(duì)平均銷售單價(jià)進(jìn)行比較

SELECT
    product_id,
    product_name,
    sale_price
FROM Product AS P1
WHERE sale_price > (SELECT AVG(sale_price)
                    FROM Product AS P2
                    WHERE P1.product_type = P2.product_type);

執(zhí)行結(jié)果:


這里起關(guān)鍵作用的就是在子查詢中添加WHERE子句的條件,該條件的意思就是,在同一商品種類中對(duì)各商品的銷售單價(jià)和平均單價(jià)進(jìn)行比較。

我的博客即將同步至騰訊云+社區(qū),邀請(qǐng)大家一同入駐:
https://cloud.tencent.com/developer/support-plan?invite_code=1979ipzwsgq9u

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容