SQL题

1、取出sql表中第31到40的记录(以自动增长ID为主键)

sql server方案:               

select top 10 * from t where id not in (select top 30 id from t order by id ) orde by id

mysql方案:               

select * from t order by id limit 30,10

 oracle方案:               

select * from (select rownum r,* from t where r<=40) where r>30

2、用一条SQL语句 查询出每门课都大于80分的学生姓名

name   kecheng   fenshu
张三     语文       81
张三     数学       75
李四     语文       76
李四     数学       90
王五     语文       81
王五     数学       100
王五     英语       90 

准备数据的sql代码:
create table score(id int primary key auto_increment,name varchar(20),subject varchar(20),score int);
insert into score values
(null,'张三','语文',81),
(null,'张三','数学',75),
(null,'李四','语文',76),
(null,'李四','数学',90),
(null,'王五','语文',81),
(null,'王五','数学',100),
(null,'王五 ','英语',90);

思路:转化为查出有<80分的学生姓名,然后排除这些学生剩下的就都是>80的了

 select distinct name from score  where  name not in (select distinct name from score where score<=80)

3、所有部门之间的比赛组合
一个叫department的表,里面只有一个字段name,一共有4条纪录,分别是a,b,c,d,对应四个球对,现在四个球对进行比赛,用一条sql语句显示所有可能的比赛组合.

select a.name, b.name from team a, team b where a.name < b.name

4、请用SQL语句实现:从TestDB数据表中查询出所有月份的发生额都比101科目相应月份的发生额高的科目。请注意:TestDB中有很多科目,都有1-12月份的发生额。AccID:科目代码,Occmonth:发生额月份,DebitOccur:发生额。

准备数据的sql代码:

create table TestDB(id int primary key auto_increment,AccID varchar(20), Occmonth date, DebitOccur bigint);
insert into TestDB values
(null,'101','1988-1-1',100),
(null,'101','1988-2-1',110),
(null,'101','1988-3-1',120),
(null,'101','1988-4-1',100),
(null,'101','1988-5-1',100),
(null,'101','1988-6-1',100),
(null,'101','1988-7-1',100),
(null,'101','1988-8-1',100);
-- 复制上面的数据,故意把第一个月份的发生额数字改小一点
insert into TestDB values
(null,'102','1988-1-1',90),
(null,'102','1988-2-1',110),
(null,'102','1988-3-1',120),
(null,'102','1988-4-1',100),
(null,'102','1988-5-1',100),
(null,'102','1988-6-1',100),
(null,'102','1988-7-1',100),
(null,'102','1988-8-1',100);
-- 复制最上面的数据,故意把所有发生额数字改大一点
insert into TestDB values
(null,'103','1988-1-1',150),
(null,'103','1988-2-1',160),
(null,'103','1988-3-1',180),
(null,'103','1988-4-1',120),
(null,'103','1988-5-1',120),
(null,'103','1988-6-1',120),
(null,'103','1988-7-1',120),
(null,'103','1988-8-1',120);
-- 复制最上面的数据,故意把所有发生额数字改大一点
insert into TestDB values
(null,'104','1988-1-1',130),
(null,'104','1988-2-1',130),
(null,'104','1988-3-1',140),
(null,'104','1988-4-1',150),
(null,'104','1988-5-1',160),
(null,'104','1988-6-1',170),
(null,'104','1988-7-1',180),
(null,'104','1988-8-1',140);
-- 复制最上面的数据,故意把第二个月份的发生额数字改小一点
insert into TestDB values
(null,'105','1988-1-1',100),
(null,'105','1988-2-1',80),
(null,'105','1988-3-1',120),
(null,'105','1988-4-1',100),
(null,'105','1988-5-1',100),
(null,'105','1988-6-1',100),
(null,'105','1988-7-1',100),
(null,'105','1988-8-1',100);

此题的思路其实就是把科目为101的单独看成一个关联表,比较主表和关联表on中条件对应上的对应科目数据  

