最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SQL高級(jí)查詢與預(yù)處理語句解析以及實(shí)戰(zhàn)練習(xí)題

 更新時(shí)間:2025年10月30日 10:38:01   作者:洲覆  
預(yù)處理語句是數(shù)據(jù)庫優(yōu)化技術(shù)中的一項(xiàng)重要功能,它允許數(shù)據(jù)庫服務(wù)器預(yù)先解析SQL語句并生成執(zhí)行計(jì)劃,然后在后續(xù)執(zhí)行中只需傳遞參數(shù)即可重復(fù)使用,這篇文章主要介紹了SQL高級(jí)查詢與預(yù)處理語句解析以及實(shí)戰(zhàn)練習(xí)題的相關(guān)資料,需要的朋友可以參考下

一、SQL高級(jí)查詢

1.1 表結(jié)構(gòu)創(chuàng)建

通過SQL語句創(chuàng)建5張核心表(班級(jí)表、課程表、成績表、學(xué)生表、教師表),并定義字段類型、主鍵、外鍵及自增規(guī)則,確保表間數(shù)據(jù)關(guān)聯(lián)的完整性。

-- 1. 班級(jí)表(class):存儲(chǔ)班級(jí)信息
DROP TABLE IF EXISTS `class`;
CREATE TABLE `class` (
  `cid` int(11) NOT NULL AUTO_INCREMENT, -- 班級(jí)ID,自增主鍵
  `caption` varchar(32) NOT NULL, -- 班級(jí)名稱(如“高一1班”)
  PRIMARY KEY (`cid`)
) ENGINE=innoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- 2. 課程表(course):存儲(chǔ)課程信息,關(guān)聯(lián)教師表
DROP TABLE IF EXISTS `course`;
CREATE TABLE `course` (
  `cid` int(11) NOT NULL AUTO_INCREMENT, -- 課程ID,自增主鍵
  `cname` varchar(32) NOT NULL, -- 課程名稱(如“數(shù)學(xué)”)
  `teacher_id` int(11) NOT NULL, -- 授課教師ID,關(guān)聯(lián)教師表的tid
  PRIMARY KEY (`cid`),
  KEY `fk_course_teacher` (`teacher_id`), -- 為外鍵創(chuàng)建索引,提升查詢效率
  CONSTRAINT `fk_course_teacher` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`tid`) -- 外鍵約束
) ENGINE=innoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- 3. 成績表(score):存儲(chǔ)學(xué)生成績,關(guān)聯(lián)學(xué)生表和課程表
DROP TABLE IF EXISTS `score`;
CREATE TABLE `score` (
  `sid` int(11) NOT NULL AUTO_INCREMENT, -- 成績記錄ID,自增主鍵
  `student_id` int(11) NOT NULL, -- 學(xué)生ID,關(guān)聯(lián)學(xué)生表的sid
  `course_id` int(11) NOT NULL, -- 課程ID,關(guān)聯(lián)課程表的cid
  `num` int(11) NOT NULL, -- 分?jǐn)?shù)(如85、92)
  PRIMARY KEY (`sid`),
  KEY `fk_score_student` (`student_id`), -- 外鍵索引
  KEY `fk_score_course` (`course_id`), -- 外鍵索引
  CONSTRAINT `fk_score_course` FOREIGN KEY (`course_id`) REFERENCES `course` (`cid`), -- 外鍵約束(關(guān)聯(lián)課程)
  CONSTRAINT `fk_score_student` FOREIGN KEY (`student_id`) REFERENCES `student` (`sid`) -- 外鍵約束(關(guān)聯(lián)學(xué)生)
) ENGINE=innoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8;

-- 4. 學(xué)生表(student):存儲(chǔ)學(xué)生信息,關(guān)聯(lián)班級(jí)表
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `sid` int(11) NOT NULL AUTO_INCREMENT, -- 學(xué)生ID,自增主鍵
  `gender` char(1) NOT NULL, -- 性別(如“男”“女”)
  `class_id` int(11) NOT NULL, -- 班級(jí)ID,關(guān)聯(lián)班級(jí)表的cid
  `sname` varchar(32) NOT NULL, -- 學(xué)生姓名
  PRIMARY KEY (`sid`),
  KEY `fk_class` (`class_id`), -- 外鍵索引
  CONSTRAINT `fk_class` FOREIGN KEY (`class_id`) REFERENCES `class` (`cid`) -- 外鍵約束(關(guān)聯(lián)班級(jí))
) ENGINE=innoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;

-- 5. 教師表(teacher):存儲(chǔ)教師信息
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
  `tid` int(11) NOT NULL AUTO_INCREMENT, -- 教師ID,自增主鍵
  `tname` varchar(32) NOT NULL, -- 教師姓名
  PRIMARY KEY (`tid`)
) ENGINE=innoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

1.2 基礎(chǔ)查詢

