表名:score; 表结构:uid,subject_id,score
求:找出所有科目成绩都大于某一学科平均成绩的学生数据集如下
1001 | 01 | 90 |
1001 | 02 | 90 |
1001 | 03 | 90 |
1002 | 01 | 85 |
1002 | 02 | 85 |
1002 | 03 | 70 |
1003 | 01 | 70 |
1003 | 02 | 70 |
1003 | 03 | 85 |
数据
insert into score values('1001','01',90);
insert into score values('1001','02',90);
insert into score values('1001','03',90);
insert into score values('1002','01',85);
insert into score values('1002','02',85);
insert into score values('1002','03',70);
insert into score values('1003','01',70);
insert into score values('1003','02',70);
insert into score values('1003','03',85);
1) 建表语句
create table score (
uid string,
subject_id string,
score int)
row format delimited fields terminated by '\t';
2) 求出每个学科的平均成绩
select u_id, score, avg(score) over(partition by subject_id) avg_score
from score; t1
3) 根据是否大于平均成绩记录flag,大于则记为0否则记为1
select uid, if (score>avg_score,0,1) flag
from t1; t2
4) 根据学生id分组统计flag的和,和为0则是所有学科都大于平均成绩
select uid
from t2
group by uid
having sum(flag) = 0;
5) 最终SQL
select uid
from
(
select uid, if (score>avg_score,0,1) flag
from
(
select uid, score, avg(score) over(partition by subject_id) avg_score
from score
) t1
) t2
group by uid
having sum(flag) = 0;
我们有如下的用户访问数据
userId |
visitDate |
visitCount |
u01 |
2017/1/21 |
5 |
u02 |
2017/1/23 |
6 |
u03 |
2017/1/22 |
8 |
u04 |
2017/1/20 |
3 |
u01 |
2017/1/23 |
6 |
u01 |
2017/2/21 |
8 |
u02 |
2017/1/23 |
6 |
u01 |
2017/2/22 |
4 |
要求使用SQL统计出每个用户的累积访问次数,如下表所示:
用户id |
月份 |
小计 |
累积 |
u01 |
2017-01 |
11 |
11 |
u01 |
2017-02 |
12 |
23 |
u02 |
2017-01 |
12 |
12 |
u03 |
2017-01 |
8 |
8 |
u04 |
2017-01 |
3 |
3 |
数据
insert into action values('u01','2017/1/21',5);
insert into action values('u02','2017/1/23',6);
insert into action values('u03','2017/1/22',8);
insert into action values('u04','2017/1/20',3);
insert into action values('u01','2017/1/23',6);
insert into action values('u01','2017/2/21',8);
insert into action values('u02','2017/1/23',6);
insert into action values('u01','2017/2/22',4);
1) 建表语句
create table action (
userId string,
visitDate string,
visitCount int)
row format delimited fields terminated by '\t';
2) 修改数据格式
select userId, date_format(regexp_replace(visitDate, '/', '-'), 'yyyy-MM') mn, visitCount
from action; t1
3) 计算每人单月访问量
select userId, mn, sum(visitCount) mn_count
from t1
group by userId, mn; t2
4) 按月累计访问量
select userId, mn, mn_count, sum(mn_count) over(partition by userId order by mn)
from t2;
5) 最终SQL
select userId, mn, mn_count, sum(mn_count) over(partition by userId order by mn)
from
(
select userId, mn, sum(visitCount) mn_count
from
(
select userId, date_format(regexp_replace(visitDate,'/','-'),'yyyy-MM') mn, visitCount
from action
) t1
group by userId, mn
) t2;
有50W个京东店铺,每个顾客访客访问任何一个店铺的任何一个商品时都会产生一条访问日志,访问日志存储的表名为visit,访客的用户id为user_id,被访问的店铺名称为shop,请统计:
1)每个店铺的UV(访客数)
2)每个店铺访问次数top3的访客信息。输出店铺名称、访客id、访问次数
数据
insert into visit values(3,'女装');
insert into visit values(4,'女装');
insert into visit values(5,'女装');
insert into visit values(6,'女装');
insert into visit values(7,'女装');
insert into visit values(8,'女装');
insert into visit values(8,'女装');
insert into visit values(9,'女装');
insert into visit values(10,'女装');
insert into visit values(11,'女装');
insert into visit values(1,'男装');
insert into visit values(1,'男装');
insert into visit values(1,'男装');
insert into visit values(1,'男装');
insert into visit values(2,'男装');
insert into visit values(3,'男装');
insert into visit values(4,'男装');
1) 建表语句
create table visit (
user_id string,
shop string)
row format delimited fields terminated by '\t';
2) 每个店铺的UV(访客数)
select shop, count(distinct user_id)
from visit
group by shop;
3) 每个店铺访问次数top3的访客信息。输出店铺名称、访客id、访问次数
一个访客可以多次访问一个店铺
3.1) 查询每个店铺被每个用户访问的次数
select shop, user_id, count(*) as cnt
from visit
group by shop, user_id; t1
3.2) 计算每个店铺被用户访问的排名
select shop, user_id, cnt, rank() over (partition by shop order by cnt desc) rk
from t1; t2
3.3) 取每个店铺前三名
select shop, user_id, cnt
from
(
select shop, user_id, cnt, rank() over (partition by shop order by cnt desc) rk
from
(
select shop, user_id, count(*) cnt
from visit
group by shop, user_id
) t1
) t2
where rk <= 3;
已知一个表STG.ORDER(order_tab),有如下字段: dt,order_id,user_id,amount。请给出sql进行统计:数据样例:2017-01-01,10029028,1000003251,33.57。
1)给出 2017年每个月的订单数、用户数、总成交金额。
2)给出2017年11月的新客数(指在11月才有第一笔订单)
数据
insert into order_tab values('2017-01-01', '10029028', '1000003251', 33.57);
1) 建表语句
create table order_tab (
dt string,
order_id string,
user_id string,
amount decimal(10,2))
row format delimited fields terminated by '\t';
2) 给出 2017年每个月的订单数、用户数、总成交金额。
订单号不会重复
select date_format(dt,'yyyy-MM'), count(order_id), count(distinct user_id), sum(amount)
from order_tab
where date_format(dt,'yyyy') = '2017'
group by date_format(dt,'yyyy-MM');
3) 给出2017年11月的新客数(指在11月才有第一笔订单)
select count(user_id)
from order_tab
group by user_id
having date_format(min(dt), 'yyyy-MM') = '2017-11'
有一个5000万的用户文件(user_id,name,age) user_file,一个2亿记录的用户看电影的记录文件(user_id,url) film file,根据年龄段(每隔10岁算一个年龄段)观看电影的次数进行排序?
数据准备
INSERT INTO TABLE user_file VALUES ('001', 'u1', 10);
INSERT INTO TABLE user_file VALUES ('002', 'u2', 15);
INSERT INTO TABLE user_file VALUES ('003', 'u3', 15);
INSERT INTO TABLE user_file VALUES ('004', 'u4', 20);
INSERT INTO TABLE user_file VALUES ('005', 'u5', 25);
INSERT INTO TABLE user_file VALUES ('006', 'u6', 35);
INSERT INTO TABLE user_file VALUES ('007', 'u7', 40);
INSERT INTO TABLE user_file VALUES ('008', 'u8', 45);
INSERT INTO TABLE user_file VALUES ('009', 'u9', 50);
INSERT INTO TABLE user_file VALUES ('0010', 'u10', 65);
INSERT INTO TABLE film_file VALUES ('001', 'url1');
INSERT INTO TABLE film_file VALUES ('002', 'url1');
INSERT INTO TABLE film_file VALUES ('003', 'url2');
INSERT INTO TABLE film_file VALUES ('004', 'url3');
INSERT INTO TABLE film_file VALUES ('005', 'url3');
INSERT INTO TABLE film_file VALUES ('006', 'url1');
INSERT INTO TABLE film_file VALUES ('007', 'url5');
INSERT INTO TABLE film_file VALUES ('008', 'url7');
INSERT INTO TABLE film_file VALUES ('009', 'url5');
INSERT INTO TABLE film_file VALUES ('0010', 'url1');
1) 建表语句
create table user_file (
user_id string,
name string,
age int)
row format delimited fields terminated by '\t';
create table film_file (
user_id string,
url string)
row format delimited fields terminated by '\t';
2) 需要按年龄段进行排序,所以要先按照年龄段进行细分
select user_id,
case when age <= 10 and age > 0 then '0-10'
when age <= 20 and age > 10 then '10-20'
when age <= 30 and age > 20 then '20-30'
when age <= 40 and age > 30 then '30-40'
when age <= 50 and age > 40 then '40-50'
when age <= 60 and age > 50 then '50-60'
when age <= 70 and age > 60 then '60-70'
else '70+' end as 'age-stage'
from user_file;
3) 各年龄段的用户看电影的次数,需要将用户文件与记录文件连接,分组排序
select u.user_id, count(*)
from film_file f
left join
(
select user_id,
case when age <= 10 and age > 0 then '0-10'
when age <= 20 and age > 10 then '10-20'
when age <= 30 and age > 20 then '20-30'
when age <= 40 and age > 30 then '30-40'
when age <= 50 and age > 40 then '40-50'
when age <= 60 and age > 50 then '50-60'
when age <= 70 and age > 60 then '60-70'
else '70+' end as 'age_stage'
from user_file
) u
on f.user_id = u.user_id
group by age_stage
order by count(*);
有日志如下,请写出代码求得所有用户和活跃用户的总数及平均年龄。(活跃用户指连续两天都有访问记录的用户)user_file字段(date,user_id,age)
dt user_id age
2019-02-11,test_1,23
2019-02-11,test_2,19
2019-02-11,test_3,39
2019-02-11,test_1,23
2019-02-11,test_3,39
2019-02-11,test_1,23
2019-02-12,test_2,19
2019-02-13,test_1,23
2019-02-15,test_2,19
2019-02-16,test_2,19
2019-02-17,test_4,35
2019-02-18,test_4,35
2019-02-22,test_4,35
2019-02-23,test_4,35
数据
insert into table user_file values ('2019-02-11','test_1',23)
insert into table user_file values ('2019-02-11','test_2',19)
insert into table user_file values ('2019-02-11','test_3',39)
insert into table user_file values ('2019-02-11','test_1',23)
insert into table user_file values ('2019-02-11','test_3',39)
insert into table user_file values ('2019-02-11','test_1',23)
insert into table user_file values ('2019-02-12','test_2',19)
insert into table user_file values ('2019-02-13','test_1',23)
insert into table user_file values ('2019-02-15','test_2',19)
insert into table user_file values ('2019-02-16','test_2',19)
insert into table user_file values ('2019-02-17','test_4',35)
insert into table user_file values ('2019-02-18','test_4',35)
insert into table user_file values ('2019-02-22','test_4',35)
insert into table user_file values ('2019-02-23','test_4',35)
1) 建表语句
create table user_age (
dt string,
user_id string,
age int)
row format delimited
fields terminated by ','
lines terminated by '\n'
stored as textfile;
2) 按照日期以及用户分组,按照日期排序并给出排名
由于同一个用户在每天可能登录多次,计算活跃用户数时每天登陆一次就算今日活跃过了,所以要对每日重复登陆的用户去重(日期和用户算一组),去重方式两种:
第一种:group by和窗口函数可以一块使用,先对数据聚合,在聚合的基础上再执行窗口函数
如果使用了group by 就需要与聚合函数(sum,max,min,avg,count)一起使用
select user_id, dt, rank() over (partition by user_id order by dt) rk, min(age) age
from user_file
group by user_id, dt; t1
第二种:通过子查询的方式
select t1.user_id, t1.dt, row_number() over(partition by t1.user_id order by t1.dt) rm, t1.age
from
(
select distinct user_id, dt, age
from user_file
) t1;
结果如下:
user_id dt rk age
test_1 2019-02-11 1 23
test_1 2019-02-13 2 23
test_2 2019-02-11 1 19
test_2 2019-02-12 2 19
test_2 2019-02-15 3 19
test_2 2019-02-16 4 19
test_3 2019-02-11 1 39
test_4 2019-02-17 1 35
test_4 2019-02-18 2 35
test_4 2019-02-22 3 35
test_4 2019-02-23 4 35
这里面由于同一个用户日期没有重复数据,所以这里rank()和row_number()结果一样
3) 计算日期(dt)及排名(rk)的差值,在连续登陆的情况下,每次相减的结果都相同
我们可以使用DATE_SUB() 函数从日期减去指定的时间间隔。
select user_id, dt, rk, date_sub(dt,rk) flag, age
from t1; t2
结果如下:
user_id dt rk flag age
test_1 2019-02-11 1 2019-02-10 23
test_1 2019-02-13 2 2019-02-11 23
test_2 2019-02-11 1 2019-02-10 19
test_2 2019-02-12 2 2019-02-10 19
test_2 2019-02-15 3 2019-02-12 19
test_2 2019-02-16 4 2019-02-12 19
test_3 2019-02-11 1 2019-02-10 39
test_4 2019-02-17 1 2019-02-16 35
test_4 2019-02-18 2 2019-02-16 35
test_4 2019-02-22 3 2019-02-19 35
test_4 2019-02-23 4 2019-02-19 35
4) 过滤出差值个数大于等于 2 的,即为连续两天活跃的用户
select user_id, min(age) age
from t2
group by user_id, flag
having count(*) >= 2; t3
连续登陆3天算活跃用户,就count(*)>=3;
连续登陆4天算活跃用户,就count(*)>=4;
连续登陆5天算活跃用户,就count(*)>=5;
以此逻辑类推;
5) 对数据进行去重处理(一个用户可以在两个不同的时间点连续登录),例如:a 用户在 1
月 10 号 1 月 11 号以及 1 月 20 号和 1 月 21 号 4 天登录。
select user_id, min(age) age
from t3
group by user_id; t4
6) 计算活跃用户的人数(两天连续有访问)及平均年龄
聚合函数不仅限于分组查询,如果只使用聚合函数,没有group by,则聚合函数是用于聚合整个结果集(匹配WHERE子句的所有行)
CAST(expression AS data_type) 在这里是保留总共10位数,其中小数位是2位
select count(*) cnt, cast(sum(age)/count(*) as decimal(10,2))
from t4;
7) 对全量数据进行按照用户去重(一个用户在一天登录多次)
select user_id, min(age) age
from user_file
group by user_id; t5
计算所有用户的数量及平均年龄
select count(*) cnt, cast(sum(age)/count(*) as decimal(10,1))
from t5;
8) 将第5步(t4)以及第7步(t5)两个数据集进行union all(活跃用户和所有用户)
select sum(user_total_count), sum(user_total_avg_age), sum(twice_count), sum(twice_count_avg_age)
from
(
select 0 user_total_count, 0 user_total_avg_age, count(*) twice_count, cast(sum(age)/count(*) as decimal(10,2)) twice_count_avg_age
from
(
select user_id, min(age) age
from
(
select user_id, min(age) age
from
(
select user_id, dt, rk, date_sub(dt,rk) flag, age
from
(
select user_id, dt, rank() over (partition by user_id order by dt) rk, min(age) age
group by user_id, dt
) t1
) t2
group by user_id, flag
having count(*) >= 2
) t3
group by user_id
) t4
union all
select count(*) user_total_count, cast(sum(age)/count(*) as decimal(10,1)) user_total_avg_age, 0 twice_count, 0 twice_count_avg_age
from
(
select user_id, min(age) age
from user_file
group by user_id
) t5
) t6
请用sql写出所有用户中在今年10月份第一次购买商品的金额,表ordertable字段(购买用户:userid,金额:money,购买时间:paymenttime(格式:2017-10-01),订单id:orderid)
数据
insert into table ordertable values('001',100,'2017-10-01','123123');
insert into table ordertable values('001',200,'2017-10-02','123124');
insert into table ordertable values('002',500,'2017-10-01','222222');
insert into table ordertable values('001',100,'2017-11-01','123123');
1) 建表语句
create table ordertable (
userid string,
money int,
paymentime string,
orderid string
);
2) 查询出‘2017-10’中最早的日期
select user_id, min(paymenttime) paymenttime
from ordertable
where date_format(paymenttime, 'yyyy-MM') = '2017-10'
group by user_id; t1
3) 方法1:连接查询
select t1.user_id, o.money
from
(
select user_id, min(paymenttime) paymenttime
from ordertable
where date_format(paymenttime = '2017-10')
group by user_id
) t1
join ordertable o
on t1.user_id = o.user_id and t1.paymenttime = o.paymenttime;
方法2:窗口函数
① 对每个用户的购买时间进行排名
select user_id, money, row_number() over(partition by user_id order by paymenttime) rm
from ordertable
where date_format(paymenttime, 'yyyy-MM' = '2017-10'); t1
② 筛选出用户在2017年10月第一次购买商品,即rm=1
select user_id,money
from
(
select user_id, money, row_number() over(partition by user_id order by paymenttime)
from ordertable
where date_format(paymenttime, 'yyyy-MM') = '2017-10'
) t1
where rm = 1;
有一个线上服务器访问日志格式如下(用sql答题)
时间 接口 ip地址
2016-11-09 14:22:05 /api/user/login 110.23.5.33
2016-11-09 14:23:10 /api/user/detail 57.3.2.16
2016-11-09 15:59:40 /api/user/login 200.6.5.166
… …
求11月9号下午14点(14-15点),访问/api/user/login接口的top10的ip地址
数据
insert into table ip values('2016-11-09 11:22:05','/api/user/login','110.23.5.23');
insert into table ip values('2016-11-09 11:23:10','/api/user/detail','57.3.2.16');
insert into table ip values('2016-11-09 23:59:40','/api/user/login','200.6.5.166');
insert into table ip values('2016-11-09 11:14:23','/api/user/login','136.79.47.70');
insert into table ip values('2016-11-09 11:15:23','/api/user/detail','94.144.143.141');
insert into table ip values('2016-11-09 11:16:23','/api/user/login','197.161.8.206');
insert into table ip values('2016-11-09 12:14:23','/api/user/detail','240.227.107.145');
insert into table ip values('2016-11-09 13:14:23','/api/user/login','79.130.122.205');
insert into table ip values('2016-11-09 14:14:23','/api/user/detail','65.228.251.189');
insert into table ip values('2016-11-09 14:15:23','/api/user/detail','245.23.122.44');
insert into table ip values('2016-11-09 14:17:23','/api/user/detail','22.74.142.137');
insert into table ip values('2016-11-09 14:19:23','/api/user/detail','54.93.212.87');
insert into table ip values('2016-11-09 14:20:23','/api/user/detail','218.15.167.248');
insert into table ip values('2016-11-09 14:24:23','/api/user/detail','20.117.19.75');
insert into table ip values('2016-11-09 15:14:23','/api/user/login','183.162.66.97');
insert into table ip values('2016-11-09 16:14:23','/api/user/login','108.181.245.147');
insert into table ip values('2016-11-09 14:17:23','/api/user/login','22.74.142.137');
insert into table ip values('2016-11-09 14:19:23','/api/user/login','22.74.142.137');
1) 建表语句
create table ip (
time string,
interface string,
ip string)
row format delimited fields terminated by '\t'
2) 查询语句
select ip, count(*) cnt
from ip
where date_format(time, 'yyyy-MM-dd HH') >= '2016-11-09 14' and date_format(time, 'yyyy-MM-dd HH') <= '2016-11-09 15' and interface = '/api/user/login'
group by ip
order by cnt desc
limit 10;
有一个账号表如下,请写出SQL语句,查询各自区组的money排名前十的账号(分组取前10)
1) 建表语句
CREATE TABLE account (
`dist_id` int(11) default null COMMENT '区组id',
`account` varchar(100) default null COMMENT '账号',
`gold` int(11) default 0 COMMENT '金币',
PRIMARY KEY (`dist_id`, `account_id`)
) ENGINE=InnoDB DEFAULT CHARSET-utf8;
2) 查询语句
① 对各区组的money进行排名
select dist_id, account, gold, row_number() over (partition by dist_id order by gold desc) rm
from account; t1
② 查询各区组排名前十的账号
select t1.dist_id, t1.account, t1.gold
from
(
select dist_id, account, gold, row_number() over (partition by dist_id order by gold desc) rm
from account
) t1
where rm <= 10;
有一个充值日志表如下:
CREATE TABLE `credit_log`
(
`dist_id` int(11)DEFAULT NULL COMMENT '区组id',
`account` varchar(100)DEFAULT NULL COMMENT '账号',
`money` int(11) DEFAULT NULL COMMENT '充值金额',
`create_time` datetime DEFAULT NULL COMMENT '订单时间'
) ENGINE=InnoDB DEFAUILT CHARSET-utf8
请写出SQL语句,查询充值日志表2015年7月9号每个区组下充值额最大的账号,要求结果:
区组id,账号,金额,充值时间
1) 对2015年7月9号每个区组账号充值金额排序(未考虑重复充值,考虑的话先group by再排名,增加了一层查询)
select dist_id, account, money, create_time, row_number() over (partition by dist_id order bv money desc) rm
from credit_log
where date_format(create_time, 'yyyy-MM-dd') = '2015-07-09'; t1
2) 查询每个区充值最大的账号 (这里面只取了一行,可能有多个最大,与面试官确认需求)
select t1.dist_id, t1.account, t1.money, t1.create_time
from
(
select dist_id, account, money, create_time, row_number() over (partition by dist_id order bv money desc) rm
from credit_log
where date_format(create_time, 'yyyy-MM-dd') = '2015-07-09'
) t1
where rm = 1;
1)有三张表分别为会员表(member)销售表(sale)退货表(regoods)
(1)会员表有字段memberid(会员id,主键)credits(积分);
(2)销售表有字段memberid(会员id,外键)购买金额(MNAccount);
(3)退货表中有字段memberid(会员id,外键)退货金额(RMNAccount);
2)业务说明:
(1)销售表中的销售记录可以是会员购买,也可是非会员购买。(即销售表中的memberid可以为空)
(2)销售表中的一个会员可以有多条购买记录
(3)退货表中的退货记录可以是会员,也可是非会员
(4)一个会员可以有一条或多条退货记录
查询需求:分组查出销售表中所有会员购买金额,同时分组查出退货表中所有会员的退货金额,把会员id相同的购买金额-退款金额得到的结果更新到会员表中对应会员的积分字段(credits)
数据
insert into sale values(1,345.9);
insert into sale values(13,435.9);
insert into sale values(13,245.9);
insert into sale values(23,435.9);
insert into sale values(32,345.9);
insert into sale values(33,345.9);
insert into sale values(null,345.9);
insert into regoods values(1,256.9);
insert into regoods values(12,526.9);
insert into regoods values(12,516.9);
insert into regoods values(22,546.9);
insert into regoods values(32,156.9);
insert into regoods values(32,256.9);
insert into regoods values(null,256.9);
1) 建表语句
create table member(memberid string,credits double) row format delimited fields terminated by '\t';
create table sale(memberid string,MNAccount double) row format delimited fields terminated by '\t';
create table regoods(memberid string,RMNAccount double) row format delimited fields terminated by '\t';
2) 查询语句
insert into table member
select t1.memberid memberid, t1.MNAccount-t2.RMNAccount credits
from
(
select memberid, sum(MNAccount) MNAccount
from sale
where memeberid != ' '
group by memberid
) t1
join
(
select memberid, sum(RMNAccount) RMNAccount
from regoods
where memeberid != ' '
group by memberid
) t2
on t1. memeberid = t2.memberid
SQL表user_time中字段是user_id , time(用户访问时间), 求每个用户相邻两次浏览时间之差小于三分钟的次数。
数据
insert into user_time values(1,'2020-05-07 21:13:07');
insert into user_time values(1,'2020-05-07 21:15:26');
insert into user_time values(1,'2020-05-07 21:17:44');
insert into user_time values(2,'2020-05-13 21:14:06');
insert into user_time values(2,'2020-05-13 21:18:19');
insert into user_time values(2,'2020-05-13 21:20:36');
insert into user_time values(3,'2020-05-21 21:16:51');
insert into user_time values(4,'2020-05-16 22:22:08');
insert into user_time values(4,'2020-05-02 21:17:22');
insert into user_time values(4,'2020-05-30 15:15:44');
insert into user_time values(4,'2020-05-30 15:17:57');
1) 建表语句
create table user_time (
user_id string,
time datetime
);
2) 查询语句
WITH next_view AS (
SELECT user_id, time, LEAD(time, 1) OVER (PARTITION BY user_id ORDER BY time) AS next_time
FROM user_time),
view_diff AS (
SELECT user_id, TIMESTAMPDIFF(SECOND, time, next_time) AS diff
FROM next_view);
SELECT user_id, COUNT(*)
FROM view_diff
WHERE diff < 180
GROUP BY user_id;
上面查询语句不会显示次数为0的用户,如果要显示,最后一句查询语句修改如下:
SELECT user_id,
COUNT(CASE WHEN diff < 180 THEN user_id ELSE NULL END) AS count
FROM view_diff
GROUP BY user_id;
表名为score:用一条 SQL 语句查询出每门课都大于 80 分的学生姓名
name kecheng fenshu
张三 语文 81
张三 数学 75
李四 语文 76
李四 数学 90
王五 语文 81
王五 数学 100
王五 英语 90
方法1:子查询
select distinct name
from score
where name not in
(
select distinct name
from score
where fenshu <= 80
)
方法2: group by和having
select distinct name
from score
group by name
having min(fenshu) > 80;
学生表 student 如下:
自动编号 学号 姓名 课程编号 课程名称 分数
1 2005001 张三 0001 数学 69
2 2005002 李四 0001 数学 89
3 2005001 张三 0001 数学 69
删除除了自动编号不同, 其他都相同的学生冗余信息
delete student where 自动编号 not in
(
select min(自动编号)
from student
group by 学号, 姓名, 课程编号, 课程名称, 分数
)
一个叫 team 的表,里面只有一个字段 name,一共有 4 条纪录,分别是 a,b,c,d,对应四个球队,现在四个球队进行比赛,用一条 sql 语句显示所有可能的比赛组合.
select a.name, b.name
from team a, team b
where a.name < b.name;
怎么把这样一个表
year month amount
1991 1 1.1
1991 2 1.2
1991 3 1.3
1991 4 1.4
1992 1 2.1
1992 2 2.2
1992 3 2.3
1992 4 2.4
查成这样一个结果
year m1 m2 m3 m4
1991 1.1 1.2 1.3 1.4
1992 2.1 2.2 2.3 2.4
查询语句如下:
select year,
(select amount from aaa m where aaa.year = m.year and m.month = 1) m1,
(select amount from aaa m where aaa.year = m.year and m.month = 2) m2,
(select amount from aaa m where aaa.year = m.year and m.month = 3) m3,
(select amount from aaa m where aaa.year = m.year and m.month = 4) m4
from aaa
group by year;
说明:复制表(只复制结构, 源表名:a 新表名:b)
SQL: where1=1,拷贝表结构和数据内容
select * into b from a where 1<>1;
ORACLE:
create table b as
select * from a where 1=2;
<>(不等于)(SQL Server Compact):比较两个表达式;当使用此运算符比较非空表达式时,如果左操作数不等于右操作数,则结果为true;否则,结果为false
原表
courseid coursename score
1 java 70
2 oracle 90
3 xml 40
4 jsp 30
5 servlet 80
为了便于阅读,查询此表后的结果显式如下(及格分数为 60):
courseid coursename score mark
1 java 70 pass
2 oracle 90 pass 3 xml 40 fail
4 jsp 30 fail
5 servlet 80 pass
select courseid, coursename, score, if(score>=60,"pass","fail") mark
from course;
表名:购物信息
购物人 商品名称 数量
A 甲 2
B 乙 4
C 丙 1
A 丁 2
B 丙 5
……
给出所有购入商品为两种或两种以上的购物人记录
select *
from 购物信息
where 购物人 in
(
select 购物人
from 购物信息
group by 购物人
having count(*) >=2
);
info表
date result
2005-05-09 win
2005-05-09 lose
2005-05-09 lose
2005-05-09 lose
2005-05-10 win
2005-05-10 lose
2005-05-10 lose
如果要生成下列结果, 该如何写 sql 语句?
win lose
2005-05-09 2 2
2005-05-10 1 2
方法1:聚合函数+case when
select date,
sum(case when result = "win" then 1 else 0 end) as "win",
sum(case when result = "lose" then 1 else 0 end) as "lose"
from info
group by date;
方法2:连接查询
select a.date, a.result, b.result
from
(
select date, count(*) result
from info
where result = 'win'
group by date
) a
join
(
select date, count(*) result
from info
where result = 'lose'
group by date
) b
on a.date = b.date
有一个订单表 order。已知字段有:order_id(订单 ID), user_id(用户ID),amount(金额), pay_datetime(付费时间),channel_id(渠道 ID),dt(分区字段)。
1) 在 Hive 中创建这个表。
create external table order (
order_id int,
user_id int,
amount double,
pay_datetime timestamp,
channel_id int
)partitioned by(dt string)
row format delimited fields terminated by '\t';
2) 查询 dt=‘2018-09-01‘里每个渠道的订单数,下单人数(去重),总金额。
select count(order_id), count(distinct (user_id)), sum(amount)
from order
where dt = '2018-09-01';
3) 查询 dt=‘2018-09-01‘里每个渠道的金额最大 3 笔订单。
select
count(order_id),
count(distinct(user_id)),
sum(amount)
from order
where dt="2019-09-01"
select
order_id,
channel_id,
channel_id_amount
from(
select
order_id
channel_id,
amount,
max(amount) over(partition by channel_id),
min(amount) over(partition by channel_id),
row_number() over(partition by channel_id order by amount desc) ranks
from order
where dt="2019-09-01"
) t
where t.ranks<4;
4) 有一天发现订单数据重复,请分析原因
订单属于业务数据,在关系型数据库中不会存在数据重复hive 建表时也不会导致数据重复,
我推测是在数据迁移时,迁移失败导致重复迁移数据冗余了
手写HQL第二十二题
有一个订单表t_order,已知字段有:order_id(订单ID),item_id(商品id),create_time(下单时间),amount(下单金额)
有一个商品表t_item,已知字段有:item_id(商品id),item_name(商品名称),category(品类)
有一个商品表t_item,已知字段有:item_id(商品id),item_name(商品名称),category_1(一级品类),category_2(二级品类)
需求:
1) 最近一个月,销售数量最多的 10 个商品
select item_id, count(order_id)
from t_order
where datediff(creat_time,current_date) <= 30
group by item_id
order by count(order_id) desc
limit 10;
2) 最近一个月,每个种类里销售数量最多的 10 个商品 # 一个订单对应一个商品 一个商品对应一个品类
with cte as (
select order_id, item_id, item_name, category
from t_order t1
join t_item t2 on t1.item_id = t2.item_id
)
select order_id, item_id, item_name, category, count(item_id partition by category) item_count,
from cte
group by category
order by item_count desc
limit 10;
计算平台的每一个用户发过多少日记、获得多少点赞数
t1:10万行数据
uid(用户id) log_id(日记id)
uid1 log_id1
uid2 log_id2
uid3 log_id3
......t2:1000万行数据(注:没有被点赞的日志此表不做记录)
log_id(日记id) like_uid(点赞的用户id)
log_id1 uid2
log_id1 uid3
log_id1 uid4
log_id3 uid2
......结果如下:
uid(用户id) log_cnt(发过多少日记) liked_cnt(获得多少点赞)
uid1 2 3
uid2 1 1 ......
with cte as (
select t1.uid, t1.log_id, t2.like_uid
from t1
left join t2 on t1.log_id = t2.log_id
)
select uid,
count(log_id) over(partition by uid) log_cnt,
count(like_uid) over(partition by uid) liked_cnt
from cte;
处理产品版本号,版本号信息存储在数据表中,每行一个版本号
版本号命名规则:产品版本号由三部分组成,如:v9.11.2
第一部分9为主版本号,为1-99之间的数字;第二部分11为子版本号,为0-99之间的数字;第三部分2为阶段版本号,为0-99之间的数字(可选)
已知t1表有若干个版本号:
version_id(版本号)
v9.9.9
v8.1
v9.9.2
v9.20
v31.0.1 ......
1、需求 A:找出 t1 表中最大的版本号
2、需求 B:计算出如下格式的所有版本号排序,要求对于相同的版本号,顺序号并列:
version_id(版本号) seq(顺序号)
v31.0.1 0
v9.20 1
v9.9.2 2
v9.9.2 2
v9.0.8 4 ......
现在有三个表student(学生表)、course(课程表)、score(成绩单),结构如下:
create table student(
id bigint comment '学号',
name string comment '姓名',
age bigint comment '年龄');
create table course(
cid string comment '课程号,001/002格式',
cname string comment '课程名');
create table score(
id bigint comment '学号',
cid string comment '课程号',
score bigint comment '成绩'
) partitioned by(event_day string);
数据
insert into table student values(1001,'wsl1',21);
insert into table student values(1002,'wsl2',22);
insert into table student values(1003,'wsl3',23);
insert into table student values(1004,'wsl4',24);
insert into table student values(1005,'wsl5',25);
insert into table course values('001','math');
insert into table course values('002','English');
insert into table course values('003','Chinese');
insert into table course values('004','music');
insert into table score values(1001,'004',10);
insert into table score values(1002,'003',21);
insert into table score values(1003,'002',32);
insert into table score values(1004,'001',43);
insert into table score values(1005,'003',54);
insert into table score values(1001,'002',65);
insert into table score values(1002,'004',76);
insert into table score values(1003,'002',77);
insert into table score values(1001,'004',48);
insert into table score values(1002,'003',39);
其中score中的id、cid,分别是student、course中对应的列请根据上面的表结构,回答下面的问题:
① 请将本地文件(/home/users/test/20190301.csv)文件,加载到分区表score的20190301分区中,并覆盖之前的数据
load data local inpath '/home/users/test/20190301.csv' overwrite into table score partition(event_day='20190301');
② 查出平均成绩大于60分的学生的姓名、年龄、平均成绩
select
stu.name,
stu.age,
stu.avg_score
from student stu
join(
select
id,
avg(score) avg_score
from score
group by id
) t1
on stu.id=t1.id
where avg_score>60;
③ 查出没有‘001’课程成绩的学生的姓名、年龄
select
stu.name,
t2.age
from student stu
join(
select
id
from score
where cid != 001
group by id
) t2
on stu.id=t2.id;
④ 查出有‘001’,’002’这两门课程下,成绩排名前3的学生的姓名、年龄
select
stu.name,
stu.age
from(
select
id,
cid,
score,
rank() over(partition by cid order by score desc) rank
from score
where cid=001 or cid-002
) t1
join student stu
on t1.id=stu.id
where rank<=3;
⑤ 创建新的表score_20190317,并存入score表中20190317分区的数据
create table score_20190317 as select * from score where dt='20190317';
⑥ 如果上面的score表中,uid存在数据倾斜,请进行优化,查出在20190101-20190317中,学生的姓名、年龄、课程、课程的平均成绩
select
stu.name,
stu.age,
cou.cname,
t1.avg_score
from(
select
id,
cid,
avg(score) avg_score
from score
group by id,cid
where dt >= '20190101' and dt <= '20190317'
) t1
left join student stu on t1.id = stu.id
left join course cou on t1.cid = cou.cid;
⑦ 描述一下union和union all的区别,以及在mysql和HQL中用法的不同之处?
union会将联合的结果集去重,效率较union all差 union all不会对结果集去重,所以效率高 HQL中要求union或union all操作时必须保证select集合的结果相同个数的列,并且每个列的类型是一样的
⑧ 简单描述一下lateral view语法在HQL中的应用场景,并写一个HQL实例
比如一个学生表为:
学号 姓名 年龄 成绩(语文|数学|英语)
001 张三 16 90,80,95
需要实现的效果:
学号 成绩
001 90
001 80
001 95
create table student(
id string,
name string,
age int,
scores array)
row format delimited fields terminated by '\t'
collection items terminated by ',';
select
id,
score
from student
lateral view explode(scores) tmp_score as score;
username month salary(消费记录)
A 2015-01 5
A 2015-01 15
B 2015-01 5
A 2015-01 8
B 2015-01 25
A 2015-01 5
A 2015-02 4
A 2015-02 6
B 2015-02 10
B 2015-02 5
1) 建表语句
create table t_consumer(
username string,
month string,
salary int)
row format delimited fields terminated by ',';
load data local inpath '/home/hadoop/data/emp_salas.txt' into table t_consumer;
需求
1) 求出每人每月的消费金额
select
username,
month,
sum(salary) as salary
from t_consumer
group by username,month;
2) 求出截止到当月每个人累计消费总额
select
username,
month,
cnt,
sum(cnt) over(partition by username order by month) as total_cnt
from(
select
username,
month,
sum(salary) as cnt
from(
select
*
from t_consumer
) as t1
group by username, month
) as t2
order by username, month;
现有图书管理数据库的三个数据模型如下:
图书(数据表名:BOOK)
序号 |
字段名称 |
字段描述 |
字段类型 |
1 |
BOOK_ID |
总编号 |
文本 |
2 |
SORT |
分类号 |
文本 |
3 |
BOOK_NAME |
书名 |
文本 |
4 |
WRITER |
作者 |
文本 |
5 |
OUTPUT |
出版单位 |
文本 |
6 |
PRICE |
单价 |
数值(保留小数点后2位) |
读者(数据表名:READER)
序号 |
字段名称 |
字段描述 |
字段类型 |
1 |
READER_ID |
借书证号 |
文本 |
2 |
COMPANY |
单位 |
文本 |
3 |
NAME |
姓名 |
文本 |
4 |
SEX |
性别 |
文本 |
5 |
GRADE |
职称 |
文本 |
6 |
ADDR |
地址 |
文本 |
借阅记录(数据表名:BORROW LOG)
序号 |
字段名称 |
字段描述 |
字段类型 |
1 |
READER_ID |
借书证号 |
文本 |
2 |
BOOK_D |
总编号 |
文本 |
3 |
BORROW_ATE |
借书日期 |
日期 |
(1)创建图书管理库的图书、读者和借阅三个基本表的表结构。请写出建表语句。
-- 创建图书表book
CREATE TABLE library_book(
book_id string,
SORT string,
book_name string,
writer string,
OUTPUT string,
price decimal(10,2));
INSERT INTO TABLE library_book VALUES ('001','TP391','信息处理','author1','机械工业出版社','20');
INSERT INTO TABLE library_book VALUES ('002','TP392','数据库','author12','科学出版社','15');
INSERT INTO TABLE library_book VALUES ('003','TP393','计算机网络','author3','机械工业出版社','29');
INSERT INTO TABLE library_book VALUES ('004','TP399','微机原理','author4','科学出版社','39');
INSERT INTO TABLE library_book VALUES ('005','C931','管理信息系统','author5','机械工业出版社','40');
INSERT INTO TABLE library_book VALUES ('006','C932','运筹学','author6','科学出版社','55');
-- 创建读者表reader
CREATE TABLE library_reader(
reader_id string,
company string,
name string,
sex string,
grade string,
addr string);
INSERT INTO TABLE library_reader VALUES ('0001','阿里巴巴','jack','男','vp','addr1');
INSERT INTO TABLE library_reader VALUES ('0002','百度','robin','男','vp','addr2');
INSERT INTO TABLE library_reader VALUES ('0003','腾讯','tony','男','vp','addr3');
INSERT INTO TABLE library_reader VALUES ('0004','京东','jasper','男','cfo','addr4');
INSERT INTO TABLE library_reader VALUES ('0005','网易','zhangsan','女','ceo','addr5');
INSERT INTO TABLE library_reader VALUES ('0006','搜狐','lisi','女','ceo','addr6');
-- 创建借阅记录表borrow_log
CREATE TABLE library_borrow_log(
reader_id string,
book_id string,
borrow_date string);
INSERT INTO TABLE library_borrow_log VALUES ('0001','002','2019-10-14');
INSERT INTO TABLE library_borrow_log VALUES ('0002','001','2019-10-13');
INSERT INTO TABLE library_borrow_log VALUES ('0003','005','2019-09-14');
INSERT INTO TABLE library_borrow_log VALUES ('0004','006','2019-08-15');
INSERT INTO TABLE library_borrow_log VALUES ('0005','003','2019-10-10');
INSERT INTO TABLE library_borrow_log VALUES ('0006','004','2019-17-13');
(2)找出姓李的读者姓名(NAME)和所在单位(COMPANY)。
SELECT
name,
company
FROM library_reader
WHERE name LIKE '李%';
(3)查找“高等教育出版社”的所有图书名称(BOOK_NAME)及单价(PRICE),结果按单价降序排序。
SELECT
book_name,
price
FROM library_book
WHERE OUTPUT = "高等教育出版社"
ORDER BY price DESC;
(4)查找价格介于10元和20元之间的图书种类(SORT)出版单位(OUTPUT)和单价(PRICE),结果按出版单位(OUTPUT)和单价(PRICE)升序排序。
SELECT
sort,
output,
price
FROM library_book
WHERE price >= 10 and price <= 20
ORDER BY output,price;
(5)查找所有借了书的读者的姓名(NAME)及所在单位(COMPANY)。
SELECT
b.name,
b.company
FROM library_borrow_log a
JOIN library_reader b
ON a.reader_id = b.reader_id;
(6)求”科学出版社”图书的最高单价、最低单价、平均单价。
SELECT
max(price),
min(price),
avg(price)
FROM library_book
WHERE OUTPUT = '科学出版社';
(7)找出当前至少借阅了2本图书(大于等于2本)的读者姓名及其所在单位。
SELECT
b.name,
b.company
FROM(
SELECT
reader_id
FROM library_borrow_log
GROUP BY reader_id
HAVING count(*) >= 2
) a
JOIN library_reader b
ON a.reader_id = b.reader_id;
(8)考虑到数据安全的需要,需定时将“借阅记录”中数据进行备份,请使用一条SQL语句,在备份用户bak下创建与“借阅记录”表结构完全一致的数据表BORROW_LOG_BAK.井且将“借阅记录”中现有数据全部复制到BORROW_1.0G_ BAK中。
CREATE TABLE library_borrow_log_bak as SELECT * FROM library_borrow_log;
(9)现在需要将原Oracle数据库中数据迁移至Hive仓库,请写出“图书”在Hive中的建表语句(Hive实现,提示:列分隔符|;数据表数据需要外部导入:分区分别以month_part、day_part 命名)
CREATE TABLE book_hive(
book_id string,
SORT string,
book_name string,
writer string,
OUTPUT string,
price DECIMAL(10, 2))
partitioned BY ( month_part string, day_part string )
ROW format delimited FIELDS TERMINATED BY '|' stored AS textfile;
(10)Hive中有表A,现在需要将表A的月分区 201505 中 user_id为20000的user_dinner字段更新为bonc8920,其他用户user_dinner字段数据不变,请列出更新的方法步骤。(Hive实现,提示:Hlive中无update语法,请通过其他办法进行数据更新)
方式1:配置hive支持事务操作,分桶表,orc存储格式
方式2:第一步找到要更新的数据,将要更改的字段替换为新的值,第二步找到不需要更新的数据,第三步将上两步的数据插入一张新表中
参考资料:
hive sql 求所有用户和活跃用户的总数及平均年龄 - 代码先锋网
https://blog.51cto.com/u_13270164/3276437
数据分析工具——sql篇(面试题解析) - 知乎
经典Hive SQL面试题_serendipity-CSDN博客