-- 答案1
select distinct AccID from TestDB 
where AccID not in 
	(select TestDB.AccID from TestDB,
		 (select * from TestDB where AccID='101') as db101 
	where TestDB.Occmonth=db101.Occmonth and TestDB.DebitOccur<=db101.DebitOccur
	);
-- 答案2
select distinct AccID from TestDB 
where AccID not in (
select distinct t1.AccID from TestDB t1 LEFT JOIN 
          (select * from TestDB where AccID='101') t2 on t1.Occmonth=t2.Occmonth
           where t1.DebitOccur<=t2.DebitOccur )

5、统计每年每月的信息

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

准备sql语句:
drop table if exists sales;
create table sales(id int auto_increment primary key,year varchar(10), month varchar(10), amount float(2,1));
insert into sales values
(null,'1991','1',1.1),
(null,'1991','2',1.2),
(null,'1991','3',1.3),
(null,'1991','4',1.4),
(null,'1992','1',2.1),
(null,'1992','2',2.2),
(null,'1992','3',2.3),
(null,'1992','4',2.4);

说明,这个其实也就是竖表转横表

-- 答案1
select YEAR,
min(case month when '1' then amount END ) m1,
min(case month when '2' then amount END ) m2,
min(case month when '3' then amount END ) m3,
min(case month when '4' then amount END ) m4 
from sales GROUP BY YEAR 

-- 答案2
select s.year ,
(select t.amount from sales t where t.month='1' and t.year= s.year) 'm1',
(select t.amount from sales t where t.month='2' and t.year= s.year) 'm2',
(select t.amount from sales t where t.month='3' and t.year= s.year) 'm3',
(select t.amount from sales t where t.month='4' and t.year= s.year) 'm4'
from sales s  group by s.year;

6、显示文章标题,发帖人、最后回复时间
表:id,title,postuser,postdate,parentid
准备sql语句:
drop table if exists articles;
create table articles(id int auto_increment primary key,title varchar(50), postuser varchar(10), postdate datetime,parentid int references articles(id));
insert into articles values
(null,'第一条','张三','1998-10-10 12:32:32',null),
(null,'第二条','张三','1998-10-10 12:34:32',null),
(null,'第一条回复1','李四','1998-10-10 12:35:32',1),
(null,'第二条回复1','李四','1998-10-10 12:36:32',2),
(null,'第一条回复2','王五','1998-10-10 12:37:32',1),
(null,'第一条回复3','李四','1998-10-10 12:38:32',1),
(null,'第二条回复2','李四','1998-10-10 12:39:32',2),
(null,'第一条回复4','王五','1998-10-10 12:39:40',1);

-- 第一种写法 非标准SQL,仅适合于MySql 因为mysql的分组查询列可以不在group by 字段中,
-- 而且聚合函数也不需要group by就可以单独使用
select a.title,a.postuser,
(select max(postdate) from articles where parentid=a.id) reply 
from articles a where a.parentid is null;

--第二种写法:标准SQL写法
select a2.title,a2.postuser,
(select max(a.postdate) from articles a
where a.parentid=a2.id GROUP BY a.parentid ) replytime 
from articles a2 where a2.parentid is null

7、删除除了id号不同,其他都相同的学生冗余信息

create table student2(id int auto_increment primary key,code varchar(20),name varchar(20));
insert into student2 values(null,'2005001','张三'),(null,'2005002','李四'),(null,'2005001','张三');
如下语句,mysql报告错误,可能删除依赖后面统计语句,而删除又导致统计语句结果不一致。

delete from student2 where id not in(select min(id) from student2 group by name);

//于是,我想先把分组的结果做成虚表,然后从虚表中选出结果,最后再将结果作为删除的条件数据。先套一层,让子查询结果先出来再做删除,可能mysql内部没有处理这种一起关联时的先后顺序,所以只能多套一层了,这个在Oracle的rownum中也有类似现象,这点做的好的有MSSQL