基礎(chǔ)查詢是SQL的核心操作,用于從表中提取所需數(shù)據(jù),主要包括“查詢?nèi)孔侄?rdquo;“查詢部分字段”“給字段起別名”“去除重復(fù)記錄”四種場景,語法簡單且高頻使用。

  1. 查詢?nèi)孔侄?/strong>:使用SELECT *獲取表中所有字段的數(shù)據(jù),適用于需要完整數(shù)據(jù)的場景,但效率較低(不推薦在表字段較多時(shí)使用)。

    SELECT * FROM student; -- 查詢student表中所有學(xué)生的全部信息
    
  2. 查詢部分字段:指定需要的字段名(用逗號(hào)分隔),只獲取目標(biāo)數(shù)據(jù),效率高于查詢?nèi)孔侄巍?/p>

    SELECT `sname`, `class_id` FROM student; -- 只查詢student表中的“學(xué)生姓名”和“班級(jí)ID”
    
  3. 給字段起別名:使用AS關(guān)鍵字給字段重命名,使查詢結(jié)果更易理解,注意別名不能使用SQL關(guān)鍵字(如“select”“from”)。

    SELECT `sname` AS '姓名' , `class_id` AS '班級(jí)ID' FROM student; -- 字段別名分別為“姓名”“班級(jí)ID”
    
  4. 去除重復(fù)記錄:使用DISTINCT關(guān)鍵字,刪除查詢結(jié)果中完全重復(fù)的行,適用于需要唯一值的場景(如統(tǒng)計(jì)有多少個(gè)不同的班級(jí))。

    SELECT distinct `class_id` FROM student; -- 查詢student表中所有不重復(fù)的班級(jí)ID
    

1.3 條件查詢

條件查詢通過WHERE子句篩選符合條件的數(shù)據(jù),只返回滿足條件的記錄,支持單條件和多條件(用AND/OR連接)查詢,是數(shù)據(jù)篩選的核心。

  1. 單條件查詢:只設(shè)置一個(gè)篩選條件,獲取特定數(shù)據(jù)。

    -- 查詢姓名為“鄧洋洋”的學(xué)生的全部信息(字符串條件需用單引號(hào)或雙引號(hào)包裹)
    SELECT * FROM `student` WHERE `sname` = '鄧洋洋';
    
  2. 多條件查詢:用AND(同時(shí)滿足)或OR(滿足其一)連接多個(gè)條件,實(shí)現(xiàn)更精準(zhǔn)的篩選。

    -- 查詢“性別為男”并且“班級(jí)ID為2”的學(xué)生的全部信息(同時(shí)滿足兩個(gè)條件)
    SELECT * FROM `student` WHERE `gender`="男" AND `class_id`=2;
    

1.4 范圍查詢

范圍查詢用于篩選“字段值在某個(gè)連續(xù)范圍內(nèi)”的數(shù)據(jù),主要使用BETWEEN AND關(guān)鍵字,注意該關(guān)鍵字包含范圍的邊界值(即“起始值”和“結(jié)束值”都會(huì)被包含)。

-- 查詢班級(jí)ID在1到3之間的學(xué)生的全部信息(包含班級(jí)ID=1和班級(jí)ID=3的學(xué)生)
SELECT * FROM `student` WHERE `class_id` BETWEEN 1 AND 3;

1.5 判空查詢

判空查詢用于篩選“字段值為NULL”或“字段值為空字符串”的記錄,需區(qū)分兩種空值場景,且需注意IS NULL會(huì)導(dǎo)致索引失效(影響查詢效率)。

  1. 判斷字段值為NULL/非NULL:使用IS NULL(為空)或IS NOT NULL(不為空),適用于字段值未賦值的場景(NULL表示“無值”,而非空字符串)。

    SELECT * FROM `student` WHERE `class_id` IS NOT NULL; -- 查詢class_id字段值不為NULL的學(xué)生
    SELECT * FROM `student` WHERE `class_id` IS NULL;    -- 查詢class_id字段值為NULL的學(xué)生
    
  2. 判斷字段值為空字符串/非空字符串:使用 = = =(為空字符串)或<>(不為空字符串),適用于字段值賦值為空字符串('')的場景。

    SELECT * FROM `student` WHERE `gender` <> ''; -- 查詢gender字段值不為空字符串的學(xué)生
    SELECT * FROM `student` WHERE `gender` = '';  -- 查詢gender字段值為空字符串的學(xué)生
    

1.6 模糊查詢

模糊查詢通過LIKE關(guān)鍵字實(shí)現(xiàn)“非精確匹配”,支持通配符來替代不確定的字符,常用通配符有%(任意數(shù)量字符,包括0個(gè))和_(單個(gè)字符,必須有一個(gè))。

  1. %通配符:匹配“指定字符開頭/結(jié)尾/包含指定字符”的字符串。

    -- 查詢教師姓名以“謝”開頭的所有教師信息(“謝”后面可以跟任意數(shù)量的字符)
    SELECT * FROM `teacher` WHERE `tname` LIKE '謝%';
    
  2. _通配符:匹配“指定位置有特定字符”的字符串,每個(gè)_代表一個(gè)占位符(必須匹配一個(gè)字符,不能多也不能少)。

    -- 查詢教師姓名中第二個(gè)字為“小”的所有教師信息(第一個(gè)字任意,第二個(gè)字是“小”,后面任意)
    SELECT * FROM `teacher` WHERE `tname` LIKE '_小%';
    

1.7 分頁查詢

分頁查詢用于“按頁獲取數(shù)據(jù)”,通過LIMIT關(guān)鍵字實(shí)現(xiàn),語法為 LIMIT 起始位置, 顯示條數(shù),注意表中默認(rèn)第一條記錄的起始位置為0。

-- 查詢student表中“從第2條記錄開始,顯示2條記錄”(即第2條和第3條記錄)
-- 起始位置計(jì)算:第N條記錄的起始位置 = N-1(第2條的起始位置是1)
SELECT * FROM `student` LIMIT 1,2;

1.8 查詢后排序

