SQL小练

10. 找出注册年限超过五年的会员,返回卡号、会员姓名、办理日期和注册年限
Oracle:
select handledate,cardno,username, trunc(months_between(sysdate,handledate) / 12) from t_user_info where months_between(sysdate,handledate) / 12 > 5

11.查询10、20号部门的最高工资,最低工资和平均工资
SQL server:
当时笔者对题目了解有些出入,认为是查找10、20两个部门合并后的最高工资、最低工资、和平均工资,建了一个视图,代码如下:
create view emp_1020 as select empno,ename,sal,deptno from EMP where deptno = 10 or deptno = 20
然后再查询
select MAX(sal) as 最高工资,MIN(sal) as 最低工资,convert(decimal(18,2),AVG(sal)) as 平均工资 from emp_1020
select MAX(sal) as 最高工资,MIN(sal) as 最低工资,round(AVG(sal),4) as 平均工资 from emp_1020
这两句其实是一样的,我是想记录一下保留小数的两种方法。

题目的意思其实是分别计算。
select deptno,MAX(sal) as 最高工资,MIN(sal) as 最低工资,convert(decimal(18,2),AVG(sal)) as 平均工资 from emp_1020 group by deptno
建视图其实多此一举,直接用 in 即可完成
select deptno,max(sal),min(sal),round(avg(sal)) from emp where deptno in (10,20) group by deptno

12.查询累计消费高于300的会员
select cardno, SUM(account) as 消费总额 from T_CONSUME group by cardno having SUM(account) > 300

13.查询全部员工的工资均高于1000的部门
要全部员工工资高于1000,那不就是部门工资最低的小可怜的工资大于1000就可以了
select deptno from emp group by deptno having min(sal)>1000

14.查询每个部门每个工种的最高工资
select deptno,job,MAX(sal) as 最高工资 from EMP group by job,deptno
这里用group 分下组就好了

15.查询每个部门工资高于1500的人数
select COUNT(case when sal > 1500 then 1 end) as 人数,deptno from EMP group by deptno
count(case when…then…end )用于条件统计。

16.找出20号部门工资高于30号部门全体员工的人
select empno,sal from EMP A where deptno = 20 and sal >(select MAX(sal) from EMP B where deptno = 30)
17.按部门分组,计算每个部门员工工资与部门最高工资以及与部门平均工资之间的差额(取绝对值)
select deptno,sal, max(sal) over(partition by deptno) - sal, round(abs(sal-avg(sal) over(partition by deptno))) from emp
18.按部门分组,给员工按员工编号(或rowid)排序,并计算该员工与后序员工的工资差值(取绝对值),空缺的按0处理
select deptno,empno, row_number() over(partition by deptno order by empno), sal, abs(sal-lead(sal,1,0) over(partition by deptno order by empno)) from emp
偏移函数
lead 下n行 当前行减去向下偏移量为n的行
lag 前n行 当前行减去向上偏移量为n的行

Lag和Lead分析函数可以在同一次查询中取出同一字段的前N行的数据(Lag)和后N行的数据(Lead)作为独立的列。
语法如下:
lag(exp_str,offset,defval) over()
Lead(exp_str,offset,defval) over()
–exp_str要取的列
–offset取偏移后的第几行数据
–defval:没有符合条件的默认值
19.按部门分组,计算员工工资占部门总工资的比重
select deptno,sal, round(ratio_to_report(sal) over(partition by deptno ),2)ratio_over from emp
ratio_to_report 是Oracle中的统计函数,sqlserver中不支持。

``

超市篇

建表、插数据

创建用户消费表、超市表、充值表、用户信息表
create table T_CONSUME ( cardno NUMBER(4), account NUMBER, consumedate DATE, loc_code NUMBER(3) )

create table T_MARKET ( m_code NUMBER(3), fullname VARCHAR2(100), district VARCHAR2(12), validtype NUMBER )

create table T_RECHARGE ( cardno NUMBER(4), account NUMBER, rechargedate DATE, loc_code NUMBER(3) )
create table T_USER_INFO ( cardno NUMBER(4) not null, username VARCHAR2(40), handledate DATE, loc_code NUMBER(3), balance NUMBER, usertype NUMBER )
select * from T_CONSUME/*消费信息表,会员卡号、消费金额、消费日期、店铺代码*/ select * from T_MARKET/*店铺信息表,店铺代码,店铺名,区域,可用*/ select * from T_RECHARGE/*会员充值表,会员卡号,充值金额,充值日期,店铺代码*/ select * from T_USER_INFO/*用户信息表,会员卡号,用户名,注册日期,店铺代码,余额,会员等级*/