delete from student2 where id not in(select mid from (select min(id) mid
from student2 group by name) as t);

8、航空网的几个航班查询题

表结构如下:
flight{flightID,StartCityID ,endCityID,StartTime}
city{cityID, CityName)
实验环境:
create table city(cityID int auto_increment primary key,cityName varchar(20));
create table flight (flightID int auto_increment primary key,
StartCityID int references city(cityID),
endCityID int references city(cityID),
StartTime time);
sql数据:
insert into city values(null,'北京'),(null,'上海'),(null,'广州');
insert into flight values
(null,1,2,'9:37:23'),(null,1,3,'9:37:23'),(null,1,2,'10:37:23'),(null,2,3,'10:37:23');

1)、查询起飞城市是北京的所有航班,按到达城市的名字排序

-- 方法1 左连接查询
select f.*,c.* from flight f 
left join city c on f.startcityid=c.cityid
left join city c2 on f.endcityid=c2.cityid
where c.cityname='北京' ORDER BY c2.cityname asc
-- 方法2 嵌套子查询加笛卡尔积过滤
select * from flight f,city c 
where f.endcityid = c.cityid and startcityid = 
(select c1.cityid from city c1 where c1.cityname = "北京")
order by c.cityname asc;

2)、查询北京到上海的所有航班纪录(起飞城市,到达城市,起飞时间,航班号)

select f.flightid,f.starttime,c.cityname,c2.cityname from flight f 
left join city c on f.startcityid=c.cityid
left join city c2 on f.endcityid=c2.cityid
where c.cityname='北京' and c2.cityname='上海'

9、一个用户具有多个角色,请查询出改表中具有该用户的所有角色的其他用户;

CREATE TABLE `emp` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`number` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`role` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
);

INSERT INTO `emp` VALUES (1,1001,'a','read');
INSERT INTO `emp` VALUES (2,1001,'a','write');
INSERT INTO `emp` VALUES (3,1001,'a','copy');
INSERT INTO `emp` VALUES (4,1002,'b','read');
INSERT INTO `emp` VALUES (5,1002,'b','write');
INSERT INTO `emp` VALUES (7,1003,'c','listen');
INSERT INTO `emp` VALUES (8,1003,'c','read');
INSERT INTO `emp` VALUES (9,1004,'d','read');
INSERT INTO `emp` VALUES (10,1004,'d','write');
INSERT INTO `emp` VALUES (11,1005,'e','read');
INSERT INTO `emp` VALUES (12,1005,'e','write');

-- 查出具有1002所有角色的用户
select e1.number from emp e1 ,(select * from emp where number=1002) e2
where e1.role =e2.role and e1.number!=e2.number
group by e1.number 
having count(e1.number)
=(select count(e3.number) 
from emp e3 where e3.number=1002 
group by e3.number)

10、基于EMPLOYEES表写出查询:查出个人工资高于其所在部门平均工资的员工,列出这些员工的全部个人信息及该员工工资高出部门平均工资百分比。

Table EMPLOYEES Structure:

        EMPLOYEE_ID NUMBER Primary Key,
        FIRST_NAME VARCHAR2(25),
         LAST_NAME VARCHAR2(25),
        Salary number(8,2),
         HiredDate DATE,
         Departmentid number(2)
Table Departments Structure:
         Departmentid number(2) Primary Key,
        DepartmentName VARCHAR2(25). 

select employee1.*,(employee1.salary-t.avgSalary)*100/employee1.salary 
from employee1,
(select deptid,avg(salary) avgSalary from employee1 group by deptid) as t
where employee1.deptid = t.deptid and employee1.salary>t.avgSalary;

11、有一个Order表,表结构如下:

1 A 张三 1000
2 A 李四 500
3 C 赵五 2000
4 A 张三 1500
5 C 赵五 1500
6 A 张三 500
7 B 王六 800
8 B 钱七 1000
9 B 王六 1500