查詢后排序通過ORDER BY關(guān)鍵字對(duì)查詢結(jié)果按指定字段排序,支持“升序”和“降序”,也可按多個(gè)字段排序,確保結(jié)果的有序性。

  1. 單字段排序:按一個(gè)字段排序,ASC表示升序(從小到大,默認(rèn)值,可省略),DESC表示降序(從大到小)。

    -- 按成績表(score)的分?jǐn)?shù)(num)升序排序(分?jǐn)?shù)從低到高)
    SELECT * FROM `score` ORDER BY `num` ASC;
    
  2. 多字段排序:按多個(gè)字段排序,先按第一個(gè)字段排序,若第一個(gè)字段值相同,則按第二個(gè)字段排序,以此類推。

    -- 先按課程ID(course_id)降序排序,課程ID相同的再按分?jǐn)?shù)(num)降序排序
    SELECT * FROM `score` ORDER BY `course_id` DESC, `num` DESC;
    

1.9 聚合查詢

聚合查詢通過“聚合函數(shù)”對(duì)一列數(shù)據(jù)進(jìn)行統(tǒng)計(jì)計(jì)算,返回單個(gè)結(jié)果(如“總分”“平均分”),常用聚合函數(shù)有5種,適用于數(shù)據(jù)統(tǒng)計(jì)場景。

常用聚合函數(shù)說明:

聚合函數(shù)描述
sum()計(jì)算某列的總和(僅適用于數(shù)值類型字段)
avg()計(jì)算某列的平均值(僅適用于數(shù)值類型字段)
max()計(jì)算某列的最大值(可用于數(shù)值、字符串、日期類型)
min()計(jì)算某列的最小值(可用于數(shù)值、字符串、日期類型)
count()計(jì)算某列的行數(shù)(統(tǒng)計(jì)非NULL值的數(shù)量)

聚合函數(shù)示例:

SELECT sum(`num`) FROM `score`;  -- 計(jì)算score表中所有分?jǐn)?shù)的總和
SELECT avg(`num`) FROM `score`;  -- 計(jì)算score表中所有分?jǐn)?shù)的平均值
SELECT max(`num`) FROM `score`;  -- 找出score表中分?jǐn)?shù)的最大值
SELECT min(`num`) FROM `score`;  -- 找出score表中分?jǐn)?shù)的最小值
SELECT count(`num`) FROM `score`;-- 統(tǒng)計(jì)score表中分?jǐn)?shù)的有效記錄數(shù)(num不為NULL的行數(shù))

1.10 分組查詢

分組查詢通過GROUP BY關(guān)鍵字將數(shù)據(jù)按指定字段“分組”,再對(duì)每組數(shù)據(jù)進(jìn)行統(tǒng)計(jì)(常與聚合函數(shù)搭配),也可通過HAVING篩選分組后的結(jié)果(區(qū)別于WHERE篩選分組前的數(shù)據(jù))。

  1. 基礎(chǔ)分組:僅按指定字段分組,返回每組的唯一值。

    -- 按學(xué)生性別(gender)分組,返回“男”“女”兩個(gè)分組(每個(gè)分組一行)
    SELECT `gender` FROM `student` GROUP BY `gender`;
    
  2. 分組+拼接字段:用group_concat(字段名)將每組中指定字段的所有值拼接成一個(gè)字符串,方便查看組內(nèi)詳情。

    -- 按性別分組,同時(shí)拼接每組學(xué)生的年齡(ages為別名)
    SELECT `gender`, group_concat(`age`) as ages FROM `student` GROUP BY `gender`;
    
  3. 分組+聚合函數(shù):對(duì)每組數(shù)據(jù)使用聚合函數(shù)統(tǒng)計(jì),獲取每組的統(tǒng)計(jì)結(jié)果(如“每組的人數(shù)”“每組的平均分”)。

    -- 按性別分組,統(tǒng)計(jì)每組的學(xué)生人數(shù)(num為別名,count(*)表示統(tǒng)計(jì)每組的總行數(shù))
    SELECT `gender`, count(*) as num FROM `student` GROUP BY `gender`;
    
  4. 分組+篩選(HAVING):用HAVING對(duì)分組后的結(jié)果篩選(類似WHERE,但HAVING作用于分組后,支持聚合函數(shù))。

    -- 按性別分組,統(tǒng)計(jì)每組人數(shù)后,只保留人數(shù)大于6的分組
    SELECT `gender`, count(*) as num FROM `student` GROUP BY `gender` HAVING num > 6;
    

1.11 聯(lián)表查詢

聯(lián)表查詢用于“關(guān)聯(lián)多個(gè)表”獲取數(shù)據(jù)(因?yàn)閱伪頂?shù)據(jù)有限,需結(jié)合多表信息),核心是通過“外鍵”建立表間關(guān)聯(lián),常用連接方式有三種:INNER JOIN、LEFT JOIN、RIGHT JOIN。

三種連接方式的區(qū)別

連接方式核心特點(diǎn)適用場景
INNER JOIN(內(nèi)連接)只取兩表中“有對(duì)應(yīng)關(guān)系”的記錄(無對(duì)應(yīng)關(guān)系的記錄會(huì)被過濾)需獲取兩表都存在的數(shù)據(jù)(如“有授課教師的課程”)
LEFT JOIN(左連接)保留左表所有記錄,右表只取有對(duì)應(yīng)關(guān)系的記錄(右表無對(duì)應(yīng)則為NULL)需保留左表全部數(shù)據(jù),同時(shí)關(guān)聯(lián)右表數(shù)據(jù)(如“所有課程及對(duì)應(yīng)的教師,無教師的課程也顯示”)
RIGHT JOIN(右連接)保留右表所有記錄,左表只取有對(duì)應(yīng)關(guān)系的記錄(左表無對(duì)應(yīng)則為NULL)需保留右表全部數(shù)據(jù),同時(shí)關(guān)聯(lián)左表數(shù)據(jù)(如“所有教師及對(duì)應(yīng)的課程,無課程的教師也顯示”)

