如果只是简单的操作数据库的话,包括和Java等语言的联动,基本上一天速成是没什么毛病的。此文章用于自查简单语句用,非泛用型教程。有爱自取,长期不定期更新
注:大部分事例代码根据《SQL基础教程总结》编写。由于原书的相关事例都是日文事例(数据名称是日文罗马音),阅读不便,可能会根据需要进行相关的事例调整。
*所有结束语句必须用“;”结尾
**一般情况下所有的标准SQL关键字都用全大写表示(也就是说本身SQL的关键字不区分大小写),方便识别,提升可阅读性
***MySQL的注释为“-- ”,两个单短线+一个空格 ,此注释为单行空格,MySQL支持多行注释,方法和C相同
初始步骤,假设你不用DataGrip这样的IDE或者与 Java联动的话,在终端需要进行账户登陆:
mysql -u 用户名 -p
回车后进行密码输入,登入mysql的相关账户(其他SQL大同小异,在这里不在赘述。根据实际操作进行应变即可)
*********************************************************************
DDL语句(Data Definition Language 数据库(表)定义语言)
————————————————
此部分语句用于调整整个数据库或者数据库中的表格数据(而不是表格中的详细数据)。
对表中的数据进行相关操作的是DML语句。
————————————————
1.CREATE 创建数据库和表的对象
创建表格
CREATE DATABASE SchoolDatabase;
创建一个名为SchoolDatabase的数据库(而不是数据库里面的表)
数据库是用来存储表的,而表才是我们常识中用来存储数据用的单位。
语句结尾需要用“;”来结尾,后面不在赘述
CREATE TABLEstudentsBook(
student_IDINT NOT NULL, -- 存储学生学号,整型,不能为空
student_NAMEVARCHAR(20) NOT NULL, -- 存储学生姓名,可变长度字符型,不能为空
-- 可变长度是指,如果输入的数据长度没有达到限制的长度的话,字符串仍然会保存成原始字符串的长度(例如“abc”被存储为“abc”)
student_SEXCHAR(6) NOT NULL, -- 存储学生性别,不可变长度字符串,不能为空
-- 不可变长度是指,如果输入的数据长度没有达到限制长度的话,字符串会存储成设定的字符串长度(例如“abc”会存储成"abc "(多了一个空格,因为原始字符串为4长度))
student_TELCHAR(13) DEFAULT '-' , -- 存储学生电话号码,不可变长度字符串,可为空,默认情况下为单横线
student_BIRTH DATE , -- 存储学生生日,日期类型,可为空PRIMARY KEY (student_ID) -- 设定主键约束。被设定为主键约束的列中不能包含重复的数据(理论上不会出现两个学号相同的学生,所以将学生学号设定为PRIMARY KEY是合理的。一般情况下,为了使数据中的某一列具有唯一性,通常会将这 #一列设定为PRIMARY KEY)
);
需要注意的是,如果创建表单的时候设定了默认值(例如student_TEL),则在INSERT 数值的时候可以使用DEFAULT关键字作为插入值。
DROP 删除数据库和表等对象
DROP TABLE studentsBook; -- 删除studentsBook这个表
除非你是故意的,否则别随便跑这个句子。跑完后整个表都会被删除掉
ALTER 修改数据库和表等结构对象的结构
ALTER TABLE studentsBook ADD COLUMNxxxx; -- 添加xxxx列到studentsBook中(包括列的定义)ALTER TABLE studentsBook ADD COLUMN(xxxx,xxxx,xxxx); -- 添加三列到studentsBook中(包括列的定义)ALTER TABLE studentsBook DROP COLUMNxxxx; -- 删除studentsBook表中的xxxx列(可同时删除多个列,操作和ADD一样)ALTER TABLE studentsBook to studentsbook -- 对表格进行重新命名
*********************************************************************
DML语句(Data Nabuoulation Language, 数据操作语言) 语句用来查询或者变更表中的数据
————————————————
此部分语句用于操作数据库中表的相关数据,与前面DDL语句不同的是,这部分只针对表中的数据进行修改,对表的列、表名称等不进行干涉
————————————————
SELECT 查询表中的数据(可与FROM,WHERE等关键字搭配进行特定数据查找)
SELECT * FROM studentsBook; -- 从整个表中选取数据,并进行展示
SELECT student_ID, student_NAME FROM studentsBook -- 从表中选取相关的列,并进行展示
SELECT student_ID AS ID, student_NAME AS NAME FROM studentsBook; -- 从表中选取相关的数据,对各个列头进行别称命名(例如student_ID 列头显示为ID,student_NAME 列头显示为NAME)
同时,SELECT可以选择常量,并对常量进行别名定义,
例如:
SELECT 'boy' AS students, 20 AS students_AGE, student_ID as ID FROM studentsBook;
有时候我们可能只想获得不重复的数据,例如想知道一个班内是否只有男生或者是否只有女生或者是否既有男生又有女生(我们假设这三种情况可能存在),那么可以通过
SELECT DISTINCT student_SEX FROM studentsBook;
来查找我们想要的结构。这句话会合并重复的行。(如果此数据为NULL状态,他们同样会被合并)
如果将多个列放在列参数中,前面调用DISTINCT的时候会将同样的行进行合并(而不是只比较单列中的数据是否相同。从常识上考虑显然这么做也是不合理的)。
有时候,对于数据我们可能需要进行一定的筛选。例如在学生名单中只查找年龄在18岁以上的男生,或者未成年的所有同学等。这时候就需要对列中的相关数据进行筛选了。
例如选择年龄等于18的未成年人作为筛查对象的话,则可以通过以下语句进行:(MySQL中的波尔等号为单等号,这个与一般编程语言中并不相同,需要注意)
MySQL的比较运算符
运算符
含义
=
相等
<>
不想等
>=
大于等于
<=
小于等于
>
大于
<
小于
SELECT * FROM studentsBook WHERE student_AGE = 18; -- FROM 和 WHERE的位置不可以调换,这一点需要注意
当然,我们也可以通过比较日期来进行数据比较
SELECT * FROM studentsBook WHERE student_BIRTH <= '2001-01-01';
或者通过运算来比较数据
SELECT * FROM studentsBook WHERE student_AGE - 18 <= 0;
或者相反的效果:
SELECT * FROM studentsBook WHERE NOT student_AGE - 18 <= 0; -- 注意NOT的位置
当然有时候条件并不是单一的,例如查找18岁以上的男生这句话就包括了两个需要判断的条件。此时需要使用“AND”来对条件进行拼接(如果是或的话则使用“OR”来进行链接)
另外需要注意的是,由于条件关键词的优先级各不相同,AND > OR,因此有时候需要使用括号来对优先级进行适当的调整。
SELECT * FROM studentsBook WHERE student_AGE >= 18 AND student_SEX = 'MALE';
如果比较的是字符串或者字符,则结果是根据unicode或者其他编码进行比较的(这一点和Java类似)
另外,NULL元素不可以使用比较运算符。结果会直接被排除在外 ,而这有时候是并不合适的,同时,即使使用形如“= NULL”, 也不会显示任何内容。如果移动要操作NULL的相关元素或者数据,则使用“IS”或者“IS NOT”运算符
来链接前面的判断数据和后面的NULL。
也因此,SQL并不是单纯的判断真假,而是判断真假和不确定。AND和OR的情况由4个变成来9个,当条件变成不确定的时候,我们需要根据不确定取真或取假,对结果是否有影响来判断最终AND和OR的结果。如果有影响,则结果为不确定,反之则为原先确定的结果
如果想暂时性的查看表中数据经过一些变化后的结果(例如一年后各位同学都多大了?之类的),则可以在SELECT语句中包含一些算数表达式
算数表达式支持(+ - * / )
SELECT student_ID, studnet_NAME, student_AGE + 1 AS student_YearAge FROM studentsBook;
注:如果算数表达式操作的是NULL元素,无论什么算数操作,最终结果都是NULL
INSERT 向表中插入数据(一般与VALUES和INTO等关键字搭配使用)
INSERT INTO studentsBook VALUES(100000, 'Andy Tom', 'MALE', '1234567890', '1998-10-23'); -- 根据表中列的顺序进行插入操作。
如果想一次性插入多条数据的话,则通过下面的语句进行操作:
START TRANSACTION;INSERT INTO......;INSERT INTO......;INSERT INTO......;COMMIT;
或者直接一句INSERT完成工作:
INSERT INTO TableName (col1, col2, col3...) VALUES(val1, val2, val3...),
(val4, val5, val6...),
(val7, val8, val9...);--最后一个要插入的数据由分号结尾,其他数据通过逗号来进行连接。
如果只是想插入部分数据(例如只插入NOT NULL的数据),则可用来执行相关的操作
常见格式为:
INSERT INTO TableName (col1, col2, col3...) VALUES (val1, val2, val3...);
INSERT INTO studentsBook (student_ID, student_NAME, student_SEX) VALUES(100000, 'Andy Tom', 'MALE');
理所应当的,需要插入的数据与插入数据所在的列应当是一一对应的,否则会造成错误。
另外需要注意的是,如果插入的位置被设定为NOT NULL标志,则不可以向此处插入NULL数据,其他位置则可以根据需要插入NULL数据。
有时候我们可能并不想一行行的将数据逐行插入到表中,而是希望通过直接将表中的相关数据添加到另一张表中。显然这么做会节省更多的时间,且更准确,不容易出错
具体代码如下:
INSERT INTO studentsBookCopy (col1, col2, col3) SELECT col1, col2, col3 FROM studentsBook WHERE.... GROUP BY col1;
UPDATE 变更表中的数据
如果想对某一行的数据进行更新,例如所有15届的学生被记录成了16届,则可以通过UPDATE-SET语句对表进行更新:
UPDATE studentsBook SET year = 2015; -- 此处的“=” 相当于是赋值操作,而不是判断两个数值是否相等
当然我们可能只是某一个人的数据有所失误,这时候只需要使用WHERE关键字来对表进行筛选即可:
UPDATE studentsBook SET year = 2015 WHERE students_ID = 12345678;
如果想一次更新多行语句,则可以使用如下方法进行操作:
UPDATE studentsTable SET student_ID = 2015215,
student_YEAR= 2015 WHERE student_NAME = 'Tom';
DELETE 删除表中的数据
例如删除一个表中的所有数据,但是保留表的相关性质,则通过一下语句完成(操作的是行数据,而不是列数据):
DELETE FROM TableName;
如果想要根据特定信息来进行信息的删除,可以与WHERE关键字结合来对删除的数据先进行筛选,然后再进行数据的删除操作。例如下面的语句:
DELETE FROM studentsBook WHERE student_ID = 12345678;
*********************************************************************
DCL语句(Data Control Language 数据控制语言)
————————————————
用来确认或者取消对表格中的数据所进行的变更。除此之外,还可以对关系型数据库的用户是否有全县操作数据库中的对象(数据库表等)进行设定
————————————————
COMMIT: 确认对数据库中的数据进行的变更
ROLLBACK:取消对数据库中的数据进行的变更
GRANT:赋予用户操作的权限
REVOKE:取消用户的操作权限
部分常用聚合函数
有时候我们可能需要对表格中的数据进行一些简单的处理操作,例如比大小,查找最大、最小值等操作。此时就需要通过聚合函数来对表进行相关的操作。
常用的聚合函数包括:
COUNT:计算表中的记录数(行数)
COUNT可以记录整张表的行数,也可以记录单列(不包括NULL)的行数。
例如:SELECT COUNT(*) FROM studentsBook;会计算整个表的行数,无论这张表是不是全部都是NULL。而假设极端情况下所有数据都是NULL,
则SELECT COUNT(NULL_COL)FROM studentsBook;的结果则是0。COUNT计算单个列的时候会忽略掉全部都NULL元素
同时,COUNT支持与DISTINCT进行联动。例如如下操作:想知道大家的生日都分布在哪一天(没有重复),则可以使用如下的方法:
SELECT COUNT(DISTINCT student_BIRTH) FROM studentsBook;
注:DISTINCT的用法在其他聚合函数中同样适用
SUM:计算表中数值列的总和
SELECT SUM(单一列)FROM studentsBook;
注意:对于列中的NULL元素会首先采取排除操作,然后再进行相关数据的求和计算,因此不会出现+ NULL = NULL的情况(AVG同理)
AVG:求熟知列中数据的平均值
SELECT AVG(单一列) FROM studentsBook;
MAX:求出表中任一列中数据的最大值
SELECT MAX(单一列) FROM studentsBook;
MIN:求出表中任一列中数据的最小值
SELECT MIN(单一列) FROM studentsBook;
注:聚合函数不可以在WHERE子句中使用
GROUP BY
这一部分相对理解困难,为了方便理解,会用图片进行辅助理解。
由于
group by不准确的说就是对数据库中的表进行再分解,形成一个个的小表,并对这些小表进行相关的操作。
假设我们有一个商品相关的数据库,则使用其中有一列卫种类列(假设为product_cat),其中包含衣服类2行,办公用品2行,厨房用具4行,则在执行如下语句的时候:
SELECT product_cat, COUNT(*) FROM shopTable GROUP BY product_cat; -- 注意各个关键字的顺序
首先会对product_cat进行分割(分成衣服、办公用品、厨房用具三部分)。此时之后的“*”则是针对分割后的子表来说的,而不是整个的shopTable。因为GROUP BY关键句已经限定了数据的操作范围。此时相当于进行了3次的COUNT聚合函数的操作。(这部分有待验证)(并且第一部分,第二部分,第三部分是随机分配的)
如果聚合分类后包含NULL列(即NULL被单独的进行了分组),则NULL也会包含在内,并对NULL进行相关的计算(例如COUNT出有多少行NULL)
分类并不代表不能加限定条件了。我们同样可以用WHERE来进行相关的限定操作
例如如下语句:
SELECT shop_cat, COUNT(*) FROM shopList WHERE shop_cat = 'Cloth' GROUP BY shop_cat;
此段代码可以这么理解:首先对数据通过WHERE语句进行一次筛选(只剩下了衣服)。之后对筛选后的数据进行再分割例如衣服分类内有T恤与裤子,则最终结果是T恤记1,裤子记1.
注:SELECT中的列名必须与GROUP BY里面的列名完全相同。如果两个部分的列名不完全相同则会产生错误
另外由于语句的执行顺序,不能再GROUP BY中使用列的别名(临时给列起的名字),这同样是非法操作。
HAVING子句
前面经常使用的WHERE子句是真对表中的数据来进行判断操作,例如行内的数据是否大于0这样的判断条件。但是WHERE不能使用聚合函数,也因此(尽管这不是全部的原因),WHERE不能判断表的特征(而不是表内部数据的特征)。为了判断表的特征(例如分割完毕的子表是否包含两行,可能就需要COUNT聚合函数来判断),我们就需要使用HAVING子句。与WEHRE更偏向于表内数据不同,HAVING子句更偏向于对表的外部特征(例如表包含了多少行)进行判断操作。
HAVING子句需要写在GROUP BY子句后面
举个例子,在商品列表这张表中,我们需要判断哪一种商品包含2种商品,此时就可以通过下面的语句来对表进行相关操作:
SELECT shop_cat, COUNT(*) FROM shopList GROUP BY shop_cat HAVING COUNT(*) = 2;
另外,由于HAVING是再针对GROUP BY来进行修订的,因此HAVING子句的可包含的内容与SELECT限定的一样:
常数
聚合函数
GROUP BY中指定的列名
有些时候HAVING和WHERE所得出的结果是相同的。举两个相同结果的事例代码:
SELECT shop_cat, COUNT(*) FROM shopList GROUP BY shop_cat HAVING shop_cat = 'Cloth';
SELECT shop_cat, COUNT(*) FROM shopList WHERE shop_cat = 'Cloth';
此两句的结果是完全相同的。但是在编写SQL的时候我们应当有这样的潜意识操作:HAVING更多的是针对表的外在条件(例如包含多少行),而WHERE更多的是对表内的数据进行判断操作(例如谁的年龄超过了18岁)因此,对于shop_cat = 'Cloth'这样的语句来说,其更适合安放在WHERE中,而不是HAVING子句中,尽管两种表达方式都是合法且正确的。
ORDER BY
数据往往不是提取出来就算完成任务。有时候我们希望对数据进行简单的排序操作(例如按照学生年龄的高低来进行数据的排序操作)。此时我们就需要使用ORDER BY语句来对我们最终得到的数据进行排序操作
例如如下语句:
SELECT student_ID, student_AGE, student_NAME FROM studentsBook ORDER BY student_ID;
从studentsBook表中选择学生ID,学生年龄,学生姓名,并根据学生的ID对数据进行排序(升序)
如果想让程序按照降序来显示相关的内容,则在最后添加“DESC”关键字即可。事例代码如下:
SELECT student_ID, student_AGE, student_NAME FROM studentsBook ORDER BY student_ID DESC;
如果想要按照多个信息进行排列,则可以在ORDER BY部分添加多个关键字 ,从而使得排序效果更佳符合我们的预期,效果如下:
SELECT student_ID, student_AGE, student_NAME FROM studentsBook ORDER BY student_ID, student_AGE;
程序首先根据最左边的数据进行排序。如果出现无法比较的数据,则根据右一数据进行排序。
然而,排序的话难免会有处理NULL数据的情况。因此,一旦排序的列中包含了NULL数据,则在最后的数据显示中,NULL数据会被安排在整个排序数据的最后面。
注1:ORDER BY中可以使用列的别名(例如student_ID AS ID,则可以使用ID作为ORDER BY的关键字来使用)
注2:由于排序的数据未必是我们的分割数据,因此排序的数据可以不出现在SELECT中,这与GROUP BY与SELECT的关系是并不一样的。
注3:尽管这么做是合法的,但是由于这个方法会造成:1.阅读上的困难性提升 2.这个功能可能会被删除:不要使用编号作为列的表示方法。
事务
所谓事务,在SQL中类似一系列需要按顺序或者一次性完成的工作。说白了,将前面提到的各个短句拼接在一起,并且按照一定的顺序执行就是一个事务。
对于MySQL来说,事例代码如下:
START TRANSACTION;
语句1;
语句2;
语句3;COMMIT;
注:不同的SQL可能起始句不同。例如MySQL的是START TRANSACTION,而Postgre则是BEGIN TRANSACTION
上述的程序执行过程大致可以分为下面几步:
1.开始执行表中数据的相关操作,也就是START TRANSACTION。
2.依次执行语句1,语句2,语句3.
3.COMMIT,确认所做的修改,将其覆盖到原先的表格当中。
这种修改是永久性的(不考虑数据的可恢复性),所以当执行上述语句的时候,一定要确保你所对数据造成的修改是正确的,没有失误的。尤其是执行DELETE语句的时候。
如果我们想撤销我们所做的一系列修改,只需将COMMIT修改成ROLLBACK(回滚)即可。
注1.一旦回滚,则START TRANSACTION在ROLLBACK之间的语句都将报废
注2:事务操作更多的是在程序自动化执行的时候进行的操作。如果在IDE界面(例如workbench)操作的话,则可以直接对有问题的句子进行修改。
考虑下面情况:你需要通过Java语言进行数据库的批量数据更新或者倒入,此时显然通过start transaction以及commit与rollback相结合进行数据的导入更靠谱。一旦出现导入错误(或者违法数据),则执行rollback操作,反之则在最后执行commit操作即可。
而如果是直接在workbench进行数据的导入,显然直接在语句中对非法数据进行修改要比start transacton来的明智的多。
事务的ACID特性。
事务(也就是start transaction到commit或rollback之间的语句)遵循ACID特性。
原子性(Atomicity):事务或者全部执行,或者全部不执行,不会出现只执行一部分的情况
一致性(Consistency):所有的事务操作必须符合表的相关设定(例如插入的数据类型,是否允许插入空数据等)。(其实所谓的事务说白了就是一次性执行多条语句,而每一条语句显然要符合列表的相关要求,这在前面的语句中我们也已经强调了)。
隔离性(Isolation)事务的所有操作除非其COMMIT了,否则对于其他事务来说是不可见的。也就是说,多个事务同时操作一个表很可能会出现问题。
持久性(Durability):数据在COMMIT之后会保持其特性,即使损坏也可以进行修复。
视图
所有的数据库与数据库中的表往往是存储在磁盘中的。如果是小型的数据库或者表显然多个重复的表不会有影响,但是一旦数据量过于庞大,这种重复性操作显然是不允许的。此时,通过视图语句(保存好的select语句)存储一块区域用来展示原表中的数据和一些经过计算的数据(例如)显然是可以在使用原数据的时候不会产生额外重复使用空间的最好选择,而原表中的修改,会直接影响到视图中的数据,也就是说视图和原表彼此之间是联动的。
我们可以这样理解视图:对于一份枯燥的数据,我们往往想经过一些精美的包装来让这份数据显得不是那么枯燥,甚至还有点意义。这时候视图的效果就显现出来了,通过视图,我们可以看到我们想要的数据效果。
例如我们想要显示一个每个班内有多少同学,可以通过以下语句创建:
CREATE VIEW studengsInClass (student_CLASS, student_COUNT) AS
SELECT student_CLASS, COUNT(*) FROM studentsBook GROUP BY student_CLASS;
而视图同样可以作为一个表(尽管将这个称为表并不准确)来进行view视图的查询,例如我们想知道如果各班如果再额外添加3名同学后,各个班的实际人数的话,则可以通过下面的语句进行操作:
CREATE VIEW studentsAdd3 (student_CLASS, student_CNT_3) AS
SELECT student_CLASS, student_COUNT + 3 FROM studentInClass;
注意到,我们并没有再次执行select语句,而是直接从studentInClass中选取了我们需要的从studentsBook来的student_CLASS与studentInClass中的student_COUNT(而不是计算COUNT())来进行我们的加三操作。
很显然,这种近似嵌套的方式在多次进行视图操作的时候会极大的减少工作量,而在最原始的表中对数据进行更新,例如某一个班里的同学转学,学生人数需要-1的时候,我们并不需要对所有的表进行更新(假设我们没有使用视图操作,而是使用了多次创建表单的情况),此时我们只需要对studentsBook里面的一个数据进行修改,则所有视图链中的数据都将得到更新。
但这里有一个问题,通过视图创建视图会影响SQL的处理数据的效率,因此是为了方便进行多次嵌套,还是说直接忽视掉效率,而进行直接的视图出视图操作,需要酌情考虑。(书内如是说)
视图的一个用处就是创建子查询,即将视图看作一个表(尽管这个表是由产生其的母表决定的)。例如下面的代码:
SELECT student_CLASS, student_CNT_3 FROM studentsAdd3;
就是通过视图进行子查询。不难发现。如果是不使用视图操作,则FROM部分可能至少需要嵌套2次SELECT语句。(首先创建studentInClass为最内层,studentsAdd3所包含的SELECT语句为第二层,之后是我们查询信息用的SELECT语句为第三层,而三层的嵌套对于我们来说显然不是一个友善的代码)而一旦这种嵌套层数再次增加,显然某种意义上是一种灾难。
子查询的一个分支是标量子查询所谓标量子查询,即最终结果为单行结果(即有且只有一个结果)。而这种结果可以使用在WHERE子句中(而WHERE子句是不可以包含聚合函数的)。
在定义视图的时候,需要注意以下几点(仅针对Mysql)
1.不要使用ORDER BY语句对表内数据进行排序操作,尽管这在SELECT语句中是合法的操作。
2.视图一般情况不能被更新,除非:1.select中没有使用group by、having,distinct,并且只有一张表被包含在了select语句中。
如果想要删除掉视图,执行如下事例代码即可:
DROP VIEW YourView(col1, col2, col3...);
如果想要删除掉整个view,则直接写视图名称即可。
关联子查询
理论上这部分应当归类到子查询部分,但是由于个人理解能力比较低下,所以这部分单开一章。并且这部分用到了几乎前面全部的语句,也算是一个复习用部分。
我们先假设这么一个使用环境:在超市仓库中,有多种赏评,每种商品都有一个均价,而我们要做的是找出此类商品下所有高出均价的商品全部罗列出来,(即只要高出其同类商品均价的商品都要罗列出来)。首先我们这里会出现这个:1.如果要比较数据的话,则应当使用where+一个标量子查询,但是标量子查询的限定条件是有且只有一个条件被罗列出来。如果有多个商品的均价的情况下,是不能使用标量子查询的,也就是说没有办法使用在WHERE部分作为一个数字存在。这个时候就需要根据当前种类查找其对应的均价,并进行比较,查询结果,而一个商品其所在种类只有一个均价。伴随这个想法,我们可以通过以下语句进行数据的查询:
假设某表中有如下列:
1. product_ID: 产品编号
2. product_price: 产品单价
3. product_name: 产品名称
4. product_cat: 产品种类
我们通过如下语句进行我们上述要求的信息查询:
SELECT product_ID, product_price, product_name FROM shopList AS SL1
WHERE product_price > (SELECT AVG(product_price) FROM shopList AS SL2
WHERE SL1.product_cat = SL2product.cat
GROUP BY product_cat);
上述语句的执行顺序大致如下:首先执行括号内的select语句部分,将表通过产品种类对表进行分割,并非别对各个子表求出其对应的平均数-->将这些平均数中与我们想要判断的产品种类相同的平均数提取出来,此时就不是多行平均数了,而是一个近似标量子查询结果的单个数值。此时括号内所代表的是当前种类的平均数,之后再进行product_price与其对应的平均数进行比较。如果单价更高,则将其添加到查询的表中。
其中
WHERE SL1.product_cat = SL2product.cat
称谓关联条件语句。
需要注意的是,关联条件语句存在作用域。例如前面的事例中的关联语句只能作用于其所在的select语句之中,而一旦将其位置进行了更换,则会使得整个关联型查询报废。
数据库谓词的使用
有时候我们查找一个内容的时候可能很难精确描述我们想要查找的内容,尤其如下内容:
“查找一个姓李的学生”。对于元素来说,我们还没有确切的判断字符串中是否包含某个或者某段特定字符的方法。这时候,就需要使用谓词来进行帮助查找了
LIKE:
查找某字符串的某一个位置是否包含某子字符串
例:
SELECT * FROM SampleLike WHERE stroll LIKE 'ddd%'; --前方一致(查找的字符串为'ddd')
SELECT * FROM SampleLike WHERE stroll LIKE '%dd%'; --中间一致(查找的字符串为'ddd')
SELECT * FROM SampleLike WHERE stroll LIKE '%ddd'; --后方一致(查找的字符串为'ddd')
BETWEEN:
查找符合一段范围的数值
例:
SELECT shop_cat, shop_price FROM ShopList WHERE shop_price BETWEEN 100 AND 1000; --查找数值范围在100到1000之间的数值,(100与1000均包括)
IN:
如果数值在某一个集合中,则显示这个数值:
例:
SELECT shop_cat, shop_price FROM ShopList WHERE shop_price IN (320, 500, 5000); --如果数值存在于这个集合中,则显示这行信息
注:IN谓词可以添加NOT关键字从而起到反效果。