sql准备如下:

CREATE TABLE `order` (
`orderID` int(11) DEFAULT NULL,
`region` varchar(255) DEFAULT NULL,
`sales` varchar(255) DEFAULT NULL,
`total` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO `order` VALUES ('1', 'A', '张三', '1000');
INSERT INTO `order` VALUES ('2', 'A', '李四', '500');
INSERT INTO `order` VALUES ('3', 'C', '赵五', '2000');
INSERT INTO `order` VALUES ('4', 'A', '张三', '1500');
INSERT INTO `order` VALUES ('5', 'C', '赵五', '1500');
INSERT INTO `order` VALUES ('6', 'A', '张三', '500');
INSERT INTO `order` VALUES ('7', 'B', '王六', '800');
INSERT INTO `order` VALUES ('8', 'B', '钱七', '1000');
INSERT INTO `order` VALUES ('9', 'B', '王六', '1500');

-- 1、统计出每个地区的合同金额合计并按此倒序排列显示 
select region,sum(total) from `order` GROUP BY region
-- 2、统计出每个地区销售人员数量
-- select region '地区', count(sales) '销售人员数量' from `order` GROUP BY region,sales 
-- 上为错误写法,直接分组统计会导致同一地区同一销售的的重复记录,结果不准确,得先过滤掉重复数据再统计
select t.region '地区' ,count(t.region) '销售人员数量' from (select distinct region,sales from `order`) t GROUP BY t.region
-- 3、统计出每个地区合同金额最少的销售人员
select t1.* from 
(select o3.region o3_region,o3.sales o3_sales,sum(o3.total) o3_sumTotal from `order` o3 GROUP BY o3.region,o3.sales) t1
LEFT JOIN 
(select o2.o1_region o2_region,min(o2.o1_sumTotal) o2_minTotal
 from (
       select o1.region o1_region,o1.sales o1_sales,sum(o1.total) o1_sumTotal from `order` o1 GROUP BY o1.region,o1.sales
) o2 group BY o2.o1_region
-- 单独通过t2这一步可以统计出各个地区的合同金额最少的销售的金额值,但是无法得出销售姓名,
-- 因为不能按照销售分组,采用min(sales)数据结果会出现偏差,所以还得外层再套一下,这步不能少
) t2   on t1.o3_region = t2.o2_region 
where  t1.o3_sumTotal=t2.o2_minTotal
-- 4、统计出所有超过本地区合同金额平均值的合同及金额
select o2.* from `order` o2, 
(select o1.region o1_region,avg(o1.total) o1_avgTotal from `order` o1 GROUP BY o1.region ) t1
where o2.region=t1.o1_region and o2.total>t1.o1_avgTotal;

12、Oracle的rowid和rownum的区别,写出查询3-10条的分页记录

答:rowid和rownum都是Oracle的伪列,区别是rowid是属于具体表记录上的地址信息,是用16进制表示的,可以通过此地址信息快速定位到具体记录行,但是rownum并不是属于表本身,而是每次查询结果集返回之前Oracle自动添加的一个数据排列int索引,类似于号码牌,rownum根据结果集条数不同数值不同,其每次都是从1开始的,所以不能直接进行大于1的区间过滤,但是<的过滤没问题,直接查=1的结果也可以出来,但是查=其他数值的话查不出来,所以只能把结果再转一下成中间表再过滤

分页: 

select * from (select rownum r, e.* from emp e where rownum <=10) t
where t.r>3

rownum可以起别名,但是具体使用时如where条件中不能用别名,只能用rownum,且如果select * 必须指定表别名.* 不能直接* ,rowid也一样,不能直接*, 

select rowid r,e.* from emp e; -- ok
select rowid,* from emp -- erorr

 

  

 

posted @ 2017-08-19 15:57  关键步就几步  阅读(409)  评论(0编辑  收藏  举报