聯(lián)表查詢示例

  1. INNER JOIN(內(nèi)連接)

    -- 關(guān)聯(lián)course(課程表)和teacher(教師表),只查詢“有對(duì)應(yīng)教師的課程”的課程ID
    -- ON后面是兩表的關(guān)聯(lián)條件:課程表的teacher_id = 教師表的tid
    SELECT course.cid
    FROM `course`
    INNER JOIN `teacher` ON course.teacher_id = teacher.tid;
    
  2. LEFT JOIN(左連接)

    -- 關(guān)聯(lián)course(左表)和teacher(右表),保留所有課程,關(guān)聯(lián)對(duì)應(yīng)的教師(無教師的課程cid仍顯示,教師信息為NULL)
    SELECT course.cid
    FROM `course`
    LEFT JOIN `teacher` ON course.teacher_id = teacher.tid;
    
  3. RIGHT JOIN(右連接)

    -- 關(guān)聯(lián)course(左表)和teacher(右表),保留所有教師,關(guān)聯(lián)對(duì)應(yīng)的課程(無課程的教師仍顯示,課程cid為NULL)
    SELECT course.cid
    FROM `course`
    RIGHT JOIN `teacher` ON course.teacher_id = teacher.tid;
    

1.12 子查詢/合并查詢

子查詢是“嵌套在其他查詢中的查詢”,內(nèi)層查詢的結(jié)果作為外層查詢的條件或數(shù)據(jù)源,按返回結(jié)果行數(shù)可分為“單行子查詢”和“多行子查詢”,也可在FROM子句中作為臨時(shí)表使用。

單行子查詢

內(nèi)層查詢返回“一行一列”的結(jié)果,外層查詢用“=”“>”等單值比較符使用該結(jié)果,適用于“基于單個(gè)值篩選”的場景。

-- 先查“謝小二老師”的tid(內(nèi)層子查詢),再查該教師授課的所有課程(外層查詢)
select * from course where teacher_id = (select tid from teacher where tname = '謝小二老師');

多行子查詢

內(nèi)層查詢返回“多行數(shù)據(jù)”,外層查詢需用支持多行的關(guān)鍵字(如IN、EXISTS、ALL、ANY),適用于“基于多個(gè)值篩選”的場景。

  1. IN關(guān)鍵字:檢測外層查詢的字段值是否“在”內(nèi)層查詢的結(jié)果集中,存在則返回該記錄。

    -- 先查“teacher_id=2的教師”所授課程的cid(內(nèi)層),再查“班級(jí)ID在這些課程中的學(xué)生”(外層)
    select * from student where class_id in (select cid from course where teacher_id = 2);
    
  2. EXISTS關(guān)鍵字:判斷內(nèi)層查詢是否“存在滿足條件的記錄”(不關(guān)心具體結(jié)果,只返回真假)。若內(nèi)層返回真(有記錄),則執(zhí)行外層查詢;若返回假(無記錄),則外層查詢無結(jié)果。

    -- 先判斷“是否存在cid=5的課程”(內(nèi)層),若存在,則查詢所有學(xué)生(外層);若不存在,則無結(jié)果
    select * from student where exists(select cid from course where cid = 5);
    
  3. ALL關(guān)鍵字:外層查詢的字段值需“滿足內(nèi)層查詢返回的所有結(jié)果”,才返回該記錄(如“大于所有值”“小于所有值”)。

  4. ANY關(guān)鍵字:外層查詢的字段值只需“滿足內(nèi)層查詢返回的任意一個(gè)結(jié)果”,就返回該記錄(如“大于任意一個(gè)值”“小于任意一個(gè)值”)。

FROM子句中的子查詢

將內(nèi)層查詢的結(jié)果作為“臨時(shí)表”(需用AS取別名),外層查詢從臨時(shí)表中獲取數(shù)據(jù),適用于“需先篩選數(shù)據(jù),再關(guān)聯(lián)其他表”的場景。

-- 1. 內(nèi)層查詢:篩選score表中“course_id=1或course_id=2”的記錄,作為臨時(shí)表A
-- 2. 外層查詢:關(guān)聯(lián)臨時(shí)表A和student表,獲取學(xué)生ID和學(xué)生姓名
SELECT
   student_id,
   sname
FROM
    (SELECT * FROM score WHERE course_id = 1 OR course_id = 2) AS A -- 臨時(shí)表A(必須取別名)
      LEFT JOIN student ON A.student_id = student.sid; -- 關(guān)聯(lián)臨時(shí)表A和student表

1.13 正則表達(dá)式查詢

正則表達(dá)式通過REGEXP關(guān)鍵字實(shí)現(xiàn)“更靈活的模糊匹配”,支持多種匹配規(guī)則(如“開頭匹配”“任意字符匹配”),比LIKE的匹配能力更強(qiáng)。

常用正則表達(dá)式規(guī)則

