简单范例: select * from courses where name = “李明”;
上面这句sql的作用就是查询courses表中姓名为李明的人的所有信息(未关联表的情况下的信息)
注意所有的sql语句以分号;
结束
注意下面的
这个我查询的文档:原文链接:http://c.biancheng.net/view/7178.html
简单总结就是:
至于另外的视图名,数据库名,表名要根据使用的系统来进行具体的情况划分,详情点开上面的链接
下面这些语句都是等价的:
SELECT name FROM student ;
SELECT NAME FROM student ;
SELECT nAmE FROM student ;
select name from student ;
select "Hello SQL!";
直接将要打印的内容写在sql语句的引号中就是要打印的字符串
select name,student from courses
从courses表中查询name 和 student 两列
where name ="李明"
其中where的操作符有 等于= 大于> 小于< 不等于!=或<>
注意没有 == 这个符号
这个distict的采用例题的方式更容易让人明白
比如:查询如下所示的teacher表中所有的国籍
如果直接写为select country from teacher
那么查询到的结果将会显示为表最后一列:
如若查询的sql语句改为:select DISTINCT country from teacher
那么它就会自动去重 得到的结果为
这种去重的查询在对确定有哪些地方,哪些人,需要考虑重复的情况下比较有效
作用就是向表中添加新的数据
INSERT INTO `table_name` VALUES (value1, value2, value3,...);
INSERT INTO courses
VALUES (13, "Python", 400, "2021-05-23", 3);
需要注意的是设计的表中对应的integer类型的valuen可直接写整数,其他字符类型 如String类型 要写成""或者‘’
括起来的形式
INSERT INTO `table_name` (`column1`, `column2`, `column3`,...) VALUES (value1, value2, value3,...);
INSERT INTO teachers (name,email,age,country)
values ("XiaoFu","[email protected]",20,"CN");
插入的效果(第一列为自增列可不用插入数据,数据库自己增加序列):
注意:不管是哪种插入方式它都不能插入一个不存在的列
插入语句的语法:
UPDATE `table_name`
SET `column1`=value1,`column2`=value2,...
WHERE `some_column`=some_value;
where一般作为筛选条件,可根据筛选条件具体判定是哪一列的数据
例如:修改课程表courses选择Artificial Intelligence的人数为500(若表中没有这个名称的课程那么表不会被修改)
update courses
set student_count = 500
where name = "Artificial Intelligence";
标准格式删除某一行的数据(通过where来进行筛选):
DELETE FROM `table_name`
WHERE `some_column` = `some_value`;
例如:删除courses表中2020年之前所有的信息
delete from courses
where created_at < "2020-1-1";
若是不加where的判定条件,直接执行delete from courses
后将会清空这个表的数据
注意删除表的定义和整个表采用的是 drop table_name
其中关于删除表,删除表中数据,参考这个网站或百度(关于drop,truncate和delete对数据库表的相关操作):https://www.cnblogs.com/1312mn/p/4422396.html
< > = <>或!= >= <=
大于,小于,等于,不等于(<>或!=),大于等于,小于等于
WHERE A operator B
如:where age > 20
或where name = "小张
当b是字符串时记得用引号括起来
例如:查询teachers表中所有的国籍为中国的姓名
select name from teachers
where country = "CN"
WHERE condition1 AND condition2;
SELECT * FROM courses
WHERE teacher_id = 4 and student_count > 500;
SELECT * FROM courses
WHERE name = 'Web' or name = 'Big Data';
SELECT *
FROM courses
WHERE not teacher_id = 3 and student_count > 800
SELECT *
FROM `table_name`
WHERE `column_name` IN `value`;
可用于查询多条件 value 可以是一个集合,也可嵌套一个sql的查询语句得到的集合
例如:查询课程表 courses 中开课日期为 2021-01-01 或者 2021-01-03 的所有课程信息
SELECT * FROM courses
WHERE created_at in ('2021-01-01','2021-01-03');
语法:
SELECT *
FROM `table_name`
WHERE `column_name` NOT IN value;
例如:查询课程表 courses 中所有教师 id teacher_id 不为 1 或 3 的所有课程名称
SELECT name FROM courses
WHERE teacher_id not in (1,3);
语法:
SELECT *
FROM `table_name`
WHERE `column_name` BETWEEN `value` AND `value`;
例如:查询课程表 courses 中学生数量在 50 到 55 之间的所有课程信息
SELECT * from courses
where student_count BETWEEN 50 and 55;
例如:查询教师表 teachers 中,国籍为 ‘CN’ 或 ‘JP’ 且 email 信息不为空的所有教师信息
SELECT * FROM teachers
WHERE country in ('CN','JP') and email is not NULL;
语法:
SELECT *
FROM `table_name`
WHERE `column_name` LIKE `value`;
例如:查询教师表 teachers 中,所有使用 qq 邮箱的教师名字和邮箱
SELECT name,email FROM teachers
WHERE email like '%@qq.com'
上面的这个%就代表了前面有0个或多个字符,最后以@qq.com结尾,有点类似于python中的正则表达式
语法:
SELECT `column_name`, `column_name`
FROM `table_name`
ORDER BY `column_name`, `column_name` ASC|DESC;
例如:查询教师表 teachers 中的中国教师,并按照年龄降序排序
SELECT * FROM teachers
WHERE country = 'CN'
order by age DESC
语法:
SELECT `column_name`, `column_name`
FROM `table_name`
LIMIT `offset` , `count`;
例如:从教师表(teachers)中查询一条年龄最大的中国教师的信息
SELECT * FROM teachers
WHERE country = 'CN'
order by age DESC
limit 1;
语法:
SELECT AVG(`student_count`) AS `average_student_count`
FROM `courses`;
as 后面的是给计算的结果这个新的列去的一个名字
例如:查询教师表 teachers 中教师邮箱为 ‘@qq.com’ 结尾的年龄的平均值,最后返回结果列名显示为 ‘average_teacher_age’ 。
SELECT avg(age) as average_teacher_age FROM teachers
WHERE email like '%@qq.com';
语法:
SELECT MAX(`column_name`)
FROM `table_name`;
例如:从教师表 teachers 中,查询最年长的中国教师信息,并返回该教师的年龄。
SELECT MAX(age) as max_age from teachers
WHERE country = 'CN'
MIN() 函数
用于返回指定列中的最小值 与MAX相同 就不特此举例了
SUM() 函数
用于统计数值列的总数并返回其值
语法:
SELECT SUM(`column_name`)
FROM `table_name`;
例如:统计课程表 courses 中 teacher_id 为 3 的教师所教授的学生总数,并用select_student_sum 作为结果集列名。
SELECT SUM(student_count) as select_student_sum FROM courses
WHERE teacher_id = 3
语法:
SELECT ROUND(`column_name`, `decimals`)
FROM `table_name`;
例如:查询教师表 teachers 中,20 岁(不包含 20 岁)以上教师的平均年龄,返回的字段为 avg_teacher_age ,结果保留四舍五入后的整数
SELECT ROUND(AVG(age)) as avg_teacher_age FROM teachers
where age > 20;
SELECT ISNULL(`column_name`)
FROM `table_name`;
如果 column_name 列中的某个字段是 NULL 则返回 1,不是则返回 0
SELECT IFNULL(`column_name`, `value`)
FROM `table_name`;
如果 column_name 列中的某个字段是 NULL 则返回 value 值,不是则返回对应内容。
COALESCE(column_name, value) 函数也用于判断字段是否为NULL,其用法和 IFNULL() 相同
例如:从 teachers 表中找出没有邮箱并且年龄大于20岁的教师信息
SELECT * FROM teachers
WHERE isnull(email) and age > 20
isnull函数的返回值可用于判断条件
count() 函数
例如:统计教师表中年龄在 20 到 28 岁之间,且国籍为中国或英国的教师人数,最后返回统计值,结果列名显示为 teacher_count
SELECT COUNT(*) AS teacher_count
FROM teachers
WHERE age between 20 and 28 and country in ('CN','UK')
注意: COUNT(column_name) 与 COUNT(*) 的区别
COUNT(column_name) 中,如果 column_name 字段中的值为 NULL,则计数不会增加,而如果字段值为空字符串"",则字段值会加 1
COUNT() 中,除非整个记录全为 NULL,则计数不会增加,如果存在某一个记录不为 NULL,或者为空字符串"",计数值都会加 1。正常来说,表都会有主键,而主键不为空,所以 COUNT() 在有主键的表中等同于 COUNT(PRIMARY_KEY),即查询有多少条记录。
例如:统计课程表 courses 中不同的教师 id teacher_id 的数量,最后返回统计值,结果列名显示为 teacher_count
SELECT COUNT(DISTINCT teacher_id) as teacher_count
FROM courses
相当于统计有多少个teacher_id (有多少个教师)
在使用 NOW() 和 CURTIME() 时,如果要精确的秒以后的时间的话,
可以在()中加数字,加多少,就表示精确到秒后多少位
比如 NOW(3) 就是精确到毫秒,表示为: 2021-03-31 15:27:20.645
例如:向记录表 records 中插入当前的日期
INSERT INTO records
VALUES(CURDATE())
例如:查询课程表中课程的创建日期
SELECT `name`,DATE(`created_at`) AS `created_date`
FROM `courses`;
得到结果:
例如2:分别查询出课程表的课程创建时间中的日期与时间
SELECT `name`, `created_at`,
DATE_FORMAT(DATE(`created_at`),"%Y-%m-%d") AS `created_date`,
DATE_FORMAT(TIME(`created_at`),"%H:%i:%s") AS `created_time`
FROM `courses`;
语法:
SELECT EXTRACT(unit FROM date)
FROM `table`
date 参数是合法的日期表达式。
unit 参数是需要返回的时间部分,如 YEAR 、MONTH 、 DAY 、 HOUR 、MINUTE 、SECOND 等。
例如:从课程表 courses 中查询所有课程的课程名称( name )和课程创建时间( created_at )的小时数,将提取小时数的列名起别名为 created_hour。
SELECT name,EXTRACT(hour FROM created_at) as created_hour
FROM courses
语法:
SELECT DATE_FORMAT(date,format);
其中
date 一个有效日期。
format 是 date/time 的输出格式。 其中 %m 表示月份,%d 表示日期,%Y 表示年份,%w 表示星期。
关于format的格式要求:参考
%i、%l(小写L)、%I(大写i)每一个所表示的格式都不同,参考上面的这个链接
例如:查询 courses 表,查询课程创建时间,按照 ’年-月-日 时:分:秒’ 的格式返回结果,返回列名显示为 DATE_FORMAT
SELECT DATE_FORMAT(created_at,'%Y-%m-%d %H:%i:%S') AS DATE_FORMAT FROM courses
语法:
SELECT DATE_ADD(date, INTERVAL expr type)
FROM table_name
date 指代希望被操作的有效日期,为起始日期
expr 是希望添加的时间间隔的数值(expr 是一个字符串,对于负值的间隔,可以以 ”-“ 开头)
type 是具体的数据类型,表示加上时间间隔的单位(可以是 MICROSECOND , SECOND , MINUTE , HOUR , DAY , WEEK , MONTH , QUARTER , YEAR 等)
例如:修改 courses 表中课程的课程创建日期,将课程创建日期均推迟一天,最后返回课程名称 name 及修改后的课程创建时间,修改后的课程创建时间命名为 new_created
SELECT name, DATE_ADD(created_at, INTERVAL 1 day) as new_created
FROM courses
语法:
SELECT DATE_SUB(date, INTERVAL expr type)
FROM table_name
expr和type与上面DATE_ADD()函数相同
注意:date_add 本身为加,expr为负数时,为减,date_SUB 本身为减,expr为负数时,为加
语法:
SELECT DATEDIFF(时间1,时间2) AS date_diff FROM courses;
DATEDIFF() 差值计算规则:时间 1 - 时间 2
例如:查询 courses 表,计算从 2019 年 03 月 26 日到创建时间(created_at)相差的天数,结果列名以 date_diff 显示
select DATEDIFF(created_at,'2019-03-26') AS date_diff from courses
语法:
SELECT TIMESTAMPDIFF (类型,时间1,时间2) AS year_diff;
TIMESTAMPDIFF() 差值计算规则:时间 2 - 时间 1
例如:查询 courses 表,计算课程创建时间与 ‘2020-04-22’ 的月数差,返回列名显示为 MonthDiff
select TIMESTAMPDIFF(month,created_at,'2020-04-22') as MonthDiff from courses
注意两个时间相减的方向
在 SQL 中,约束是规定表中的数据规则。若存在违反约束的行为,行为就会阻止。它能帮助管理员更好地管理数据库,并且确保数据库中数据的正确性和有效性。例如在后台的数据库设计中对要输入的数据进行核查或判断,再决定是否写入数据库,这都是约束的应用。
例如:
CREATE TABLE `Persons` (
`ID` int NOT NULL,
`LastName` varchar(255) NOT NULL,
`FirstName` varchar(255) NOT NULL,
`Age` int
);
在一个已创建的表的 Age 字段中添加 NOT NULL 约束如下所示:
ALTER TABLE `Persons`
MODIFY `Age` int NOT NULL;
在一个已创建的表的 Age 字段中删除 NOT NULL 约束如下所示:
ALTER TABLE `Persons`
MODIFY `Age` int NULL;
注意
不要把 NULL 值与空串相混淆。NULL 值是没有值,
它不是空串。如果指定’ '(两个单引号,其间没有字符),这在 NOT NULL 列中是允许的。空串是一个有效的值,它不是无值。NULL 值用关键字 NULL 而不是空串指定
create table的时候 unique的约束创建
下面的 SQL 在 Persons 表创建时在 P_Id 列上创建 UNIQUE 约束:
MYSQL中:
CREATE TABLE `Persons`
(
`P_Id` int NOT NULL,
`LastName` varchar(255) NOT NULL,
`FirstName` varchar(255),
`Address` varchar(255),
`City` varchar(255),
UNIQUE (`P_Id`)
)
SQL Server / Oracle / MS Access中:
CREATE TABLE `Persons`
(
`P_Id` int NOT NULL UNIQUE,
`LastName` varchar(255) NOT NULL,
`FirstName` varchar(255),
`Address` varchar(255),
`City` varchar(255)
)
命名 UNIQUE 约束,并定义多个列的 UNIQUE 约束:
MYSQL / SQL Server / Oracle / MS Access 所有都是:
CREATE TABLE `Persons`
(
`P_Id` int NOT NULL,
`LastName` varchar(255) NOT NULL,
`FirstName` varchar(255),
`Address` varchar(255),
`City` varchar(255),
CONSTRAINT uc_PersonID UNIQUE (`P_Id`,`LastName`)
)
ALTER TABLE 时的 UNIQUE 约束:
当表已被创建时,在 P_Id 列创建 UNIQUE 约束:
MySQL / SQL Server / Oracle / MS Access中,增加约束:
ALTER TABLE `Persons`
ADD UNIQUE(`P_Id`)
例如:当表已被创建时,需命名 UNIQUE 约束,并定义多个列的 UNIQUE 约束:
MySQL / SQL Server / Oracle / MS Access:
ALTER TABLE `Persons`
ADD CONSTRAINT uc_PersonID UNIQUE (`P_Id`,`LastName`)
constraint 是给取别名
如需撤销 UNIQUE 约束 :
MySQL中:
ALTER TABLE `Persons`
DROP INDEX uc_PersonID
SQL Server / Oracle / MS Access中:
ALTER TABLE `Persons`
DROP CONSTRAINT uc_PersonID
如:
表一:用户 id (主键),用户名
表二: 银行卡号 id (主键),用户 id (外键)
则表一为主表,表二为从表。
CREATE TABLE 时 添加 PRIMARY KEY 约束
下面的 SQL 在 个人信息表 Persons 创建时,在 P_Id 列上添加 PRIMARY KEY 约束:
方式1:
CREATE TABLE `Persons`
(
`P_Id` int NOT NULL,
`LastName` varchar(255) NOT NULL,
`FirstName` varchar(255),
`Address` varchar(255),
`City` varchar(255),
PRIMARY KEY (`P_Id`)
);
方式2:
CREATE TABLE `Persons`
(
`P_Id` int NOT NULL PRIMARY KEY,
`LastName` varchar(255) NOT NULL,
`FirstName` varchar(255),
`Address` varchar(255),
`City` varchar(255)
)
由多个值一起构成主键:
CREATE TABLE `Persons`
(
`P_Id` int NOT NULL,
`LastName` varchar(255) NOT NULL,
`FirstName` varchar(255),
`Address` varchar(255),
`City` varchar(255),
CONSTRAINT pk_PersonID PRIMARY KEY (`P_Id`,`LastName`)
)
在已创建的表中添加主键:
ALTER TABLE `Persons`
ADD CONSTRAINT pk_PersonID PRIMARY KEY (`P_Id`,`LastName`)
注释:
如果您使用 ALTER TABLE 语句添加主键,必须把主键列声明为不包含 NULL 值(在表首次创建时)
撤销主键:
ALTER TABLE `Persons`
DROP PRIMARY KEY
另一种方式(取别名的主键,上一种方法其实也可以去除):
ALTER TABLE `Persons`
DROP CONSTRAINT pk_PersonID
CREATE TABLE 时的 SQL FOREIGN KEY 约束
在 “Orders” 表创建时在 “P_Id” 列上创建 FOREIGN KEY 约束:
CREATE TABLE `Orders`
(
`O_Id` int NOT NULL,
`OrderNo` int NOT NULL,
`P_Id` int,
PRIMARY KEY (O_Id),
FOREIGN KEY (P_Id) REFERENCES Persons(P_Id)
)
写法2:
CREATE TABLE `Orders`
(
`O_Id` int NOT NULL PRIMARY KEY,
`OrderNo` int NOT NULL,
P_Id int FOREIGN KEY REFERENCES Persons(P_Id)
)
其中
NOT NULL 表示该字段不为空
REFERENCES 表示 引用一个表
命名外键约束:
CREATE TABLE `Orders`
(
`O_Id` int NOT NULL,
`OrderNo` int NOT NULL,
`P_Id` int,
PRIMARY KEY (O_Id),
CONSTRAINT fk_PerOrders FOREIGN KEY (P_Id)
REFERENCES Persons(P_Id)
)
其中
CONSTRAINT 表示约束,后面接约束名称,常用于创建约束和删除约束;
添加外键约束:
写法1:
ALTER TABLE `Orders`
ADD FOREIGN KEY (P_Id)
REFERENCES Persons(P_Id)
写法2:
ALTER TABLE `Orders`
ADD CONSTRAINT fk_PerOrders
FOREIGN KEY (P_Id)
REFERENCES Persons(P_Id)
撤销外键约束:
ALTER TABLE `Orders`
DROP FOREIGN KEY fk_PerOrders
check 检查约束
用于限制列中的值的范围,评估插入或修改后的值。满足条件的值将会插入表中,否则将放弃插入操作。 可以为同一列指定多个 CHECK 约束。
CHECK 约束既可以用于某一列也可以用于某张表:
1、如果对单个列定义 CHECK 约束,那么该列只允许特定的值。
2、如果对一个表定义 CHECK 约束,那么此约束会基于行中其他列的值在特定的列中对值进行限制。
定义 CHECK 约束条件在某种程度上类似于编写查询的 WHERE 子句,使用不同的比较运算符(例如 AND、OR、BETWEEN、IN、LIKE 和 IS NULL)编写其布尔表达式,该布尔表达式将返回 TRUE、FALSE 或 UNKNOWN 。 当条件中存在 NULL 值时,CHECK约束将返回 UNKNOWN 值。
在创建课程表 courses 时,给学生总数 student_count 字段加上一个大于 0 的约束:
`id` int,
`name` varchar(255),
`student_count` int,
`created_at` date,
`teacher_id` int,
CHECK (`student_count` > 0)
)
为多个列添加 CHECK 约束:
CREATE TABLE `courses`
(
`id` int,
`name` varchar(255),
`student_count` int,
`created_at` date,
`teacher_id` int,
CHECK (`student_count` > 0 AND `teacher_id` > 0)
)
表已存在时添加 CHECK 约束:
ALTER TABLE `courses`
ADD CHECK ( `student_count` > 0);
撤销 CHECK 约束:
ALTER TABLE `courses`
DROP CHECK chk_courses
语法:
<字段名> <数据类型> DEFAULT <默认值>
CREATE TABLE 时的 DEFAULT 约束:
CREATE TABLE `Persons`
(
`P_Id` int NOT NULL,
`LastName` varchar(255) NOT NULL,
`FirstName` varchar(255),
`Address` varchar(255),
`City` varchar(255) DEFAULT 'Sandnes'
)
ALTER TABLE 时的 DEFAULT 约束:
ALTER TABLE `Persons`
ALTER `City` SET DEFAULT 'SANDNES'
撤销 DEFAULT 约束:
ALTER TABLE `Persons`
ALTER `City` DROP DEFAULT
联结是一种机制,用于在一条 SELECT 语句中关联多个表,返回一组输出。
这个时候就要说一下联结中的两大主角——主键(PRIMARY KEY)和外键(FOREIGN KEY)
JOIN 连接子句
语法:
写法一:
SELECT `table1`.`column1`, `table2`.`column2`...
FROM `table1`
INNER JOIN `table2`
ON `table1`.`common_field` = `table2`.`common_field`;
写法二:
SELECT `table1`.`column1`, `table2`.`column2`...
FROM `table1`
JOIN `table2`
ON `table1`.`common_field` = `table2`.`common_field`;
需要注意的是,联结条件需使用特定的 ON 子句给出。
例如:请编写 SQL 语句,将课程表 courses 和教师表 teachers 进行内连接,查询 “Eastern Heretic” 老师所教的所有课程的课程名和课程编号 , 且结果列名分别以课程编号 id 、课程名称 course_name 和教师姓名 teacher_name 显示。
select c.id,c.name as course_name,t.name as teacher_name
from courses c join teachers t on c.teacher_id = t.id
where t.name = 'Eastern Heretic'
在MySQL中,外连接查询会返回所操作的表中至少一个表的所有数据记录。在MySQL中,数据查询通过SQL语句 “OUTER JOIN…ON” 来实现,外连接查询可以分为以下三类:
左外连接
左外连接的结果包括 LEFT OUTER 子句中指定的左表的所有行,而不仅仅是连接列所匹配的行,这就意味着,左连接会返回左表中的所有记录,加上右表中匹配到的记录。如果左表的某行在右表中没有匹配行,那么在相关联的结果行中,右表的所有选择列表均为空值。
右外连接
外连接查询中的右外连接是指新关系中执行匹配条件时,以关键字 RIGHT JOIN 右边的表为参考表,如果右表的某行在左表中没有匹配行,左表就返回空值。
全外连接
FULL OUTER JOIN 关键字只要左表(table1)和右表(table2)其中一个表中存在匹配,则返回行。FULL OUTER JOIN 关键字结合了 LEFT JOIN 和 RIGHT JOIN 的结果。
mysql不支持全连接(full join),可以使用 left join+ union+right join
(SELECT * from a left JOIN b on a.name=b.id) UNION (SELECT * from a RIGHT JOIN b on a.name=b.id );
查询语法:
SELECT column_name 1,column_name 2 ... column_name n
FROM table1
LEFT | RIGHT | FULL (OUTER) JOIN table2
ON CONDITION;
在上述语句中,参数 column_name 表示所要查询的字段名字,来源于所连接的表 table1 和 table2,关键字 OUTER JOIN 表示表进行外连接,参数 CONDITION 表示进行匹配的条件。
例如1:
请编写 SQL 语句,将教师表 teachers 和课程表 courses 进行左连接,查询来自中国(讲师国籍 country =‘CN’ )的教师名称以及所教课程名称,结果列名请分别以课程名称 course_name ,教师名称 teacher_name 显示。
select c.name as course_name,t.name as teacher_name
from teachers t left join courses c on t.id = c.teacher_id
where country ='CN'
例如2:
请编写 SQL 语句,将课程表 courses 和教师表 teachers 进行右连接,查询来自中国(讲师国籍 country =‘CN’ )的教师姓名,邮箱以及所教课程名称,结果列名请分别以课程名称 course_name ,教师名称 teacher_name ,教师邮箱 teacher_email 显示。
select c.name as course_name,t.name as teacher_name,t.email as teacher_email
from courses c right join teachers t on c.teacher_id = t.id
where country = 'CN'
例如3:
将课程表 courses 和教师表 teachers 进行外连接,查询所有课程名称以及与其相互对应的教师名称和教师国籍,结果列名请分别以课程名称 course_name 、教师名称 teacher_name 、教师国籍 teacher_country 显示。
select c.name as course_name, t.name as teacher_name,t.country as teacher_country
from courses c left join teachers t on c.teacher_id = t.id
union
select c.name as course_name, t.name as teacher_name,t.country as teacher_country
from courses c right join teachers t on c.teacher_id = t.id
与内连接和外连接相比,交叉连接非常简单,因为它不存在 ON 子句
交叉连接:返回左表中的所有行,左表中的每一行与右表中的所有行组合。即将两个表的数据一一对应,其查询结果的行数为左表中的行数乘以右表中的行数。
CROSS JOIN(交叉连接)的结果也称作笛卡尔积
笛卡尔乘积是指在数学中,两个集合 X 和 Y 的笛卡尓积(Cartesian product),又称直积,表示为X × Y,第一个对象是 X 的成员而第二个对象是 Y 的所有可能有序对的其中一个成员。
定义方式:
交叉连接有两种定义方式,分为隐式连接和显式连接。两种定义方式的查询结果是相同的。
隐式交叉连接:不需要使用 CROSS JOIN 关键字,只要在 SELECT 语句的 FROM 语句后将要进行交叉连接的表名列出即可,这种方式基本上可以被任意数据库系统支持。
隐式语法:
SELECT `c`.`name` AS `course_name`, `t`.`name` AS `teacher_name`
FROM `courses` `c`,`teachers` `t`;
显示语法:
SELECT `c`.`name` AS `course_name`, `t`.`name` AS `teacher_name`
FROM `courses` `c`
CROSS JOIN `teachers` `t`;
语法:
SELECT `column_name`, aggregate_function(`column_name`)
FROM `table_name`
WHERE `column_name` operator value
GROUP BY `column_name`;
例如:查询教师表 teachers,统计不同年龄教师的人数,并将结果按照年龄从大到小排列,返回列名显示为 age_count:
select age ,count(age) as age_count
from teachers
group by age
order by age DESC
例如2:查询教师表 teachers 和课程表 courses,统计每个老师教授课程的数量,并将结果按课程数量从大到小排列,如果相同课程数量则按照教师姓名排列,返回列名老师姓名列名显示为 teacher_name ,课程数量列名显示为 course_count:
select t.name as teacher_name,IFNULL(count(c.name),0) as course_count
from courses c right join teachers t on c.teacher_id = t.id
group by teacher_name
order by course_count DESC,teacher_name
我们在使用 WHERE 条件子句时会发现其不能与聚合函数联合使用,为解决这一点,SQL 中提供了 HAVING 子句。在使用时, HAVING 子句经常与 GROUP BY 联合使用,HAVING 子句就是对分组统计函数进行过滤的子句
HAVING 子句对于 GROUP BY 子句设置条件的方式其实与 WHERE 子句与 SELECT 的方式类似,语法也相近,但 WHERE 子句搜索条件是在分组操作之前,而 HAVING 则是在之后
语法:
SELECT `column_name`, aggregate_function(`column_name`)
FROM `table_name`
WHERE `column_name` operator value
GROUP BY `column_name`
HAVING aggregate_function(`column_name`) operator value;
例如:查询 teachers 表中,各个国家所有教师的平均年龄大于所有国家教师的平均年龄的教师信息:
待补充
语法:
SELECT `column_name(s)`
FROM `table_name`
WHERE `column_name` OPERATOR (
SELECT `column_name(s)`
FROM `table_name`
);
1、子查询方法:
select name from teachers
where id = (
select teacher_id from courses
where name = 'Big Data'
)
2、表联结方法:
select t.name from
teachers t join courses c on t.id = c.teacher_id
where c.name = 'Big Data'
对于 INSERT 语句中的子查询来说,首先是使用子查询的 SELECT 语句找到需要插入的数据,之后将返回的数据插入到另一个表中。在子查询中所选择的数据可以用任何字符、日期或数字函数修改:
insert into 插入子查询:
语法:
INSERT INTO `table_name`
SELECT `colnum_name(s)`
FROM `table_name`
[ WHERE VALUE OPERATOR ]
例如:备份teachers表的数据
INSERT INTO `teachers_bkp`
SELECT *
FROM `teachers`;
update 子查询用法:
语法:
UPDATE `table_name`
SET `column_name` = `new_value`
WHERE `column_name` OPERATOR
(SELECT `column_name`
FROM `table_name`
[WHERE] )
DELETE语句的子查询
语法:
DELETE FROM `table_name`
WHERE `column_name` OPERATOR
(SELECT `column_name`
FROM `table_name`
[WHERE] )
例如:删除教师表 teachers 中在 2020 年前(不包括 2020 年)创建过课程的教师
delete from teachers
where id in (
select distinct teacher_id from courses
where created_at < '2020-01-01'
)
范例:现需要查询国籍为美国(USA),且年龄最大的教师,请使用内联视图子查询实现。
SELECT *
FROM (
SELECT *
FROM `teachers`
WHERE `country` = 'USA'
) `T`
WHERE `age` = (
SELECT MAX(`age`)
FROM `teachers`
);
范例:现需要查询国籍为美国(USA)的教师所开的所有课程,请使用 IN 操作符进行多行子查询。
SELECT `name`
FROM `courses`
WHERE `teacher_id` IN (
SELECT `id`
FROM `teachers`
WHERE `country` = 'USA'
);
范例:现需要查询学生上课人数超过 “Eastern Heretic” 的任意一门课的学生人数的课程信息,请使用 ANY 操作符实现多行子查询。
SELECT *
FROM `courses`
WHERE `student_count` > ANY (
SELECT `student_count`
FROM `courses`
WHERE `teacher_id` = (
SELECT `id`
FROM `teachers`
WHERE `name` = 'Eastern Heretic'
)
)
AND `teacher_id` <> (
SELECT `id`
FROM `teachers`
WHERE `name` = 'Eastern Heretic'
);
范例:现需要查询学生人数超过 ”Western Venom“ 所有课程学生人数的课程信息,请使用 ALL 操作符实现多行子查询。
SELECT *
FROM `courses`
WHERE `student_count` > ALL (
SELECT `student_count`
FROM `courses`
WHERE `teacher_id` = (
SELECT `id`
FROM `teachers`
WHERE `name` = 'Western Venom'
)
);
当是多行多列子查询时,主查询语句的条件语句中引用子查询结果时必须用多行比较符号(IN,ANY,ALL 等)来进行比较。
范例:现需要找到每个国家年龄最大的教师,请编写 SQL 语句实现多列子查询
SELECT `name`, `age`, `country`
FROM `teachers`
WHERE (`country`, `age`) IN (
SELECT `country`, MAX(`age`)
FROM `teachers`
GROUP BY `country`
);
当子查询出现在 HAVING 子句中时,像 HAVING 子句中的任何表达式一样,表示要进行分组过滤,它被用作行组选择的一部分,一般返回单行单列的数据
范例:现需要计算每位教师所开课程的平均学生人数与全部课程的平均学生人数,比较其大小,最后返回超过全部课程平均学生人数的教师姓名,请编写相应的 SQL 语句实现。
SELECT `name`
FROM `teachers`
WHERE `id` IN (
SELECT `teacher_id`
FROM `courses`
GROUP BY `teacher_id`
HAVING AVG(`student_count`) > (
SELECT AVG(`student_count`)
FROM `courses`
)
);
描述:请编写 SQL 语句,连接 courses 与 teachers 表,统计不同国籍教师所开课程的学生总数,对于没有任课的老师,学生总人数计为 0 。最后查询教师国籍是 ‘U’ 开头且这个国籍的所有教师的学生总数在 2000 到 5000 之间(包括 2000 和 5000)的教师国籍及学生总数 (别名为 student_count ),结果按照学生总数降序排列,如果学生总数相同,则按照教师国籍升序排列。
两个表字段如下所示:
先在这儿思考一下吧!!!
练习答案:
select country, sum(student_count) student_count
from courses c left join teachers t on c.teacher_id = t.id
where t.id in (
select id from teachers
where country like "U%"
)
group by t.country
having sum(student_count) between 2000 and 5000
order by student_count desc , country asc
MySQL 为我们提供了以下重要语句来控制事务:
默认情况下,MySQL 自动将更改永久性地提交给数据库。要强迫 MySQL 不自动提交更改,你可以使用以下语句:
SET autocommit = 0;
-- OR --
SET autocommit = OFF
锁:计算机协调多个进程或线程并发访问某一资源的机制。
锁的重要性:
在数据库中,除了传统的计算资源(CPU、RAM、I\O等)的争抢,数据也是一种供多用户共享的资源。
因此,如何保证数据并发访问的一致性,有效性,是所有数据库必须要解决的问题。
锁冲突也是影响数据库并发访问性能的一个重要因素,因此锁对数据库尤其重要。
锁的缺点:
加锁是消耗资源的,锁的各种操作,包括:获得锁、检测锁是否已经解除、释放锁等,都会增加系统的开销。
Oracle 数据库的事务隔离级别基本都是读已提交(READ-COMMITTED),所有的锁也针对这个级别来总结
MySQL 默认隔离级别是 Repeatable read(可重复读)
查看自己的数据库的事务隔离级别
命令:
SHOW VARIABLES like '%isolation%';
查询当前数据库的自增锁模式:
show variables like '%innodb_autoinc_lock_mode%';
0:traditonal 每次 insert 语句执行都会产生表锁
1:consecutive simple insert 会获得批量的锁,保证一批插入自增序列的连续性,插入之前提前释放锁,在这个模式下你会发现当你 insert 多条数据回滚的时候虽然 DB 没有插入数据,但是自增 ID 已经增长了,也是数据库默认的级别
2:interleaved 不会锁表,实时插入,并发最高,但是基于主从的复制是不安全的,感兴趣可以去查询 RBR 和 SBR 的优缺点
通过查询知道,我的数据库是开启 consecutive 级别,simple insert 表示通过分析 insert 语句可以确定插入的数量;如:insert, insert, insert … valies(), values(), values();相应的其他插入方式还有 Bulk inserts,Mixed-mode inserts 等。
案例可访问这个页面进行查看:https://www.lintcode.com/learn/84/285
并发控制
提到共享锁和排它锁就不得不提并发控制(Concurrency Control),并发控制可以解决临界资源操作时不一致的情况产生,保证数据一致性常见的手段就是锁和数据多版本(Multi Version)
直接加锁
这种方式会导致被加锁的资源都被锁住,读取任务也无法执行直到锁释放,所有执行的任务相当于串行化方式,简单粗暴,不能并发
共享锁(Shared Locks)简称为 S 锁
读取数据时候可以加 S 锁。
共享 (S) 锁允许并发事务读取 (SELECT) 一个资源。资源上存在共享 (S) 锁时,任何其它事务都不能修改数据。一旦已经读取数据,便立即释放资源上的共享 (S) 锁,除非将事务隔离级别设置为可重复读或更高级别,或者在事务生存周期内用锁定提示保留共享 (S) 锁。
排它 (X) 锁可以防止并发事务对资源进行访问。其它事务不能读取或修改排它 (X) 锁锁定的数据。
共享锁之间可以并行,排它锁和共享锁之间互斥,也就是说只要共享锁开启没有释放掉的时候,更新锁是不能抢占的,此时其他读取同资源的操作可以进行读取不受限制;同理排它锁开启时候只要没有释放其他不管是排它锁还是共享锁都不可以抢占资源直到锁释放。
案例讲解:https://www.lintcode.com/learn/84/292
因为锁是使用可能会引发死锁的状态:
死锁
死锁在本文不详细进行讲解,只列举一些可能会造成死锁的诱因
数据多版本
上面讲到 X 锁占领后其他 S 锁没法占用导致只要写没完成读就不能进行并发查询,InnoDB 引入了数据多版本概念去解决这一问题
核心原理简单讲就是 clone 了一个版本数据进行修改,比如原有的数据版本号是 Version0,这个时候进行写操作 clone 了一份版本号 V1,这个时候对 V1 版本数据进行修改写入操作;与此同时其他查询读任务并发进来一样可以读取 V0 版本数据不受任何影响,这样就解决了在数据更新回写之前不能读取的问题,进一步提高了数据库引擎处理并发的能力
意向锁是一种特殊的表级锁,意向锁是为了让 InnoDB 多粒度的锁能共存而设计的。取得行的共享锁和排他锁之前需要先取得表的意向共享锁(IS)和意向排他锁(IX),意向共享锁和意向排他锁都是系统自动添加和自动释放的,整个过程无需人工干预。
意向锁就是指未来的某一个时刻事务可能要加共享锁或者排它锁,提前声明一个意向,分为两种:
-- 事务要获取某些行的 S 锁,必须先获得表的 IS 锁。
SELECT column FROM table ... LOCK IN SHARE MODE;
-- 事务要获取某些行的 X 锁,必须先获得表的 IX 锁。
SELECT column FROM table ... FOR UPDATE;
另:关于InnoDB锁的种类之临键锁和插入意向锁以及临键锁和插入意向锁的浏览地址:https://www.lintcode.com/learn/84/294
MySQL常用存储引擎有 MyISAM 和 InnoDB,而 InnoDB 是 MySQL 默认的引擎。MyISAM 不支持行锁,而 InnoDB 支持行锁和表锁。
-- 上读锁 --
SELECT
-- 上写锁 --
INSERT, UPDATE, DELETE
select column_name from table_name where lock in share mode;
上排它锁(写锁)的写法:for update,例如:
select column_name from table_name where conditions for update;
-- 解锁所有锁表 --
UNLOCK TABLES;
例如
待后续更新
to be continue。。。。。