参考数据库操作系统(第五版)的第三章的关系数据库标准语言SQL的中例子,对数据库的创建、插入、修改、查询功能的一个演示,在hive中创建数据库,在spark-shell中结合Hive on Spark做CURD操作。
1.准备工作
创建一个test数据库,里面包含三张表:学生表、课程表、学生选课表
- 学生表:Student(Sno,Sname,Ssex,Sage,Sdept)
- 课程表:Course(Cno,Cname,Cpno,Ccredit)
- 学生选课表:SC(Sno,Cno,Grade)
2.构建数据仓库
学生表:在/home/hadoop/hive
添加Student.txt
文件
200215121 李勇 男 20 CS
200215122 刘晨 女 19 CS
200215123 王敏 女 18 MA
200215125 张利 男 19 IS
课程表:在/home/hadoop/hive
添加Course.txt
文件
1 数据库 5 4
2 数学 2
3 信息系统 1 4
4 操作系统 6 3
5 数据结构 7 4
6 数据处理 2
7 PASCAL语言 6 4
学生-课程表:在/home/hadoop/hive
添加SC.txt
文件
200215121 1 92
200215121 2 85
200215121 3 88
200215122 2 90
200215122 3 80
3.创建数据表
create table Student(Sno int,Sname string,Ssex string,Sage int,Sdept string) row format delimited fields terminated by '\t';
create table Course(Cno int,Cname string,Cpno int,Ccredit int) row format delimited fields terminated by '\t';
create table SC(Sno int,Cno int,Grade int) row format delimited fields terminated by '\t';
4.加载数据
load data local inpath '/home/hadoop/hive/Student.txt' into table test1.Student;
load data local inpath '/home/hadoop/hive/Course.txt' into table test1.Course;
load data local inpath '/home/hadoop/hive/SC.txt' into table test1.SC;
5.查询基本操作
进入spark-shell
命令行,输入以下命令:
import org.apache.spark.sql.hive.HiveContext
val hc = new HiveContext(sc)
//将上面的SQL语句放在双引号中即可
hc.sql("show databases").show
hc.sql("use test1")
hc.sql("show tables").show
//查询操作
hc.sql("select * from student").show
5.1单表查询
1.选择表中的若干列
查询指定列
hc.sql("select Sno ,Sname from student").show
查询全部列
hc.sql("select * from student").show
查询经过计算的值
hc.sql("select Sname , 2004-Sage from student").show
//查询结果的第二列是一个算术表达式
2.选择表中的若干元组
消除取值重复的行
hc.sql("select Sno from sc").show
//取消重复的列--distinct关键词
hc.sql("select distinct Sno ").show
查询满足条件的元组
查询满足指定条件的元组可以通过where子句实现
(1)比较大小
//查询所有年龄在20岁一下的学生姓名及年龄
hc.sql("select Sname,Sage from student where Sage<20 ").show
(2)确定范围
//查询年龄在20~23岁(包括20岁23岁)之间的学生的姓名、系别和年龄
hc.sql("select Sname,Sage,Sdept from student where Sage between 20 and 30 ").show
//与between...and...相对的谓词是not between...and...
(3)确定集合
谓词IN可以用来查找属性值属于指定集合的元组,与谓词IN相对应的是NOT IN,用来查找属性值不属于指定集合的元组
//查询计算机科学系CS,数学系MA和信息系IS学生的姓名和性别
hc.sql("select Sname,Ssex from student where Sdept IN ('CS','MA','IS') ").show
(4)字符匹配
谓词like可以用来进行字符串的匹配,其含义是查找指定的属性列值与<匹配串>相匹配的元组。其一般语法格式如下:
[NOT] LIKE '<匹配串>' [ESCAPE '<换码字符>']
//查询所有姓刘的学生的姓名、学号和性别
hc.sql("select Sname,Sno,Ssex from student where Sname like '刘%'").show
如果用户要查询的字符串本身就含有通配符%
或_
,这时就要使用ESCAPE'<换码字符>'短语,对通配符进行转义。
//查询DB_Design课程的课程号和学分
hc.sql("select Cno,Ccredit from Course where Cname like 'DB\_Design' escape '\'").show
//escape'\'表示为'\'为转码字符,这样匹配串中紧跟在"\"后面的字符"_"不再具有通配符的含义,转义为普通的"_"字符
(5)涉及空值的查询
//查询缺少成绩的学生的学号和相对应的课程号(注意这里的is不能用等号=代替)
hc.sql("select Sno,Cno from SC where Grade is null").show
(6)多重条件查询
逻辑运算符and和or可用来联结多个查询条件。and的优先级高于or,但用户可以用括号改变优先级。
//查询计算机科学系年龄在20岁一下的学生姓名
hc.sql("select Sname from student where Sdept='CS' and Sage<20").show
3.ORDER BY子句
用户可以用order by 子句对查询结果按照一个或者多个属性列的升序(ASC)或降序(DESC)排列,缺省值为升序。
//查询选修了3号课程的学生的学号及其成绩,查询结果按分数的降序排列
hc.sql("select Sno,Grade from SC where Cno='3' order by Grade DESC").show
4.聚集函数
为了进一步方便用户,增强检索功能,SQL提供了许多聚集函数,主要有:
count()、sun()、avg()、max()、min()
//计算1号课程的学生平均成绩
hc.sql("select avg(Grade) from SC where Cno='1'").show
在聚集函数遇到空值时,除count(*)外,都跳过空值而只处理非空值。注意,where子句中是不能用聚集函数作为条件表达式的。
5.GROUP BY子句
GROUP BY子句将查询的结果按某一列或者多列的值分组,值相等的为一组。
//求各个课程号及相对应的选课人数
hc.sql("select Cno,count(Sno) from SC group by Cno").show
如果分组后还要求按一定的条件对这些组进行筛选,最终只输出满足指定条件的组,则可以使用Having短语指定筛选条件。
//查询选修了3门以上课程的学生学号
hc.sql("select Sno from SC group by Sno having count(*)>2").show
5.2连接查询
前面的查询都是针对一个表进行的。如一个查询结果同时涉及两个以上的表,则称之为连接查询
1.等值与非等值连接查询
连接查询的where子句中用来连接两个表的条件称之为连接条件或连接谓词,其一般的格式为:
[<表名1>.]<列名1> <比较运算符> [<表名2>.]<列名2>
//查询每个学生及其选修课程的情况
hc.sql("select student.*,sc.* from student,sc where student.Sno = sc.Sno").show
若在等值连接中把目标列中重复的属性列去掉则为自然连接
2.外连接
hc.sql("select student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade from student left out join sc on (student.Sno = sc.Sno)").show
左外连接列出左边关系(如本例student)中所有的元组,右外连接列出右边关系中所有的元组。
3.复合条件连接
where子句中只有一个条件,即连接谓词。where子句中可以有多个连接条件,称为复合条件连接
4.嵌套查询
在SQL语言中,一个select-from-where
语句称为一个查询块。将一个查询块嵌套在另一个查询块的where子句或Having短语的条件中的查询称为嵌套查询。
hc.sql("select Sname from student where Sno in (select Sno from sc where Cno ='2')").show
带有IN谓词的子查询
//查询选修了课程名为“信息系统”的学生号和姓名
hc.sql("select Sno,Sname //3.最后在student关系中取出Sno和Sname
from student
where Sno in
( select Sno //2.然后在sc关系中找出选修了3号课程的学
from sc //生的学号
where Cno in
( select Cno //1.首先在course关系中找出“信息系统”的课
from course //程号,结果为3号
where Cname = '信息系统'
)
))").show
带有比较运算符的子查询
//找出每个学生超过他选修课程平均成绩的课程号
hc.sql("select Sno,Cno from sc x where Grade >= ( select avg(Grade) from sc y where y.Sno = x.Sno)").show
带有ANY(SOME)或ALL谓词的子查询
子查询返回单值时可以用比较运算符,但返回多值时要用ANY(SOME)或ALL谓词修饰词
//查询其他系中比计算机科学系某一学生年龄小的学生姓名和年龄
hc.sql("select Sname,Sage from student where Sage < ANY (select Sage from student where Sdept ='CS') AND Sdept <> 'CS'").show
带有EXISTS谓词的子查询
EXISTS代表存在量词。带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真“true”或逻辑假值“false”
//查询所有选修了1号课程的学生姓名
hc.sql("select Sname from student where exists (select * from sc where Sno = student.Sno and Cno ='1')").show
由EXISTS引出的子查询,其目标列表达式通常用*,因为带EXISTS的子查询只返回真值或假值,给出列名无实际意义。
//查询选修了全部课程的学生姓名
hc.sql("select sname from student where not exists(select * from course where not exists(select * from sc where sno = sc.sno and sc.cno =course.cno))").show;
//查询至少选修了学生201215122选修的全部课程的学生学号
hc.sql("select distinct Sno from sc scx where not exists (select * from sc scy where scy.sno ='201215122' and not exists (select * from sc scz where scz.sno=scx.sno and scz.cno = scy.cno))").show;
以上两条查询语句报如下错误(** 待解决 **):
org.apache.spark.sql.AnalysisException: cannot resolve '`scx.sno`' given input columns: [sno, cno, grade]; line 1 pos 149;
//查询没有选修1号课程的学生姓名
hc.sql("select sname from student where not exists (select * from sc where sno=student.sno and cno='1')").show;
集合查询
select语句的查询结果是元组的集合,所以多个select语句的结果可进行集合操作。集合操作主要包含并操作UNION、交操作INTERSECT和差操作EXCEOTP。注意,参加集合操作的各查询结果的列数必须相同,对应项的数据类型也必须相同。
//查询计算机科学系的学生及年龄不大于19岁的学生
hc.sql("select * from student where Sdept='CS' UNION select * from student where Sage <=19").show
6.数据更新
6.1插入数据
SQL的数据插入语句INSERT通常有两种形式。一种是插入一个元组,另一种是插入子查询的结果。后者可以一次插入多个元组。
//将一个新学生元组(学号:200215128;姓名:陈冬;性别:男;所在系:IS;年龄:18)插入到student表中
hc.sql("insert into student values('200215128','周坚','男','18','IS')").show
6.2数据修改(已验证--hive不支持)
Hive不能delete和update的原因
ACID stands for four traits of database transactions: Atomicity (an operation either succeeds completely or fails, it does not leave partial data), Consistency (once an application performs an operation the results of that operation are visible to it in every subsequent operation), Isolation (an incomplete operation by one user does not cause unexpected side effects for other users), and Durability (once an operation is complete it will be preserved even in the face of machine or system failure). These traits have long been expected of database systems as part of their transaction functionality.
其功能是修改指定表中满足where子句条件的元组。
//将学生200215121的年龄修改为22岁
hc.sql("update student set Sage = 22 where Sno ='200215121'").show
//将计算机科学系全体学生的成绩置零
hc.sql("update sc set Grade =0 where 'CS'= (select sdept from student where student.Sno = sc.Sno)").show
6.3删除数据(已验证--hive不支持)
//删除学号为200215128的学生记录
hc.sql("delete from student where Sno='200215128'").show
参考资料
http://dblab.xmu.edu.cn/blog/1086-2/