選項(xiàng)說明(自動(dòng)加“匹配”二字)例子匹配值示例
^文本開始字符'^b’匹配以字母b開頭的字符串book, big, banana, bike
.任何單個(gè)字符'b.t’匹配任何b和t之間有一個(gè)字符bit, bat, but, bite
*0個(gè)或多個(gè)在它前面的字符'f*n’匹配字符n前面有任意個(gè)(含0個(gè))字符ffn, fan, faan, abcn
+前面的字符一次或多次'ba+'匹配以b開頭、后面緊跟至少一個(gè)aba, bay, bare, battle
<字符串>包含指定字符串的文本'fa’匹配包含“fa”的字符串fan, afa, faad
[字符集合]字符集合中的任一個(gè)字符'[xz]'匹配包含x或者z的字符串dizzy, zebra, x-ray, extra
[^]不在括號(hào)中的任何字符'[^abc]'匹配不包含a、b、c中任意一個(gè)的字符串desk, fox, f8ke
字符串{n}前面的字符串至少n次'b{2}'匹配包含2個(gè)或更多b的字符串bbb, bbbb, bbbbbb
字符串{n,m}前面的字符串至少n次、至多m次'b{2,4}'匹配包含最少2個(gè)、最多4個(gè)b的字符串bb, bbb, bbbb

正則表達(dá)式示例

-- 查詢教師姓名“以‘謝'開頭”的所有教師信息(用^匹配開頭,REGEXP指定正則規(guī)則)
SELECT * FROM `teacher` WHERE `tname` REGEXP '^謝';

二、預(yù)處理語句

預(yù)處理語句是“將SQL語句分為‘準(zhǔn)備’和‘執(zhí)行’兩個(gè)階段”的技術(shù),主要用于高頻重復(fù)執(zhí)行的SQL,核心優(yōu)勢是“提升效率”和“防止SQL注入”。

2.1 預(yù)處理語句的核心流程

準(zhǔn)備階段:將SQL語句發(fā)送給數(shù)據(jù)庫服務(wù)器,服務(wù)器對(duì)SQL進(jìn)行解析、編譯、優(yōu)化,并生成“執(zhí)行計(jì)劃”緩存起來(只執(zhí)行一次)。

執(zhí)行階段:將具體的參數(shù)傳遞給緩存的執(zhí)行計(jì)劃,服務(wù)器直接使用計(jì)劃執(zhí)行SQL(無需再次解析編譯)。

2.2 預(yù)處理語句的優(yōu)點(diǎn)

  • 減少重復(fù)解析和編譯:同一SQL只需準(zhǔn)備一次,后續(xù)執(zhí)行只需傳參數(shù),提升高頻查詢的效率。
  • 防止SQL注入:參數(shù)會(huì)被數(shù)據(jù)庫自動(dòng)檢查數(shù)據(jù)類型,避免因“拼接字符串”導(dǎo)致的SQL注入漏洞(如用戶輸入惡意SQL片段)。

2.3 預(yù)處理語句示例

預(yù)處理語句用?作為“參數(shù)占位符”,表示后續(xù)會(huì)傳遞具體值,示例如下:

-- 預(yù)處理語句:查詢表中id等于某個(gè)參數(shù)的記錄(?為參數(shù)占位符)
select * from table where id = ?;

說明:該語句第一次執(zhí)行時(shí),服務(wù)器會(huì)解析、編譯并緩存執(zhí)行計(jì)劃;后續(xù)執(zhí)行時(shí),只需傳入?對(duì)應(yīng)的具體值(如1、2),服務(wù)器直接使用緩存計(jì)劃執(zhí)行,無需重復(fù)處理SQL結(jié)構(gòu)。

三、練習(xí)

1. 查詢平均成績大于60分的同學(xué)的學(xué)號(hào)和平均成績

思路:按學(xué)生ID分組(GROUP BY student_id),用AVG(num)計(jì)算平均分,再用HAVING篩選平均分大于60的分組。

SELECT
  student_id, -- 學(xué)生學(xué)號(hào)(關(guān)聯(lián)student表的sid)
  AVG( num ) AS avg_num -- 平均成績(別名avg_num)
FROM
  score -- 從成績表查詢
GROUP BY
  student_id -- 按學(xué)生ID分組(確保每個(gè)學(xué)生一個(gè)分組)
HAVING
  avg_num > 60; -- 篩選平均分大于60的分組

2. 查詢 ‘c++’ 課程比 ‘數(shù)據(jù)庫’ 課程成績高的所有學(xué)生的學(xué)號(hào)

思路:先分別查詢“c++”和“數(shù)據(jù)庫”課程的學(xué)生成績(作為兩個(gè)臨時(shí)表),再關(guān)聯(lián)兩個(gè)臨時(shí)表,篩選c++成績大于數(shù)據(jù)庫成績的學(xué)生ID。

1)先查詢“c++”和“數(shù)據(jù)庫”課程的cid(確定課程唯一標(biāo)識(shí)):

SELECT cid FROM course WHERE cname = 'c++'; -- 假設(shè)返回cid=1
SELECT cid FROM course WHERE cname = '數(shù)據(jù)庫'; -- 假設(shè)返回cid=2

2)分別查詢兩門課程的“學(xué)生ID”和“分?jǐn)?shù)”(作為臨時(shí)表A和B):

-- 臨時(shí)表A:c++課程的學(xué)生ID和分?jǐn)?shù)
SELECT student_id, num FROM score where course_id = (SELECT cid FROM course WHERE cname = 'c++');
-- 臨時(shí)表B:數(shù)據(jù)庫課程的學(xué)生ID和分?jǐn)?shù)
SELECT student_id, num FROM score where course_id = (SELECT cid FROM course WHERE cname = '數(shù)據(jù)庫');

