GBase 8a 学习笔记 011 —— GBase 8a MPP Cluster DQL语句
DQL:Data Query Language 数据库查询语言
SELECT语句语法格式
在SQL中,SELECT语句的语法格式为
SELECT [ ALL | DISTINCT ] <列表达式>, ......
FROM <表名>, ......
[ WHERE <条件表达式> ]
[ GROUP BY <列名>, ...... [ HAVING <条件表达式> ] ]
[ ORDER BY <列名> [ ASC | DESC ], ...... ]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[INTO OUTFILE ‘file_name’ <导出选项> ] ;
编写和执行顺序
- 查询中用到的关键词主要包含六个,编写顺序依次为
- select–from–where–group by–having–order by
- SQL Select语句完整的执行顺序
- from子句用于组装来自不同数据源的数据;
- where子句用于根据指定的条件对记录行进行筛选;
- group by子句用于将数据划分为多个分组;
- 使用聚集函数进行计算;
- having子句用于筛选分组;
- order by子句用于对结果集进行排序。
单表查询示例
-- 数据准备
gbase> CREATE TABLE student (
-> Sno varchar(20) ,
-> Sname varchar(20) ,
-> Ssex varchar(20) ,
-> Sage int(11) ,
-> Sdept varchar(20)
-> ) ;
Query OK, 0 rows affected (Elapsed: 00:00:00.05)
gbase> INSERT INTO student (Sno,Sname,Ssex,Sage,Sdept) VALUES
-> ('200215125','张立','男',19,'IS')
-> ,('200215123','王敏','女',18,'MA')
-> ,('200215122','刘晨','女',19,'CS')
-> ,('200215121','李勇','男',20,'CS');
Query OK, 4 rows affected (Elapsed: 00:00:00.04)
Records: 4 Duplicates: 0 Warnings: 0
gbase> CREATE TABLE SC (
-> sno varchar(20) ,
-> cno int(11) ,
-> grade int(11)) ;
Query OK, 0 rows affected (Elapsed: 00:00:00.03)
gbase> INSERT INTO SC (sno,cno,grade) VALUES
-> ('200215121',1,92)
-> ,('200215121',2,85)
-> ,('200215121',3,88)
-> ,('200215122',2,90)
-> ,('200215122',3,80)
-> ,('200215123',3,56)
-> ,('200215123',5,80)
-> ,('200215123',1,66)
-> ,('200215126',3,58)
-> ,('200215126',6,54);
Query OK, 10 rows affected (Elapsed: 00:00:00.03)
Records: 10 Duplicates: 0 Warnings: 0
gbase> select * from student;
+-----------+--------+------+------+-------+
| Sno | Sname | Ssex | Sage | Sdept |
+-----------+--------+------+------+-------+
| 200215125 | 张立 | 男 | 19 | IS |
| 200215123 | 王敏 | 女 | 18 | MA |
| 200215122 | 刘晨 | 女 | 19 | CS |
| 200215121 | 李勇 | 男 | 20 | CS |
+-----------+--------+------+------+-------+
4 rows in set (Elapsed: 00:00:00.02)
gbase> select * from SC;
+-----------+------+-------+
| sno | cno | grade |
+-----------+------+-------+
| 200215121 | 1 | 92 |
| 200215121 | 2 | 85 |
| 200215121 | 3 | 88 |
| 200215122 | 2 | 90 |
| 200215122 | 3 | 80 |
| 200215123 | 3 | 56 |
| 200215123 | 5 | 80 |
| 200215123 | 1 | 66 |
| 200215126 | 3 | 58 |
| 200215126 | 6 | 54 |
+-----------+------+-------+
10 rows in set (Elapsed: 00:00:00.01)
gbase>
-- 查询所有学生信息
-- * 代表所有列,慎用
gbase> select * from student;
+-----------+--------+------+------+-------+
| Sno | Sname | Ssex | Sage | Sdept |
+-----------+--------+------+------+-------+
| 200215125 | 张立 | 男 | 19 | IS |
| 200215123 | 王敏 | 女 | 18 | MA |
| 200215122 | 刘晨 | 女 | 19 | CS |
| 200215121 | 李勇 | 男 | 20 | CS |
+-----------+--------+------+------+-------+
4 rows in set (Elapsed: 00:00:00.01)
-- 查询学生学号和姓名信息。
-- 推荐写具体投影列
gbase> SELECT Sno, Sname FROM STUDENT;
+-----------+--------+
| Sno | Sname |
+-----------+--------+
| 200215125 | 张立 |
| 200215123 | 王敏 |
| 200215122 | 刘晨 |
| 200215121 | 李勇 |
+-----------+--------+
4 rows in set (Elapsed: 00:00:00.01)
-- 查询偶数年龄的学生学号和姓名。
-- 推荐写where条件过滤数据
gbase> SELECT Sno 学号,Sname 姓名 FROM STUDENT where Sage % 2 = 0;
+-----------+--------+
| 学号 | 姓名 |
+-----------+--------+
| 200215123 | 王敏 |
| 200215121 | 李勇 |
+-----------+--------+
2 rows in set (Elapsed: 00:00:00.01)
-- 查询年龄19到21岁的学生学号和姓名。
-- BETWEEN... AND范围等同于>= and <=
gbase> SELECT Sno, Sname FROM Student WHERE Sage BETWEEN 19 AND 21;
+-----------+--------+
| Sno | Sname |
+-----------+--------+
| 200215125 | 张立 |
| 200215122 | 刘晨 |
| 200215121 | 李勇 |
+-----------+--------+
3 rows in set (Elapsed: 00:00:00.01)
-- 查询姓张且全名为2个汉字的学生及姓刘的学生的信息。
-- %代表任意多个字符
-- _代表任意一个字符
gbase> SELECT * FROM Student WHERE Sname LIKE '刘%' OR Sname LIKE '张_';
+-----------+--------+------+------+-------+
| Sno | Sname | Ssex | Sage | Sdept |
+-----------+--------+------+------+-------+
| 200215125 | 张立 | 男 | 19 | IS |
| 200215122 | 刘晨 | 女 | 19 | CS |
+-----------+--------+------+------+-------+
2 rows in set (Elapsed: 00:00:00.01)
运算符
查询类别 | 运算符 |
---|---|
算术 | +, -, *, /, div, %, mod |
比较 | =, >, >=, <, <=, !=, <> |
范围 | BETWEEN…AND…, NOT BETWEEN…AND… |
集合 | IN, NOT IN |
空值判断 | IS NULL, IS NOT NULL |
字符匹配 | LIKE, NOT LIKE, REGEXP, RLIKE |
逻辑运算 | NOT, !, AND, &&, OR, ||, XOR |
-- 查询缺少学生年龄的学生编号。
-- NULL 表示“空值”,没有数据;
-- 不同于数字 0或‘’ 空字符串;
-- 不能用=号,不能与其他值做运算
SELECT * FROM Student WHERE sage IS NULL ;
-- 查询缺少学生年龄的学生编号。
-- NULL 表示“空值”,没有数据;
-- 不同于数字 0或‘’ 空字符串;
-- 不能用=号,不能与其他值做运算
gbase> SELECT * FROM Student WHERE sage IS NULL ;
Empty set (Elapsed: 00:00:00.01)
常用的SQL聚合函数
聚合函数 | 描 述 |
---|---|
COUNT(*) | 计算所有行的个数 |
COUNT(<列名>) | 计算一列中非NULL值的个数 |
SUM(<列名>) | 计算一列值的总和(该列必须为数值型) |
AVG(<列名>) | 计算一列值的平均值(该列必须为数值型) |
MAX(<列名>) | 计算一列值中的最大值(Maximum) |
MIN(<列名>) | 计算一列值中的最小值(Minimum) |
-- 按课程号(Cno)分组,查询每门课程的选课人数
-- SELECT 的投影列必须包含在 GROUPBY 中
gbase> SELECT Cno,COUNT(Sno) FROM SC GROUP BY Cno ;
+------+------------+
| Cno | COUNT(Sno) |
+------+------------+
| 6 | 1 |
| 2 | 2 |
| 1 | 2 |
| 3 | 4 |
| 5 | 1 |
+------+------------+
5 rows in set (Elapsed: 00:00:00.61)
-- 查询选修了2门以上课程的学生学号
-- having是分组聚合运算后的结果上进行筛选
gbase> SELECT Sno, count(distinct cno) FROM SC GROUP BY Sno HAVING COUNT(*)>2 ORDER BY sno;
+-----------+---------------------+
| Sno | count(distinct cno) |
+-----------+---------------------+
| 200215121 | 3 |
| 200215123 | 3 |
+-----------+---------------------+
2 rows in set (Elapsed: 00:00:00.23)
where、having 的区别和用法 :
- where 后不能跟聚合函数,因为where执行顺序在分组前过滤数据。
- having 子句的作用是筛选满足条件的组,即在分组之后过滤数据,条件中经常包含聚合函数。
-- 按学生年龄降序排名
gbase> SELECT * FROM Student ORDER BY sage DESC;
+-----------+--------+------+------+-------+
| Sno | Sname | Ssex | Sage | Sdept |
+-----------+--------+------+------+-------+
| 200215121 | 李勇 | 男 | 20 | CS |
| 200215122 | 刘晨 | 女 | 19 | CS |
| 200215125 | 张立 | 男 | 19 | IS |
| 200215123 | 王敏 | 女 | 18 | MA |
+-----------+--------+------+------+-------+
4 rows in set (Elapsed: 00:00:00.07)
-- 查询年龄最大的前三名学生信息
-- LIMIT 3; //检索前 3个记录行
-- LIMIT 3,10; // 检索记录行 4-13
-- LIMIT 10 OFFSET 3; // 检索记录行 4-13
gbase> SELECT * FROM Student ORDER BY sage DESC LIMIT 3;
+-----------+--------+------+------+-------+
| Sno | Sname | Ssex | Sage | Sdept |
+-----------+--------+------+------+-------+
| 200215121 | 李勇 | 男 | 20 | CS |
| 200215125 | 张立 | 男 | 19 | IS |
| 200215122 | 刘晨 | 女 | 19 | CS |
+-----------+--------+------+------+-------+
3 rows in set (Elapsed: 00:00:00.10)
-- 使用LIMIT 实现显示11-20条结果集
SELECT * FROM Student ORDER BY sage DESC LIMIT 10,10;
-- 使用LIMIT 实现分页显示
select * from studnet limit (pageNumber-1)*pageSize, pageSize;
select * from student limit pageSize offset (pageNumber-1)*pageSize;
连接查询
- 若一个查询同时涉及两个及以上的表,则需要连接查询
- 关系数据库的强大处理能力正是源于各种形式的连接查询,能够将不同表的数据按一定条件连接在一起
- SQL 提供的链接查询分为内连接(Inner Join)和外连接(Outer Join)两大类型
- 内连接将两个表连接在一起的条件称为连接谓词(Join Predicate)或连接条件
- 内连接只返回两个表中与连接谓词匹配的行,不匹配的行不会被输出
- 外连接可以将左表或右表中不匹配的行输出
- 外连接分为左外连接(Left Outer Join)、右外连接(Right Outer Join)和完全外连接(Full OuterJoin)
- INNER JOIN(内连接)
- LEFT OUTER JOIN(左外连接:左表无对应项的记录填充NULL)
- RIGHT OUTER JOIN(右外连接:右表无对应项的记录填充NULL)
- FULL OUTER JOIN(完全外连接:左表或右表无对应项的记录填充NULL)
笛卡尔积
在编写中,避免出现笛卡尔积,会导致性能很差
只要有意义的结果,增加关联条件 WHERE A.A_id = B.A_id;
内连接
SELECT <列名>, ......
FROM <左表>,<右表>
WHERE <左表>.<主键> <比较运算符> <右表>.<外键>
-- 或
SELECT <列名>, ......
FROM <左表> INNER JOIN <右表>
ON <左表>.<主键> <比较运算符> <右表>.<外键>
-- 查询每个学生及其选修课程的情况
-- 写法一
-- 内连接,结果集取两表中符合条件的记录
SELECT S.Sname, S.Ssex, SC.Cno, SC.GRADE FROM Student S, SC WHERE S.Sno=SC.Sno;
-- 写法二
SELECT S.Sname, S.Ssex, SC.Cno, SC.GRADE FROM Student S INNER JOIN SC ON S.Sno=SC.Sno;
-- 查询每个学生及其选修课程的情况
-- 写法一
-- 内连接,结果集取两表中符合条件的记录
gbase> SELECT S.Sname, S.Ssex, SC.Cno, SC.GRADE FROM Student S, SC WHERE S.Sno=SC.Sno;
+--------+------+------+-------+
| Sname | Ssex | Cno | GRADE |
+--------+------+------+-------+
| 李勇 | 男 | 1 | 92 |
| 李勇 | 男 | 2 | 85 |
| 李勇 | 男 | 3 | 88 |
| 刘晨 | 女 | 2 | 90 |
| 刘晨 | 女 | 3 | 80 |
| 王敏 | 女 | 3 | 56 |
| 王敏 | 女 | 5 | 80 |
| 王敏 | 女 | 1 | 66 |
+--------+------+------+-------+
8 rows in set (Elapsed: 00:00:00.06)
-- 写法二
gbase> SELECT S.Sname, S.Ssex, SC.Cno, SC.GRADE FROM Student S INNER JOIN SC ON S.Sno=SC.Sno;
+--------+------+------+-------+
| Sname | Ssex | Cno | GRADE |
+--------+------+------+-------+
| 李勇 | 男 | 1 | 92 |
| 李勇 | 男 | 2 | 85 |
| 李勇 | 男 | 3 | 88 |
| 刘晨 | 女 | 2 | 90 |
| 刘晨 | 女 | 3 | 80 |
| 王敏 | 女 | 3 | 56 |
| 王敏 | 女 | 5 | 80 |
| 王敏 | 女 | 1 | 66 |
+--------+------+------+-------+
8 rows in set (Elapsed: 00:00:00.03)
-- 查询每个学生及其选修课程的情况(包括未选课学生)
-- 左外连接
-- 左外连接,结果集取左表中全部的行,如右表中没有符合条件的对应则填充null
SELECT S.Sno, S.Sname, S.Ssex, S.Sage, S.Sdept, SC.Cno, SC.GRADE FROM Student S LEFT OUTER JOIN SC ON S.Sno=SC.Sno ;
-- 查询每个学生及其选修课程的情况(包括未选课学生)
-- 左外连接
-- 左外连接,结果集取左表中全部的行,如右表中没有符合条件的对应则填充null
gbase> SELECT S.Sno, S.Sname, S.Ssex, S.Sage, S.Sdept, SC.Cno, SC.GRADE FROM Student S LEFT OUTER JOIN SC ON S.Sno=SC.Sno ;
+-----------+--------+------+------+-------+------+-------+
| Sno | Sname | Ssex | Sage | Sdept | Cno | GRADE |
+-----------+--------+------+------+-------+------+-------+
| 200215121 | 李勇 | 男 | 20 | CS | 1 | 92 |
| 200215121 | 李勇 | 男 | 20 | CS | 2 | 85 |
| 200215121 | 李勇 | 男 | 20 | CS | 3 | 88 |
| 200215122 | 刘晨 | 女 | 19 | CS | 2 | 90 |
| 200215122 | 刘晨 | 女 | 19 | CS | 3 | 80 |
| 200215123 | 王敏 | 女 | 18 | MA | 3 | 56 |
| 200215123 | 王敏 | 女 | 18 | MA | 5 | 80 |
| 200215123 | 王敏 | 女 | 18 | MA | 1 | 66 |
| 200215125 | 张立 | 男 | 19 | IS | NULL | NULL |
+-----------+--------+------+------+-------+------+-------+
9 rows in set (Elapsed: 00:00:00.41)
-- 查询每个学生及其选修课程的情况(包括未选课学生)
-- 右外连接
-- 右外连接,结果集取右表中全部的行,如左表中没有符合条件的对应则填充null
gbase> SELECT S.Sno, S.Sname, S.Ssex, S.Sage, S.Sdept, SC.Cno, SC.GRADE FROM Student S RIGHT OUTER JOIN SC ON S.Sno=SC.Sno ;
+-----------+--------+------+------+-------+------+-------+
| Sno | Sname | Ssex | Sage | Sdept | Cno | GRADE |
+-----------+--------+------+------+-------+------+-------+
| 200215121 | 李勇 | 男 | 20 | CS | 1 | 92 |
| 200215121 | 李勇 | 男 | 20 | CS | 2 | 85 |
| 200215121 | 李勇 | 男 | 20 | CS | 3 | 88 |
| 200215122 | 刘晨 | 女 | 19 | CS | 2 | 90 |
| 200215122 | 刘晨 | 女 | 19 | CS | 3 | 80 |
| 200215123 | 王敏 | 女 | 18 | MA | 3 | 56 |
| 200215123 | 王敏 | 女 | 18 | MA | 5 | 80 |
| 200215123 | 王敏 | 女 | 18 | MA | 1 | 66 |
| NULL | NULL | NULL | NULL | NULL | 3 | 58 |
| NULL | NULL | NULL | NULL | NULL | 6 | 54 |
+-----------+--------+------+------+-------+------+-------+
10 rows in set (Elapsed: 00:00:00.07)
-- 查询每个学生及其选修课程的情况
-- 全连接
-- 全连接,结果集取两张表中全部的行,如没有符合条件的对应项则填充null
gbase> SELECT S.Sno, S.Sname, S.Ssex, S.Sage, S.Sdept, SC.Cno, SC.GRADE FROM Student S FULL OUTER JOIN SC ON S.Sno=SC.Sno ;
+-----------+--------+------+------+-------+------+-------+
| Sno | Sname | Ssex | Sage | Sdept | Cno | GRADE |
+-----------+--------+------+------+-------+------+-------+
| 200215121 | 李勇 | 男 | 20 | CS | 1 | 92 |
| 200215121 | 李勇 | 男 | 20 | CS | 2 | 85 |
| 200215121 | 李勇 | 男 | 20 | CS | 3 | 88 |
| 200215122 | 刘晨 | 女 | 19 | CS | 2 | 90 |
| 200215122 | 刘晨 | 女 | 19 | CS | 3 | 80 |
| 200215123 | 王敏 | 女 | 18 | MA | 3 | 56 |
| 200215123 | 王敏 | 女 | 18 | MA | 5 | 80 |
| 200215123 | 王敏 | 女 | 18 | MA | 1 | 66 |
| 200215125 | 张立 | 男 | 19 | IS | NULL | NULL |
| NULL | NULL | NULL | NULL | NULL | 3 | 58 |
| NULL | NULL | NULL | NULL | NULL | 6 | 54 |
+-----------+--------+------+------+-------+------+-------+
11 rows in set (Elapsed: 00:00:00.04)
全连接
SELECT S.Sno, S.Sname, S.Ssex, S.Sage, S.Sdept, SC.Cno, SC.GRADE
FROM Student S FULL OUTER JOIN SC ON S.Sno=SC.Sno ;
-- 等价于左外连接 UNION 右外连接
SELECT S.*, SC.Cno, SC.GRADE FROM Student S LEFT OUTER JOIN SC
ON S.Sno=SC.Sno
UNION
SELECT S.*, SC.Cno, SC.GRADE FROM Student S RIGHT OUTER JOIN SC
ON S.Sno=SC.Sno ;
注:实际编写SQL中,尽量少用全连接,避免结果集过大导致性能慢。
自连接
是连接的一种用法, 本质是把一张表当成两张表来使用,一般用别名区分。
-- 查询比’王敏’年龄大的学生的人数( 在Student表中,’王敏’ 的年龄为18)
-- 分步方式:
SELECT sage FROM student WHERE sname='王敏'; //得出sage查询结果为18
SELECT count(*) 学生人数 FROM student WHERE sage>18;
-- 自连接方式(在一条 SQL 中实现):
-- a和b是student表的别名
gbase> SELECT count(*) 学生人数
-> from student as a, student as b
-> where a.sname='王敏' and a.sage<b.sage;
+--------------+
| 学生人数 |
+--------------+
| 3 |
+--------------+
1 row in set (Elapsed: 00:00:00.09)
多表连接
-- 查询每个学生学号,姓名,选修的课程名及成绩
-- 两个以上的表进行连接,这称为多表连接。
SELECT S.Sno, S.Sname, C.Cname, SC.Grade FROM Student S ,Course C,SC WHERE S.Sno=SC.Sno AND SC.Cno=C.Cno ;
说明:
- 多表关联时,基于代价进行优化,内关联跟表书写顺序无关;
- where条件从右向左顺序执行,建议把返回结果集小的表条件写到最后;
- 使用explain … 在线查询 SELECT 语句执行计划
Union 和 Union All
应用:如果两个或多个 SELECT 语句的结构相似,则可以用“Union”或“Union All”把这些SELECT 语句合并起来
UNION 与 UNION ALL 的区别:
- UNION : 对两个结果集进行并集操作,不包括重复行;
- Union All:对两个结果集进行并集操作,包括重复行,不进行排序;
- 如果结果集没重复数据,建议使用Union All 代替UNION,性能更好。
注意:保证各个select 集合的结果有相同个数的列,并且每个列的类型是一样的。
- 两端都是char类型数据,会隐式转换成varchar类型。
- 小的数据类型向大的数据类型转换,如:INT -> BIGINT -> DECIMAL -> DOUBLE
编写高效SQL语句
- 避免生产环境使用select ,减少投影列
- 数据量大时,group By 、order by会很费时,建议将hash分布列写在第一个位置
- 使用where条件提前过滤数据,减少join的运算
- 使用limit 减少物化的结果集条数
- 在做多表查询时应注意字段名称的唯一性;如果不唯一,则要明确写明表名。
- 内连接比外连接效率要高,连接查询所使用的字段最好是hash分布键。
- 注意笛卡尔积的问题:
- 关注 /opt/gnode/tmpdata/cache_gbase/HashJoin 空间变化,如果出现2-10G增长,则表示可能出现笛卡尔积
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。