共计 17739 个字符,预计需要花费 45 分钟才能阅读完成。
死磕数据库系列(一):关系型数据库是如何工作的?
死磕数据库系列(二):数据库系统外围知识点详解
死磕数据库系列(三):关系型数据库设计实践与流程详解
SQL 语法根底
根底
模式定义了数据如何存储、存储什么样的数据以及数据如何合成等信息,数据库和表都有模式。
主键的值不容许批改,也不容许复用(不能应用曾经删除的主键值赋给新数据行的主键)。
SQL(Structured Query Language),规范 SQL 由 ANSI 规范委员会治理,从而称为 ANSI SQL。各个 DBMS 都有本人的实现,如 PL/SQL、Transact-SQL 等。
SQL 语句不辨别大小写,然而数据库表名、列名和值是否辨别依赖于具体的 DBMS 以及配置。
SQL 反对以下三种正文:
# 正文
SELECT *
FROM mytable; -- 正文
/* 正文 1
正文 2 */
数据库创立与应用:
CREATE DATABASE test;
USE test;
创立表
CREATE TABLE mytable (
id INT NOT NULL AUTO_INCREMENT,
col1 INT NOT NULL DEFAULT 1,
col2 VARCHAR(45) NULL,
col3 DATE NULL,
PRIMARY KEY (`id`));
批改表
增加列
ALTER TABLE mytable
ADD col CHAR(20);
批改列和属性(读者 @CodeHourra 补充)
---ALTER TABLE 表名 CHANGE 原字段名 新字段名 字段类型 约束条件
ALTER TABLE mytable
CHANGE col col1 CHAR(32) NOT NULL DEFAULT '123';
删除列
ALTER TABLE mytable
DROP COLUMN col;
删除表
DROP TABLE mytable;
插入
一般插入
INSERT INTO mytable(col1, col2)
VALUES(val1, val2);
插入检索进去的数据
INSERT INTO mytable1(col1, col2)
SELECT col1, col2
FROM mytable2;
将一个表的内容插入到一个新表
CREATE TABLE newtable AS
SELECT * FROM mytable;
更新
UPDATE mytable
SET col = val
WHERE id = 1;
删除
DELETE FROM mytable
WHERE id = 1;
TRUNCATE TABLE 能够清空表,也就是删除所有行。
TRUNCATE TABLE mytable;
应用更新和删除操作时肯定要用 WHERE 子句,不然会把整张表的数据都毁坏。能够先用 SELECT 语句进行测试,避免谬误删除。
查问
DISTINCT
雷同值只会呈现一次。它作用于所有列,也就是说所有列的值都雷同才算雷同。
SELECT DISTINCT col1, col2
FROM mytable;
LIMIT
限度返回的行数。能够有两个参数,第一个参数为起始行,从 0 开始;第二个参数为返回的总行数。
返回前 5 行:
SELECT *
FROM mytable
LIMIT 5;
SELECT *
FROM mytable
LIMIT 0, 5;
返回第 3 ~ 5 行:
SELECT *
FROM mytable
LIMIT 2, 3;
排序
- ASC : 升序(默认)
- DESC : 降序
能够按多个列进行排序,并且为每个列指定不同的排序形式:
SELECT *
FROM mytable
ORDER BY col1 DESC, col2 ASC;
过滤
不进行过滤的数据十分大,导致通过网络传输了多余的数据,从而节约了网络带宽。因而尽量应用 SQL 语句来过滤不必要的数据,而不是传输所有的数据到客户端中而后由客户端进行过滤。
SELECT *
FROM mytable
WHERE col IS NULL;
下表显示了 WHERE 子句可用的操作符
应该留神到,NULL 与 0、空字符串都不同。
AND 和 OR 用于连贯多个过滤条件。优先解决 AND,当一个过滤表达式波及到多个 AND 和 OR 时,能够应用 () 来决定优先级,使得优先级关系更清晰。
IN 操作符用于匹配一组值,其后也能够接一个 SELECT 子句,从而匹配子查问失去的一组值。
NOT 操作符用于否定一个条件。
通配符
通配符也是用在过滤语句中,但它只能用于文本字段。
- % 匹配 >=0 个任意字符;
- \_ 匹配 ==1 个任意字符;
- [] 能够匹配汇合内的字符,例如 [ab] 将匹配字符 a 或者 b。用脱字符 ^ 能够对其进行否定,也就是不匹配汇合内的字符。
应用 Like 来进行通配符匹配。
SELECT *
FROM mytable
WHERE col LIKE '[^AB]%'; -- 不以 A 和 B 结尾的任意文本
不要滥用通配符,通配符位于结尾处匹配会十分慢。
计算字段
在数据库服务器上实现数据的转换和格式化的工作往往比客户端上快得多,并且转换和格式化后的数据量更少的话能够缩小网络通信量。
计算字段通常须要应用 AS 来取别名,否则输入的时候字段名为计算表达式。
SELECT col1 * col2 AS alias
FROM mytable;
CONCAT() 用于连贯两个字段。许多数据库会应用空格把一个值填充为列宽,因而连贯的后果会呈现一些不必要的空格,应用 TRIM() 能够去除首尾空格。
SELECT CONCAT(TRIM(col1), '(', TRIM(col2), ')') AS concat_col
FROM mytable;
函数
各个 DBMS 的函数都是不雷同的,因而不可移植,以下次要是 MySQL 的函数。
汇总
SELECT AVG(DISTINCT col1) AS avg_col
FROM mytable;
文本处理
转换为语音值
其中,SOUNDEX() 能够将一个字符串转换为形容其语音示意的字母数字模式。
SELECT *
FROM mytable
WHERE SOUNDEX(col1) = SOUNDEX('apple')
日期和工夫解决
- 日期格局: YYYY-MM-DD
- 工夫格局: HH:MM:SS
mysql> SELECT NOW();
2018-4-14 20:25:11
数值解决
分组
分组就是把具备雷同的数据值的行放在同一组中。
能够对同一分组数据应用汇总函数进行解决,例如求分组数据的平均值等。
指定的分组字段除了能按该字段进行分组,也会主动按该字段进行排序。
SELECT col, COUNT(*) AS num
FROM mytable
GROUP BY col;
GROUP BY 主动按分组字段进行排序,ORDER BY 也能够按汇总字段来进行排序。
SELECT col, COUNT(*) AS num
FROM mytable
GROUP BY col
ORDER BY num;
WHERE 过滤行,HAVING 过滤分组,行过滤该当先于分组过滤。
SELECT col, COUNT(*) AS num
FROM mytable
WHERE col > 2
GROUP BY col
HAVING num >= 2;
分组规定:
- GROUP BY 子句呈现在 WHERE 子句之后,ORDER BY 子句之前;
- 除了汇总字段外,SELECT 语句中的每一字段都必须在 GROUP BY 子句中给出;
- NULL 的行会独自分为一组;
- 大多数 SQL 实现不反对 GROUP BY 列具备可变长度的数据类型。
子查问
子查问中只能返回一个字段的数据。
能够将子查问的后果作为 WHRER 语句的过滤条件:
SELECT *
FROM mytable1
WHERE col1 IN (SELECT col2
FROM mytable2);
上面的语句能够检索出客户的订单数量,子查问语句会对第一个查问检索出的每个客户执行一次:
SELECT cust_name, (SELECT COUNT(*)
FROM Orders
WHERE Orders.cust_id = Customers.cust_id)
AS orders_num
FROM Customers
ORDER BY cust_name;
连贯
连贯用于连贯多个表,应用 JOIN 关键字,并且条件语句应用 ON 而不是 WHERE。
连贯能够替换子查问,并且比子查问的效率个别会更快。
能够用 AS 给列名、计算字段和表名取别名,给表名取别名是为了简化 SQL 语句以及连贯雷同表。
内连贯
内连贯又称等值连贯,应用 INNER JOIN 关键字。
SELECT A.value, B.value
FROM tablea AS A INNER JOIN tableb AS B
ON A.key = B.key;
能够不明确应用 INNER JOIN,而应用一般查问并在 WHERE 中将两个表中要连贯的列用等值办法连接起来。
SELECT A.value, B.value
FROM tablea AS A, tableb AS B
WHERE A.key = B.key;
在没有条件语句的状况下返回笛卡尔积。
自连贯
自连贯能够看成内连贯的一种,只是连贯的表是本身而已。
一张员工表,蕴含员工姓名和员工所属部门,要找出与 Jim 处在同一部门的所有员工姓名。
子查问版本
SELECT name
FROM employee
WHERE department = (
SELECT department
FROM employee
WHERE name = "Jim");
自连贯版本
SELECT e1.name
FROM employee AS e1 INNER JOIN employee AS e2
ON e1.department = e2.department
AND e2.name = "Jim";
天然连贯
天然连贯是把同名列通过等值测试连接起来的,同名列能够有多个。
内连贯和天然连贯的区别: 内连贯提供连贯的列,而天然连贯主动连贯所有同名列。
SELECT A.value, B.value
FROM tablea AS A NATURAL JOIN tableb AS B;
外连贯
外连贯保留了没有关联的那些行。分为左外连贯,右外连贯以及全外连贯,左外连贯就是保留左表没有关联的行。
检索所有顾客的订单信息,包含还没有订单信息的顾客。
SELECT Customers.cust_id, Orders.order_num
FROM Customers LEFT OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id;
组合查问
应用 UNION 来组合两个查问,如果第一个查问返回 M 行,第二个查问返回 N 行,那么组合查问的后果个别为 M+N 行。
每个查问必须蕴含雷同的列、表达式和汇集函数。
默认会去除雷同行,如果须要保留雷同行,应用 UNION ALL。
只能蕴含一个 ORDER BY 子句,并且必须位于语句的最初。
SELECT col
FROM mytable
WHERE col = 1
UNION
SELECT col
FROM mytable
WHERE col =2;
视图
视图是虚构的表,自身不蕴含数据,也就不能对其进行索引操作。
对视图的操作和对一般表的操作一样。
视图具备如下益处:
- 简化简单的 SQL 操作,比方简单的连贯;
- 只应用理论表的一部分数据;
- 通过只给用户拜访视图的权限,保证数据的安全性;
- 更改数据格式和示意。
CREATE VIEW myview AS
SELECT Concat(col1, col2) AS concat_col, col3*col4 AS compute_col
FROM mytable
WHERE col5 = val;
存储过程
存储过程能够看成是对一系列 SQL 操作的批处理。
应用存储过程的益处:
- 代码封装,保障了肯定的安全性;
- 代码复用;
- 因为是事后编译,因而具备很高的性能。
命令行中创立存储过程须要自定义分隔符,因为命令行是以 ; 为结束符,而存储过程中也蕴含了分号,因而会谬误把这部分分号当成是结束符,造成语法错误。
蕴含 in、out 和 inout 三种参数。
给变量赋值都须要用 select into 语句。
每次只能给一个变量赋值,不反对汇合的操作。
delimiter //
create procedure myprocedure(out ret int)
begin
declare y int;
select sum(col1)
from mytable
into y;
select y*y into ret;
end //
delimiter ;
call myprocedure(@ret);
select @ret;
游标
在存储过程中应用游标能够对一个后果集进行挪动遍历。
游标次要用于交互式利用,其中用户须要对数据集中的任意行进行浏览和批改。
应用游标的四个步骤:
- 申明游标,这个过程没有理论检索出数据;
- 关上游标;
- 取出数据;
- 敞开游标;
delimiter //
create procedure myprocedure(out ret int)
begin
declare done boolean default 0;
declare mycursor cursor for
select col1 from mytable;
# 定义了一个 continue handler,当 sqlstate '02000' 这个条件呈现时,会执行 set done = 1
declare continue handler for sqlstate '02000' set done = 1;
open mycursor;
repeat
fetch mycursor into ret;
select ret;
until done end repeat;
close mycursor;
end //
delimiter ;
触发器
触发器会在某个表执行以下语句时而主动执行: DELETE、INSERT、UPDATE。
触发器必须指定在语句执行之前还是之后主动执行,之前执行应用 BEFORE 关键字,之后执行应用 AFTER 关键字。BEFORE 用于数据验证和污染,AFTER 用于审计跟踪,将批改记录到另外一张表中。
INSERT 触发器蕴含一个名为 NEW 的虚构表。
CREATE TRIGGER mytrigger AFTER INSERT ON mytable
FOR EACH ROW SELECT NEW.col into @result;
SELECT @result; -- 获取后果
DELETE 触发器蕴含一个名为 OLD 的虚构表,并且是只读的。
UPDATE 触发器蕴含一个名为 NEW 和一个名为 OLD 的虚构表,其中 NEW 是能够被批改的,而 OLD 是只读的。
MySQL 不容许在触发器中应用 CALL 语句,也就是不能调用存储过程。
事务管理
根本术语:
- 事务 (transaction) 指一组 SQL 语句;
- 回退 (rollback) 指撤销指定 SQL 语句的过程;
- 提交 (commit) 指将未存储的 SQL 语句后果写入数据库表;
- 保留点 (savepoint) 指事务处理中设置的长期占位符(placeholder),你能够对它公布回退(与回退整个事务处理不同)。
不能回退 SELECT 语句,回退 SELECT 语句也没意义;也不能回退 CREATE 和 DROP 语句。
MySQL 的事务提交默认是隐式提交,每执行一条语句就把这条语句当成一个事务而后进行提交。当呈现 START TRANSACTION 语句时,会敞开隐式提交;当 COMMIT 或 ROLLBACK 语句执行后,事务会主动敞开,从新复原隐式提交。
通过设置 autocommit 为 0 能够勾销主动提交;autocommit 标记是针对每个连贯而不是针对服务器的。
如果没有设置保留点,ROLLBACK 会回退到 START TRANSACTION 语句处;如果设置了保留点,并且在 ROLLBACK 中指定该保留点,则会回退到该保留点。
START TRANSACTION
// ...
SAVEPOINT delete1
// ...
ROLLBACK TO delete1
// ...
COMMIT
字符集
根本术语:
- 字符集为字母和符号的汇合;
- 编码为某个字符集成员的外部示意;
- 校对字符指定如何比拟,次要用于排序和分组。
除了给表指定字符集和校对外,也能够给列指定:
CREATE TABLE mytable
(col VARCHAR(10) CHARACTER SET latin COLLATE latin1_general_ci )
DEFAULT CHARACTER SET hebrew COLLATE hebrew_general_ci;
能够在排序、分组时指定校对:
SELECT *
FROM mytable
ORDER BY col COLLATE latin1_general_ci;
权限治理
MySQL 的账户信息保留在 mysql 这个数据库中。
USE mysql;
SELECT user FROM user;
创立账户
新创建的账户没有任何权限。
CREATE USER myuser IDENTIFIED BY 'mypassword';
批改账户名
RENAME myuser TO newuser;
删除账户
DROP USER myuser;
查看权限
SHOW GRANTS FOR myuser;
授予权限
账户用 username@host 的模式定义,username@% 应用的是默认主机名。
GRANT SELECT, INSERT ON mydatabase.* TO myuser;
删除权限
GRANT 和 REVOKE 可在几个档次上管制拜访权限:
- 整个服务器,应用 GRANT ALL 和 REVOKE ALL;
- 整个数据库,应用 ON database.*;
- 特定的表,应用 ON database.table;
- 特定的列;
- 特定的存储过程。
REVOKE SELECT, INSERT ON mydatabase.* FROM myuser;
更改明码
必须应用 Password() 函数
SET PASSWROD FOR myuser = Password('new_password');
SQL 语句练习
在上文学习了 SQL 的根本语法当前,本文将通过最经典的“老师 - 学生 - 问题”表来帮忙你练习 SQL。
构建如下表构造
还有一个 Grade 表,在如下的练习中体现
插入数据
上面表 SQL 和相干测试数据是我 Dump 进去的
-- MySQL dump 10.13 Distrib 5.7.17, for macos10.12 (x86_64)
--
-- Host: localhost Database: learn_sql_pdai_tech
-- ------------------------------------------------------
-- Server version 5.7.28
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Table structure for table `COURSE`
--
DROP TABLE IF EXISTS `COURSE`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `COURSE` (`CNO` varchar(5) NOT NULL,
`CNAME` varchar(10) NOT NULL,
`TNO` varchar(10) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `COURSE`
--
LOCK TABLES `COURSE` WRITE;
/*!40000 ALTER TABLE `COURSE` DISABLE KEYS */;
INSERT INTO `COURSE` VALUES ('3-105','计算机导论','825'),('3-245','操作系统','804'),('6-166','数据电路','856'),('9-888','高等数学','100');
/*!40000 ALTER TABLE `COURSE` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `SCORE`
--
DROP TABLE IF EXISTS `SCORE`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `SCORE` (`SNO` varchar(3) NOT NULL,
`CNO` varchar(5) NOT NULL,
`DEGREE` decimal(10,1) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `SCORE`
--
LOCK TABLES `SCORE` WRITE;
/*!40000 ALTER TABLE `SCORE` DISABLE KEYS */;
INSERT INTO `SCORE` VALUES ('103','3-245',86.0),('105','3-245',75.0),('109','3-245',68.0),('103','3-105',92.0),('105','3-105',88.0),('109','3-105',76.0),('101','3-105',64.0),('107','3-105',91.0),('101','6-166',85.0),('107','6-106',79.0),('108','3-105',78.0),('108','6-166',81.0);
/*!40000 ALTER TABLE `SCORE` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `STUDENT`
--
DROP TABLE IF EXISTS `STUDENT`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `STUDENT` (`SNO` varchar(3) NOT NULL,
`SNAME` varchar(4) NOT NULL,
`SSEX` varchar(2) NOT NULL,
`SBIRTHDAY` datetime DEFAULT NULL,
`CLASS` varchar(5) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `STUDENT`
--
LOCK TABLES `STUDENT` WRITE;
/*!40000 ALTER TABLE `STUDENT` DISABLE KEYS */;
INSERT INTO `STUDENT` VALUES ('108','曾华','男','1977-09-01 00:00:00','95033'),('105','匡明','男','1975-10-02 00:00:00','95031'),('107','王丽','女','1976-01-23 00:00:00','95033'),('101','李军','男','1976-02-20 00:00:00','95033'),('109','王芳','女','1975-02-10 00:00:00','95031'),('103','陆君','男','1974-06-03 00:00:00','95031');
/*!40000 ALTER TABLE `STUDENT` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `TEACHER`
--
DROP TABLE IF EXISTS `TEACHER`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `TEACHER` (`TNO` varchar(3) NOT NULL,
`TNAME` varchar(4) NOT NULL,
`TSEX` varchar(2) NOT NULL,
`TBIRTHDAY` datetime NOT NULL,
`PROF` varchar(6) DEFAULT NULL,
`DEPART` varchar(10) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `TEACHER`
--
LOCK TABLES `TEACHER` WRITE;
/*!40000 ALTER TABLE `TEACHER` DISABLE KEYS */;
INSERT INTO `TEACHER` VALUES ('804','李诚','男','1958-12-02 00:00:00','副教授','计算机系'),('856','张旭','男','1969-03-12 00:00:00','讲师','电子工程系'),('825','王萍','女','1972-05-05 00:00:00','助教','计算机系'),('831','刘冰','女','1977-08-14 00:00:00','助教','电子工程系');
/*!40000 ALTER TABLE `TEACHER` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2020-02-06 18:18:25
相干练习
- 1、查问 Student 表中的所有记录的 Sname、Ssex 和 Class 列。
select SNAME, SSEX, CLASS from STUDENT;
- 2、查问老师所有的单位即不反复的 Depart 列。
select distinct DEPART from TEACHER;
- 3、查问 Student 表的所有记录。
select * from STUDENT;
- 4、查问 Score 表中问题在 60 到 80 之间的所有记录。
select *
from SCORE
where DEGREE > 60 and DEGREE < 80;
- 5、查问 Score 表中问题为 85,86 或 88 的记录。
select *
from SCORE
where DEGREE = 85 or DEGREE = 86 or DEGREE = 88;
- 6、查问 Student 表中“95031”班或性别为“女”的同学记录。
select *
from STUDENT
where CLASS = '95031' or SSEX = '女';
- 7、以 Class 降序查问 Student 表的所有记录。
select *
from STUDENT
order by CLASS desc;
- 8、以 Cno 升序、Degree 降序查问 Score 表的所有记录。
select *
from SCORE
order by CNO asc, DEGREE desc;
- 9、查问“95031”班的学生人数。
select count(*)
from STUDENT
where CLASS = '95031';
- 10、查问 Score 表中的最高分的学生学号和课程号。
select
sno,
CNO
from SCORE
where DEGREE = (select max(DEGREE)
from SCORE
);
- 11、查问‘3-105’号课程的平均分。
select avg(DEGREE)
from SCORE
where CNO = '3-105';
- 12、查问 Score 表中至多有 5 名学生选修的并以 3 结尾的课程的均匀分数。
select
avg(DEGREE),
CNO
from SCORE
where cno like '3%'
group by CNO
having count(*) > 5;
- 13、查问最低分大于 70,最高分小于 90 的 Sno 列。
select SNO
from SCORE
group by SNO
having min(DEGREE) > 70 and max(DEGREE) < 90;
- 14、查问所有学生的 Sname、Cno 和 Degree 列。
select
SNAME,
CNO,
DEGREE
from STUDENT, SCORE
where STUDENT.SNO = SCORE.SNO;
- 15、查问所有学生的 Sno、Cno 和 Degree 列。
select
SCORE.SNO,
CNO,
DEGREE
from STUDENT, SCORE
where STUDENT.SNO = SCORE.SNO;
- 16、查问所有学生的 Sname、Cname 和 Degree 列。
SELECT
A.SNAME,
B.CNAME,
C.DEGREE
FROM STUDENT A
JOIN (COURSE B, SCORE C)
ON A.SNO = C.SNO AND B.CNO = C.CNO;
- 17、查问“95033”班所选课程的平均分。
select avg(DEGREE)
from SCORE
where sno in (select SNO
from STUDENT
where CLASS = '95033');
- 18、假如应用如下命令建设了一个 grade 表:
create table grade (low numeric(3, 0),
upp numeric(3),
rank char(1)
);
insert into grade values (90, 100, 'A');
insert into grade values (80, 89, 'B');
insert into grade values (70, 79, 'C');
insert into grade values (60, 69, 'D');
insert into grade values (0, 59, 'E');
- 现查问所有同学的 Sno、Cno 和 rank 列。
SELECT
A.SNO,
A.CNO,
B.RANK
FROM SCORE A, grade B
WHERE A.DEGREE BETWEEN B.LOW AND B.UPP
ORDER BY RANK;
- 19、查问选修“3-105”课程的问题高于“109”号同学问题的所有同学的记录。
select *
from SCORE
where CNO = '3-105' and DEGREE > ALL (
select DEGREE
from SCORE
where SNO = '109'
);
- 20、查问 score 中选学一门以上课程的同学中分数为非最高分问题的学生记录
select * from STUDENT where SNO
in (select SNO
from SCORE
where DEGREE < (select MAX(DEGREE) from SCORE)
group by SNO
having count(*) > 1);
- 21、查问问题高于学号为“109”、课程号为“3-105”的问题的所有记录。
select *
from SCORE
where CNO = '3-105' and DEGREE > ALL (
select DEGREE
from SCORE
where SNO = '109'
);
- 22、查问和学号为 108 的同学同年出世的所有学生的 Sno、Sname 和 Sbirthday 列。
select
SNO,
SNAME,
SBIRTHDAY
from STUDENT
where year(SBIRTHDAY) = (select year(SBIRTHDAY)
from STUDENT
where SNO = '108'
);
- 23、查问“张旭“老师任课的学生问题。
select *
from SCORE
where cno = (
select CNO
from COURSE
inner join TEACHER on COURSE.TNO = TEACHER.TNO and TNAME = '张旭'
);
- 24、查问选修某课程的同学人数多于 5 人的老师姓名。
select TNAME
from TEACHER
where TNO = (
select TNO
from COURSE
where CNO = (select CNO
from SCORE
group by CNO
having count(SNO) > 5)
);
- 25、查问 95033 班和 95031 班全体学生的记录。
select *
from STUDENT
where CLASS in ('95033', '95031');
- 26、查问存在有 85 分以上问题的课程 Cno.
select cno
from SCORE
group by CNO
having MAX(DEGREE) > 85;
- 27、查问出“计算机系“老师所教课程的成绩表。
select *
from SCORE
where CNO in (select CNO
from TEACHER, COURSE
where DEPART = '计算机系' and COURSE.TNO = TEACHER.TNO);
- 28、查问“计算机系”与“电子工程系“不同职称的老师的 Tname 和 Prof
select
tname,
prof
from TEACHER
where depart = '计算机系' and prof not in (
select prof
from TEACHER
where depart = '电子工程系'
);
- 29、查问选修编号为“3-105“课程且问题至多高于选修编号为“3-245”的同学的 Cno、Sno 和 Degree, 并按 Degree 从高到低秩序排序。
select
CNO,
SNO,
DEGREE
from SCORE
where CNO = '3-105' and DEGREE > any (
select DEGREE
from SCORE
where CNO = '3-245'
)
order by DEGREE desc;
- 30、查问选修编号为“3-105”且问题高于选修编号为“3-245”课程的同学的 Cno、Sno 和 Degree.
SELECT *
FROM SCORE
WHERE CNO = '3-105' AND DEGREE > ALL (
SELECT DEGREE
FROM SCORE
WHERE CNO = '3-245'
)
ORDER by DEGREE desc;
- 31、查问所有老师和同学的 name、sex 和 birthday.
select
TNAME name,
TSEX sex,
TBIRTHDAY birthday
from TEACHER
union
select
sname name,
SSEX sex,
SBIRTHDAY birthday
from STUDENT;
- 32、查问所有“女”老师和“女”同学的 name、sex 和 birthday.
select
TNAME name,
TSEX sex,
TBIRTHDAY birthday
from TEACHER
where TSEX = '女'
union
select
sname name,
SSEX sex,
SBIRTHDAY birthday
from STUDENT
where SSEX = '女';
- 33、查问问题比该课程均匀问题低的同学的成绩表。
SELECT A.*
FROM SCORE A
WHERE DEGREE < (SELECT AVG(DEGREE)
FROM SCORE B
WHERE A.CNO = B.CNO);
- 34、查问所有任课教师的 Tname 和 Depart.
select
TNAME,
DEPART
from TEACHER a
where exists(select *
from COURSE b
where a.TNO = b.TNO);
- 35、查问所有未讲课的老师的 Tname 和 Depart.
select
TNAME,
DEPART
from TEACHER a
where tno not in (select tno
from COURSE);
- 36、查问至多有 2 名男生的班号。
select CLASS
from STUDENT
where SSEX = '男'
group by CLASS
having count(SSEX) > 1;
- 37、查问 Student 表中不姓“王”的同学记录。
select *
from STUDENT
where SNAME not like "王 %";
- 38、查问 Student 表中每个学生的姓名和年龄。
select
SNAME,
year(now()) - year(SBIRTHDAY)
from STUDENT;
- 39、查问 Student 表中最大和最小的 Sbirthday 日期值。
select min(SBIRTHDAY) birthday
from STUDENT
union
select max(SBIRTHDAY) birthday
from STUDENT;
- 40、以班号和年龄从大到小的程序查问 Student 表中的全副记录。
select *
from STUDENT
order by CLASS desc, year(now()) - year(SBIRTHDAY) desc;
- 41、查问“男”老师及其所上的课程。
select *
from TEACHER, COURSE
where TSEX = '男' and COURSE.TNO = TEACHER.TNO;
- 42、查问最高分同学的 Sno、Cno 和 Degree 列。
select
sno,
CNO,
DEGREE
from SCORE
where DEGREE = (select max(DEGREE)
from SCORE);
- 43、查问和“李军”同性别的所有同学的 Sname.
select sname
from STUDENT
where SSEX = (select SSEX
from STUDENT
where SNAME = '李军');
- 44、查问和“李军”同性别并同班的同学 Sname.
select sname
from STUDENT
where (SSEX, CLASS) = (select
SSEX,
CLASS
from STUDENT
where SNAME = '李军');
- 45、查问所有选修“计算机导论”课程的“男”同学的成绩表
select *
from SCORE, STUDENT
where SCORE.SNO = STUDENT.SNO and SSEX = '男' and CNO = (
select CNO
from COURSE
where CNAME = '计算机导论');
- 46、应用游标形式来同时查问每位同学的名字,他所选课程及问题。
declare
cursor student_cursor is
select S.SNO,S.SNAME,C.CNAME,SC.DEGREE as DEGREE
from STUDENT S, COURSE C, SCORE SC
where S.SNO=SC.SNO
and SC.CNO=C.CNO;
student_row student_cursor%ROWTYPE;
begin
open student_cursor;
loop
fetch student_cursor INTO student_row;
exit when student_cursor%NOTFOUND;
dbms_output.put_line( student_row.SNO || '' ||
student_row.SNAME|| ''|| student_row.CNAME ||'' ||
student_row.DEGREE);
end loop;
close student_cursor;
END;
/
- 47、申明触发器指令,每当有同学转换班级时执行触发器显示以后和之前所在班级。
CREATE OR REPLACE TRIGGER display_class_changes
AFTER DELETE OR INSERT OR UPDATE ON student
FOR EACH ROW
WHEN (NEW.sno > 0)
BEGIN
dbms_output.put_line('Old class:' || :OLD.class);
dbms_output.put_line('New class:' || :NEW.class);
END;
/
Update student
set class=95031
where sno=109;
- 48、删除已设置的触发器指令
DROP TRIGGER display_class_changes;
SQL 语句优化
负向查问不能应用索引
select name from user where id not in (1,3,4);
应该批改为:
select name from user where id in (2,5,6);
前导含糊查问不能应用索引
如:
select name from user where name like '%zhangsan'
非前导则能够:
select name from user where name like 'zhangsan%'
倡议能够思考应用 Lucene
等全文索引工具来代替频繁的含糊查问。
数据辨别不显著的不倡议创立索引
如 user 表中的性别字段,能够显著辨别的才倡议创立索引,如身份证等字段。
字段的默认值不要为 null
这样会带来和预期不统一的查问后果。
在字段上进行计算不能命中索引
select name from user where FROM_UNIXTIME(create_time) < CURDATE();
应该批改为:
select name from user where create_time < FROM_UNIXTIME(CURDATE());
最左前缀问题
如果给 user 表中的 username pwd 字段创立了复合索引那么应用以下 SQL 都是能够命中索引:
select username from user where username='zhangsan' and pwd ='axsedf1sd'
select username from user where pwd ='axsedf1sd' and username='zhangsan'
select username from user where username='zhangsan'
然而应用
select username from user where pwd ='axsedf1sd'
是不能命中索引的。
如果明确晓得只有一条记录返回
select name from user where username='zhangsan' limit 1
能够提高效率,能够让数据库进行游标挪动。
不要让数据库帮咱们做强制类型转换
select name from user where telno=18722222222
这样尽管能够查出数据,然而会导致全表扫描。
须要批改为
select name from user where telno='18722222222'
如果须要进行 join 的字段两表的字段类型要雷同
不然也不会命中索引。