3)關(guān)聯(lián)臨時(shí)表A和B,篩選c++成績大于數(shù)據(jù)庫成績的學(xué)生ID(兩種情況):

  • 情況1:只保留“同時(shí)選了兩門課”的學(xué)生(用INNER JOIN,無對(duì)應(yīng)課程的學(xué)生過濾):

    SELECT A.student_id 
    FROM
      (SELECT student_id, num FROM score where course_id = (SELECT cid FROM course WHERE cname = 'c++')) AS A
      INNER JOIN -- 內(nèi)連接,只保留兩表都有記錄的學(xué)生(同時(shí)選兩門課)
      (SELECT student_id, num FROM score where course_id = (SELECT cid FROM course WHERE cname = '數(shù)據(jù)庫')) AS B
      ON A.student_id = B.student_id -- 按學(xué)生ID關(guān)聯(lián)
    WHERE A.num > B.num; -- 篩選c++成績(A.num)大于數(shù)據(jù)庫成績(B.num)的學(xué)生
    
  • 情況2:保留“選了c++但沒選數(shù)據(jù)庫”的學(xué)生(用LEFT JOIN,沒選數(shù)據(jù)庫的學(xué)生B.num為NULL,A.num>NULL不成立,實(shí)際仍只保留有兩門成績的學(xué)生,邏輯與INNER JOIN類似):

    SELECT A.student_id 
    FROM
      (SELECT student_id, num FROM score where course_id = (SELECT cid FROM course WHERE cname = 'c++')) AS A
      LEFT JOIN -- 左連接,保留所有選c++的學(xué)生
      (SELECT student_id, num FROM score where course_id = (SELECT cid FROM course WHERE cname = '數(shù)據(jù)庫')) AS B
      ON A.student_id = B.student_id
    WHERE A.num > B.num;
    

3. 查詢所有同學(xué)的學(xué)號(hào)、姓名、選課數(shù)、總成績

思路:關(guān)聯(lián)student表(獲取學(xué)號(hào)、姓名)和score表(統(tǒng)計(jì)選課數(shù)、總成績),按學(xué)生ID分組,用COUNT(course_id)計(jì)算選課數(shù),SUM(num)計(jì)算總成績。

SELECT
  s.sid AS '學(xué)號(hào)',
  s.sname AS '姓名',
  COUNT(sc.course_id) AS '選課數(shù)', -- 統(tǒng)計(jì)每個(gè)學(xué)生的課程數(shù)量(course_id非NULL)
  SUM(sc.num) AS '總成績' -- 統(tǒng)計(jì)每個(gè)學(xué)生的分?jǐn)?shù)總和
FROM
  student s -- 學(xué)生表(別名s)
  LEFT JOIN score sc ON s.sid = sc.student_id -- 左連接成績表(確保沒選課的學(xué)生也顯示,選課數(shù)為0,總成績?yōu)镹ULL)
GROUP BY
  s.sid, s.sname; -- 按學(xué)生ID和姓名分組(確保每個(gè)學(xué)生一條記錄)

4. 查詢沒學(xué)過 ‘謝小二’ 老師課的同學(xué)的學(xué)號(hào)、姓名

思路:先查“謝小二老師”授課程的cid,再查“學(xué)過這些課程的學(xué)生ID”,最后從student表中排除這些學(xué)生,獲取沒學(xué)過的學(xué)生信息。

-- 步驟1:查謝小二老師的tid;步驟2:查該老師授課程的cid;步驟3:查學(xué)過這些課程的學(xué)生ID;步驟4:排除這些學(xué)生
SELECT sid AS '學(xué)號(hào)', sname AS '姓名'
FROM student
WHERE sid NOT IN (
  SELECT DISTINCT sc.student_id -- 學(xué)過謝小二老師課程的學(xué)生ID(去重)
  FROM score sc
  JOIN course c ON sc.course_id = c.cid
  JOIN teacher t ON c.teacher_id = t.tid
  WHERE t.tname = '謝小二' -- 篩選謝小二老師
);

5. 查詢學(xué)過課程編號(hào)為 ‘1’ 并且也學(xué)過課程編號(hào)為 ‘2’ 的同學(xué)的學(xué)號(hào)、姓名

思路:按學(xué)生ID分組,用COUNT(DISTINCT course_id)統(tǒng)計(jì)“同時(shí)選了1和2課程”的學(xué)生(分組后課程數(shù)為2),再關(guān)聯(lián)student表獲取姓名。

SELECT
  s.sid AS '學(xué)號(hào)',
  s.sname AS '姓名'
FROM
  student s
  JOIN score sc ON s.sid = sc.student_id
WHERE
  sc.course_id IN (1, 2) -- 只保留選了1或2課程的記錄
GROUP BY
  s.sid, s.sname
HAVING
  COUNT(DISTINCT sc.course_id) = 2; -- 篩選同時(shí)選了1和2課程的學(xué)生(課程數(shù)為2)

6. 查詢學(xué)過 ‘謝小二’ 老師所教的所有課的同學(xué)的學(xué)號(hào)、姓名

思路:先查“謝小二老師所教課程的總數(shù)”,再查“每個(gè)學(xué)生學(xué)過該老師課程的數(shù)量”,篩選“學(xué)生學(xué)過的數(shù)量=課程總數(shù)”的記錄(即學(xué)過所有課)。