数据有点多,我这里只插入部分数据演示一下
insert into T_CONSUME (cardno, account, consumedate, loc_code) values (1014, 50, to_date('17-01-2019', 'dd-mm-yyyy'), 325); insert into T_CONSUME (cardno, account, consumedate, loc_code) values (4003, 50, to_date('17-01-2019', 'dd-mm-yyyy'), 302); insert into T_MARKET (m_code, fullname, district, validtype) values (304, '华联安贞桥店', '朝阳区', 1); insert into T_MARKET (m_code, fullname, district, validtype) values (308, '家乐福九棵树店', '通州区', 1); insert into T_MARKET (m_code, fullname, district, validtype) values (309, '华普新华联店', '通州区', 0); insert into T_RECHARGE (cardno, account, rechargedate, loc_code) values (1001, 100, to_date('24-04-2016', 'dd-mm-yyyy'), 320); insert into T_RECHARGE (cardno, account, rechargedate, loc_code) values (1008, 150, to_date('20-06-2016', 'dd-mm-yyyy'), 312); insert into T_RECHARGE (cardno, account, rechargedate, loc_code) values (3009, 100, to_date('21-01-2016', 'dd-mm-yyyy'), 326); insert into T_RECHARGE (cardno, account, rechargedate, loc_code) values (4004, 150, to_date('14-02-2016', 'dd-mm-yyyy'), 319); insert into T_RECHARGE (cardno, account, rechargedate, loc_code) values (3005, 100, to_date('23-03-2016', 'dd-mm-yyyy'), 301);; insert into T_USER_INFO (cardno, username, handledate, loc_code, balance, usertype) values (1001, '张乐', to_date('10-07-2007', 'dd-mm-yyyy'), 304, 350, 3); insert into T_USER_INFO (cardno, username, handledate, loc_code, balance, usertype) values (1002, '张超', to_date('15-03-2008', 'dd-mm-yyyy'), 302, 306, 3); insert into T_USER_INFO (cardno, username, handledate, loc_code, balance, usertype) values (1003, '刘方谅', to_date('14-04-2008', 'dd-mm-yyyy'), 319, 347, 2); insert into T_USER_INFO (cardno, username, handledate, loc_code, balance, usertype) values (1004, '陈楦桓', to_date('28-08-2009', 'dd-mm-yyyy'), 316, 323, 1); ;
1. 查询每家超市消费总额高于200不到500以及高于500的人数
因为消费表和商店表有共同列 code。所以将这两张表左连接后,可以查询

select count(cardno) as 数量,fullname from T_MARKET M left join T_CONSUME C on C.loc_code = M.m_code group by loc_code, fullname having sum(account) between 200 and 500

select count(cardno) as 数量,fullname from T_MARKET M left join T_CONSUME C on C.loc_code = M.m_code group by loc_code, fullname having sum(account) > 500

2.按照超市一级分组,年度二级分组统计每个超市的年度消费总额,单个超市另起一行展示超市全部年份的累计消费总额,所有超市排列完以后另起一行展示所有超市的消费总额累加值。
这道题用Oracle。
select loc_code, to_char(consumedate,'yyyy'), decode ( grouping_id( loc_code , to_char(consumedate,'yyyy') ), 0,to_char(consumedate,'yyyy'), 1,'累计消费总额', '所有超市消费总额' ), sum(account) from t_consume group by rollup(loc_code, to_char(consumedate,'yyyy'))
这道题详解见之前一篇文章
高级聚合函数 grouping_id

3.按超市将办理会员姓名汇总为一行,用/分隔(提示:办理超市在t_user_info的loc_code)
select loc_code,listagg(username,'/')within group (order by rowid) from t_user_info

4.按办理年度分组,查询余额为该年度第二高的会员信息
select * from (select *,rank() over(partition by datename(yyyy,handledate) order by balance) as 排名 from T_USER_INFO ) A where A.排名 = 2

这里给出三种 排序语句:
1.row_number
row_number() over(partition by 分组字段 order by 排序字段)
-----1, 2, 3, 4 …

2.rank
rank() over(partition by 分组字段 order by 排序字段)
-----1, 1, 3, 4 …