-- 臨時(shí)表:謝小二老師所教課程的總數(shù)(假設(shè)為2)
WITH teacher_course_count AS (
  SELECT COUNT(cid) AS total FROM course WHERE teacher_id = (SELECT tid FROM teacher WHERE tname = '謝小二')
)
-- 查詢學(xué)過所有課程的學(xué)生
SELECT
  s.sid AS '學(xué)號(hào)',
  s.sname AS '姓名'
FROM
  student s
  JOIN score sc ON s.sid = sc.student_id
  JOIN course c ON sc.course_id = c.cid
  JOIN teacher t ON c.teacher_id = t.tid
WHERE
  t.tname = '謝小二'
GROUP BY
  s.sid, s.sname
HAVING
  COUNT(DISTINCT sc.course_id) = (SELECT total FROM teacher_course_count); -- 學(xué)生學(xué)過的數(shù)量=課程總數(shù)

7. 查詢有課程成績小于 60 分的同學(xué)的學(xué)號(hào)、姓名

思路:從score表中篩選num<60的學(xué)生ID,去重后關(guān)聯(lián)student表獲取姓名(避免重復(fù)顯示同一學(xué)生)。

SELECT DISTINCT
  s.sid AS '學(xué)號(hào)',
  s.sname AS '姓名'
FROM
  student s
  JOIN score sc ON s.sid = sc.student_id
WHERE
  sc.num < 60; -- 篩選成績小于60的記錄,DISTINCT避免同一學(xué)生重復(fù)顯示

8. 查詢沒有學(xué)全所有課的同學(xué)的學(xué)號(hào)、姓名

思路:先查“所有課程的總數(shù)”,再查“每個(gè)學(xué)生的選課數(shù)”,篩選“選課數(shù)<課程總數(shù)”的學(xué)生(即沒學(xué)全)。

-- 臨時(shí)表:所有課程的總數(shù)(假設(shè)為4)
WITH all_course_count AS (
  SELECT COUNT(cid) AS total FROM course
)
-- 查詢沒學(xué)全所有課的學(xué)生
SELECT
  s.sid AS '學(xué)號(hào)',
  s.sname AS '姓名'
FROM
  student s
  LEFT JOIN score sc ON s.sid = sc.student_id
GROUP BY
  s.sid, s.sname
HAVING
  COUNT(DISTINCT sc.course_id) < (SELECT total FROM all_course_count) -- 選課數(shù)<總課程數(shù)
  OR COUNT(DISTINCT sc.course_id) IS NULL; -- 包含沒選任何課的學(xué)生(選課數(shù)為NULL)

9. 查詢至少有一門課與學(xué)號(hào)為 ‘1’ 的同學(xué)所學(xué)相同的同學(xué)的學(xué)號(hào)和姓名;

思路:先查“學(xué)號(hào)1的同學(xué)所學(xué)的所有課程ID”,再查“學(xué)過這些課程的其他學(xué)生”(排除學(xué)號(hào)1本身)。

SELECT DISTINCT
  s.sid AS '學(xué)號(hào)',
  s.sname AS '姓名'
FROM
  student s
  JOIN score sc ON s.sid = sc.student_id
WHERE
  sc.course_id IN (
    SELECT course_id FROM score WHERE student_id = 1 -- 學(xué)號(hào)1的同學(xué)所學(xué)的課程ID
  )
  AND s.sid <> 1; -- 排除學(xué)號(hào)1本身,DISTINCT避免同一學(xué)生重復(fù)顯示

10. 查詢至少學(xué)過學(xué)號(hào)為 ‘1’ 同學(xué)所有課的其他同學(xué)學(xué)號(hào)和姓名

思路:先查“學(xué)號(hào)1的同學(xué)所學(xué)課程的總數(shù)”,再查“其他學(xué)生學(xué)過這些課程的數(shù)量”,篩選“學(xué)生學(xué)過的數(shù)量=課程總數(shù)”的記錄(即學(xué)過學(xué)號(hào)1的所有課)。

-- 臨時(shí)表:學(xué)號(hào)1的同學(xué)所學(xué)課程的總數(shù)(假設(shè)為3)
WITH student1_course_count AS (
  SELECT COUNT(course_id) AS total FROM score WHERE student_id = 1
)
-- 查詢至少學(xué)過學(xué)號(hào)1所有課的其他同學(xué)
SELECT
  s.sid AS '學(xué)號(hào)',
  s.sname AS '姓名'
FROM
  student s
  JOIN score sc ON s.sid = sc.student_id
WHERE
  s.sid <> 1 -- 排除學(xué)號(hào)1本身
  AND sc.course_id IN (SELECT course_id FROM score WHERE student_id = 1) -- 只保留學(xué)號(hào)1學(xué)過的課程
GROUP BY
  s.sid, s.sname
HAVING
  COUNT(DISTINCT sc.course_id) = (SELECT total FROM student1_course_count); -- 學(xué)生學(xué)過的數(shù)量=學(xué)號(hào)1的課程總數(shù)

總結(jié) 

到此這篇關(guān)于SQL高級(jí)查詢與預(yù)處理語句解析以及實(shí)戰(zhàn)練習(xí)題的文章就介紹到這了,更多相關(guān)SQL高級(jí)查詢與預(yù)處理語句內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • mysql數(shù)據(jù)庫limit的四種用法小結(jié)

    mysql數(shù)據(jù)庫limit的四種用法小結(jié)

    mysql數(shù)據(jù)庫中l(wèi)imit子句可以被用于強(qiáng)制select語句返回指定的記錄數(shù),本文主要介紹了mysql數(shù)據(jù)庫limit的四種用法小結(jié),感興趣的可以了解一下
    2023-10-10
  • MySQL錯(cuò)誤“Data?too?long”的原因、解決方案與優(yōu)化策略

    MySQL錯(cuò)誤“Data?too?long”的原因、解決方案與優(yōu)化策略

    MySQL作為重要的數(shù)據(jù)庫系統(tǒng),在數(shù)據(jù)插入時(shí)可能遇到“Data?too?long?for?column”錯(cuò)誤,本文探討了該錯(cuò)誤的原因、解決方案及預(yù)防措施,如調(diào)整字段長度、使用TEXT類型等,旨在優(yōu)化數(shù)據(jù)庫設(shè)計(jì),提升性能和用戶體驗(yàn),需要的朋友可以參考下
    2024-09-09
  • MySQL慢查詢以及重構(gòu)查詢的方式記錄

    MySQL慢查詢以及重構(gòu)查詢的方式記錄

    MySQL的慢查詢,全名是慢查詢?nèi)罩?是MySQL提供的一種日志記錄,用來記錄在MySQL中響應(yīng)時(shí)間超過閥值的語句,這篇文章主要給大家介紹了關(guān)于MySQL慢查詢以及重構(gòu)查詢的相關(guān)資料,需要的朋友可以參考下
    2021-06-06
  • 兩大步驟教您開啟MySQL 數(shù)據(jù)庫遠(yuǎn)程登陸帳號(hào)的方法

    兩大步驟教您開啟MySQL 數(shù)據(jù)庫遠(yuǎn)程登陸帳號(hào)的方法

    在工作實(shí)踐和學(xué)習(xí)中,如何開啟 MySQL 數(shù)據(jù)庫的遠(yuǎn)程登陸帳號(hào)算是一個(gè)難點(diǎn)的問題,以下內(nèi)容便是在工作和實(shí)踐中總結(jié)出來的兩大步驟,能幫助DBA們順利的完成開啟 MySQL 數(shù)據(jù)庫的遠(yuǎn)程登陸帳號(hào)。
    2011-03-03
  • mysql 全文檢索中文解決方法及實(shí)例代碼

    mysql 全文檢索中文解決方法及實(shí)例代碼

    這篇文章主要介紹了mysql 全文檢索中文解決方法及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • mybatis mysql delete in操作只能刪除第一條數(shù)據(jù)的方法

    mybatis mysql delete in操作只能刪除第一條數(shù)據(jù)的方法

    這篇文章主要介紹了mybatis mysql delete in操作只能刪除第一條數(shù)據(jù)的問題及解決方法,需要的朋友可以參考下
    2018-09-09
  • MYSQL中解析json格式數(shù)據(jù)方法示例

    MYSQL中解析json格式數(shù)據(jù)方法示例

    這篇文章主要給大家介紹了關(guān)于MYSQL中解析json格式數(shù)據(jù)的相關(guān)資料,JSON是一種輕量級(jí)的數(shù)據(jù)交換格式,采用了獨(dú)立于語言的文本格式,類似XML,但是比XML簡單,易讀并且易編寫,需要的朋友可以參考下
    2023-08-08
  • mysql使用mysql.help_topic表實(shí)現(xiàn)一行轉(zhuǎn)多行的實(shí)現(xiàn)示例

    mysql使用mysql.help_topic表實(shí)現(xiàn)一行轉(zhuǎn)多行的實(shí)現(xiàn)示例

    本文主要介紹了mysql使用mysql.help_topic表實(shí)現(xiàn)一行轉(zhuǎn)多行的實(shí)現(xiàn)示例,通過使用SUBSTRING_INDEX函數(shù),可以將逗號(hào)分隔的字符串拆分成多行,感興趣的可以了解一下
    2025-02-02
  • MySQL數(shù)據(jù)庫之存儲(chǔ)過程?procedure

    MySQL數(shù)據(jù)庫之存儲(chǔ)過程?procedure

    這篇文章主要介紹了MySQL數(shù)據(jù)庫之存儲(chǔ)過程?procedure,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下
    2022-06-06
  • MySQL 日期和時(shí)間函數(shù)示例詳解

    MySQL 日期和時(shí)間函數(shù)示例詳解

    本文詳細(xì)介紹了MySQL中處理日期和時(shí)間的各種函數(shù),包括獲取當(dāng)前日期時(shí)間、日期提取、格式化和解析、計(jì)算和運(yùn)算、生成和構(gòu)造、驗(yàn)證和調(diào)整、時(shí)間戳轉(zhuǎn)換以及實(shí)用查詢示例,并提供了性能優(yōu)化建議,感興趣的朋友跟隨小編一起看看吧
    2026-03-03

最新評(píng)論

岳阳县| 武隆县| 文水县| 安平县| 象山县| 循化| 阆中市| 濉溪县| 浮梁县| 仙桃市| 开阳县| 郸城县| 胶州市| 德阳市| 宣威市| 沙田区| 昭苏县| 怀集县| 德兴市| 高要市| 扬中市| 哈巴河县| 张家港市| 阜城县| 卓尼县| 扬州市| 微博| 吉首市| 忻州市| 卢氏县| 葫芦岛市| 黎平县| 苏尼特右旗| 枣庄市| 新河县| 林口县| 井研县| 河北省| 建平县| 池州市| 监利县|