3.dense_rank
dense_rank() over(partition by 分组字段 order by 排序字段)
-----1, 1, 2, 3 …
5.按年度下每个超市分组展现办理会员清单,以及注册会员数量,每个年度另起一行汇总展示该年度的总数据,全部数据排列完成以后汇总一行展示整体数据。
select to_char(consumedate,'yyyy'), loc_code, decode (grouping_id(to_char(consumedate,'yyyy'),loc_code), 0,to_char(loc_code), 1,'年度总数据', '总数据'), count(cardno) from t_consume group by rollup(to_char(consumedate,'yyyy'),loc_code)
decode()函数是Oracle内置函数。
6.将会员信息和充值信息关联,返回会员卡号、姓名、办理地点、充值日期
select a.cardno,a.username,b.loc_code,b.rechargedate from t_user_info a join t_recharge b on a.cardno=b.cardno
7.找出在’永辉北京站店’消费过的会员信息,返回姓名和消费日期
select tui.username,tc.consumedate from t_user_info tui,t_consume tc where tui.cardno=tc.cardno and tc.loc_code in( select m_code from t_market where fullname = '永辉北京站店')
8.找出所有超市在2016年的消费和充值信息,没有记录的显示为空,返回超市全名和消费、充值日期
select a.fullname,b.consumedate,c.rechargedate from t_market a left join t_consume b on a.m_code=b.loc_code and b.consumedate between '2016/01/01' and '2016/12/31' left join t_recharge c on a.m_code=c.loc_code and c.rechargedate between '2016/01/01' and '2016/12/31'
由于题目要求没有记录的显示为空,所以表在连接的时候使用left join,如果没有要求直接 join 即可。
select fullname, consumedate, rechargedate from T_MARKET M join T_RECHARGE R ON M.m_code = R.loc_code join T_CONSUME C on R.loc_code = C.loc_code and C.consumedate between '2016/01/01' and '2016/12/31' and R.rechargedate between '2016/01/01' and '2016/12/31'
9.查询每个行政区累计消费总额、消费次数和消费人数
select district,sum(account), count(*),count(distinct cardno) from t_market tm,t_consume tc where tm.m_code=tc.loc_code group by district
10.查询每个行政区的各个门店注册(办理会员)人数
select district,fullname,count(*) from t_market tm,t_user_info tui where tm.m_code=tui.loc_code group by district,fullname
11.查询每月至少有一笔消费金额高于150的用户,返回卡号、姓名、所在月
select a.cardno,a.username,to_char(b.consumedate,'yyyymm'),max(account) from t_user_info a join t_consume b on a.cardno=b.cardno group by a.cardno,a.username,to_char(consumedate,'yyyymm') having max(account) > 150
12.查询每月有且只有一笔消费金额高于100的用户,返回卡号、姓名、所在月
select U.cardno,U.username,datename(MM,consumedate) as 月份 from T_CONSUME C ,T_USER_INFO U where C.cardno = U.cardno group by U.cardno,U.username,datename(YYYY,consumedate),datename(MM,consumedate) having count(case when account >100 then 1 end) = 1
**13.查询2016年6月和2016年7月都有消费行为的用户,返回卡号和姓名 **
select C.cardno, U.username from T_CONSUME C , T_USER_INFO U where C.cardno = U.cardno group by C.cardno,U.username having count(case when consumedate between '2016/06/01' and '2016/06/30' then 1 end )=1 and count(case when consumedate between '2016/07/01' and '2016/07/31' then 1 end )=1
14.查询任意连续两个月都有消费行为的用户,返回卡号和姓名
select * from (select a.cardno,a.username,b.consumedate date1 from t_user_info a join t_consume b on a.cardno=b.cardno) r1 join (select a.cardno,a.username,b.consumedate date2 from t_user_info a join t_consume b on a.cardno=b.cardno) r2 on r1.cardno = r2.cardno and DATENAME(YYYY,r1.date1) = DATENAME(YYYY,r2.date2) and DATENAME(MM,r1.date1)+1 = DATENAME(MM,r2.date2)
15.查询在朝阳区有过至少两次消费行为的用户
select a.cardno, b.district, count(*) from t_consume a join t_market b on a.loc_code=b.m_code and b.district = '朝阳区' group by a.cardno, b.district having count(*) > 1
16. 查找在一家超市充值过但没有消费过的会员信息
select a.cardno, a.username from t_user_info a, t_recharge b where a.cardno = b.cardno and a.cardno not in ( select a.cardno from t_recharge a, t_consume b where a.cardno = b.cardno and a.loc_code = b.loc_code )
17.查询在任意一个门店注册并在注册门店充值总额不低于200的会员
select a.cardno from t_user_info a join t_recharge b on a.loc_code=b.loc_code and a.cardno=b.cardno group by a.cardno having sum(account) >= 200
18.查询每位会员在2016年期间的每笔单次消费金额占总额的比重,
如果没有消费记录,依然返回会员信息,消费记录部分留空,
返回卡号、姓名、单次金额、消费日期、当年消费总额、单次占比(保留两位小数)

select b.cardno,b.username,a.account,a.consumedate, sum(a.account) over(partition by b.cardno), round(ratio_to_report(a.account) over(partition by b.cardno),2) from t_consume a right join t_user_info b on a.cardno = b.cardno and a.consumedate >= to_date('20160101','yyyymmdd') and a.consumedate < to_date('20170101','yyyymmdd')
19.查询2018年至今在“物美东四店”只有过消费、充值当中一种行为的会员
select cardno from (select cardno from t_consume where consumedate >= to_date('20180101', 'yyyymmdd') and loc_code in (select m_code from t_10:12 2019/4/1510:12 2019/4/15market where fullname = '物美东四店') group by cardno union all select cardno from t_recharge where rechargedate >= to_date('20180101', 'yyyymmdd') and loc_code in (select m_code from t_market where fullname = '物美东四店') group by cardno) group by cardno having count(*) = 1;

猜你喜欢

转载自blog.csdn.net/Marko_Liu/article/details/89182936