面试常用SQL全解

面试常用SQL

2.1.1用两种方式根据部门号从高到低,工资从低到高列出每个员工的信息

employee:

     eid,ename,salary,deptid;

 select * from employee order by deptid desc,salary

2.1.2列出各个部门中工资高于本部门的平均工资的员工数和部门号,并按部门号排序

创建表:

       mysql> create table employee921(id int primary key auto_increment,name varchar(5

0),salary bigint,deptid int);

 

插入实验数据:

mysql> insert into employee921 values(null,'zs',1000,1),(null,'ls',1100,1),(null

,'ww',1100,1),(null,'zl',900,1) ,(null,'zl',1000,2), (null,'zl',900,2) ,(null,'z

l',1000,2) , (null,'zl',1100,2);

 

编写sql语句:

 

()select avg(salary) from employee921 group by deptid;

()mysql> select employee921.id,employee921.name,employee921.salary,employee921.dep

tid tid from  employee921 where salary > (select avg(salary) from employee921 where  deptid = tid);

   效率低的一个语句,仅供学习参考使用(在group by之后不能使用where,只能使用having,在group by之前可以使用where,即表示对过滤后的结果分组):

mysql> select employee921.id,employee921.name,employee921.salary,employee921.dep

tid tid from  employee921 where salary > (select avg(salary) from employee921 group by deptid having deptid = tid);

()select count(*) ,tid

from (

select employee921.id,employee921.name,employee921.salary,employee921.deptid tid

from   employee921

where salary >

  (select avg(salary) from employee921 where  deptid = tid)

) as t

group by tid ;

 

另外一种方式:关联查询

select a.ename,a.salary,a.deptid

 from emp a,

    (select deptd,avg(salary) avgsal from emp group by deptid ) b

 where a.deptid=b.deptid and a.salary>b.avgsal;

 

2.1.4数据库三范式是什么?

第一范式(1NF):字段具有原子性,不可再分。所有关系型数据库系统都满足第一范式)

数据库表中的字段都是单一属性的,不可再分。例如,姓名字段,其中的姓和名必须作为一个整体,无法区分哪部分是姓,哪部分是名,如果要区分出姓和名,必须设计成两个独立的字段。

5   第二范式(2NF):

第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。

要求数据库表中的每个实例或行必须可以被惟一地区分。通常需要为表加上一个列,以存储各个实例的惟一标识。这个惟一属性列被称为主关键字或主键。

第二范式(2NF)要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。简而言之,第二范式就是非主属性非部分依赖于主关键字。

10   

11  第三范式的要求如下:

12 满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。

13 所以第三范式具有如下特征:
         1,每一列只有一个值
         2,每一行都能区分。
         3,每一个表都不包含其他表已经包含的非主关键字信息。

14 例如,帖子表中只能出现发帖人的id,而不能出现发帖人的id,还同时出现发帖人姓名,否则,只要出现同一发帖人id的所有记录,它们中的姓名部分都必须严格保持一致,这就是数据冗余。

2.1.5 说出一些数据库优化方面的经验?

PreparedStatement 一般来说比Statement性能高:一个sql 发给服务器去执行,涉及步骤:语法检查、语义分析, 编译,缓存

“inert into user values(1,1,1)”-à二进制

“inert into user values(2,2,2)”-à二进制

“inert into user values(?,?,?)”-à二进制

 

 

 

有外键约束会影响插入和删除性能,如果程序能够保证数据的完整性,那在设计数据库时就去掉外键。(比喻:就好比免检产品,就是为了提高效率,充分相信产品的制造商)

(对于hibernate来说,就应该有一个变化:empleyee->Deptment对象,现在设计时就成了employeeàdeptid)

 

mysql帮助文档子查询章节的最后部分,例如,根据扫描的原理,下面的子查询语句要比第二条关联查询的效率高:

1.  select e.name,e.salary where e.managerid=(select id from employee where name='zxx');

 

2.   select e.name,e.salary,m.name,m.salary from employees e,employees m where

 e.managerid = m.id and m.name='zxx';

 

表中允许适当冗余,譬如,主题帖的回复数量和最后回复时间等

将姓名和密码单独从用户表中独立出来。这可以是非常好的一对一的案例哟!

 

sql语句全部大写,特别是列名和表名都大写。特别是sql命令的缓存功能,更加需要统一大小写,sql语句à发给oracle服务器à语法检查和编译成为内部指令à缓存和执行指令。根据缓存的特点,不要拼凑条件,而是用?和PreparedStatment

 

还有索引对查询性能的改进也是值得关注的。

 

备注:下面是关于性能的讨论举例

 

4航班 3个城市

 

m*n

 

select * from flight,city where flight.startcityid=city.cityid and city.name='beijing';

 

m + n

 

 

select * from flight where startcityid = (select cityid from city where cityname='beijing');

 

select flight.id,'beijing',flight.flightTime from flight where startcityid = (select cityid from city where cityname='beijing')

 

2.1.6 union和union all有什么不同?

假设我们有一个表Student,包括以下字段与数据:

4 drop table student;

5 create table student
(
id int primary key,
name nvarchar2(50) not null,
score number not null
);

6 insert into student values(1,'Aaron',78);
insert into student values(2,'Bill',76);
insert into student values(3,'Cindy',89);
insert into student values(4,'Damon',90);
insert into student values(5,'Ella',73);
insert into student values(6,'Frado',61);
insert into student values(7,'Gill',99);
insert into student values(8,'Hellen',56);
insert into student values(9,'Ivan',93);
insert into student values(10,'Jay',90);

7 commit;

8 Union和Union All的区别。

9 select *
from student
where id < 4

10 union

11 select *
from student
where id > 2 and id < 6

12 结果将是

13 1    Aaron    78
2    Bill    76
3    Cindy    89
4    Damon    90
5    Ella    73

14 如果换成Union All连接两个结果集,则返回结果是:

15 1    Aaron    78
2    Bill    76
3    Cindy    89
3    Cindy    89
4    Damon    90
5    Ella    73

16 可以看到,Union和Union All的区别之一在于对重复结果的处理。

17 

18 UNION在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果。实际大部分应用中是不会产生重复的记录,最常见的是过程表与历史表UNION。如:
select * from gc_dfys
union
select * from ls_jg_dfys
  这个SQL在运行时先取出两个表的结果,再用排序空间进行排序删除重复的记录,最后返回结果集,如果表数据量大的话可能会导致用磁盘进行排序。
 而UNION ALL只是简单的将两个结果合并后就返回。这样,如果返回的两个结果集中有重复的数据,那么返回的结果集就会包含重复的数据了。
 从效率上说,UNION ALL 要比UNION快很多,所以,如果可以确认合并的两个结果集中不包含重复的数据的话,那么就使用UNION ALL,

 

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

sql server方案1

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

sql server方案2

select top 10 * from t where id in (select top 40 id from t order by id) order by id desc

 

mysql方案:select * from t order by id limit 30,10

 

oracle方案:select * from (select rownum r,* from t where r<=40) where r>30

 

--------------------待整理进去的内容-------------------------------------

pageSize=20;

pageNo = 5;

 

1.分页技术1(直接利用sql语句进行分页,效率最高和最推荐的)

 

mysql:sql = "select * from articles limit " + (pageNo-1)*pageSize + "," + pageSize;

oracle: sql = "select * from " +

"(select rownum r,* from " +

"(select * from articles order by postime desc)" +

"where rownum<= " + pageNo*pageSize +") tmp " +

"where r>" + (pageNo-1)*pageSize;

注释:第7行保证rownum的顺序是确定的,因为oracle的索引会造成rownum返回不同的值

简洋提示:没有order by时,rownum按顺序输出,一旦有了order by,rownum不按顺序输出了,这说明rownum是排序前的编号。如果对order by从句中的字段建立了索引,那么,rownum也是按顺序输出的,因为这时候生成原始的查询结果集时会参照索引表的顺序来构建。

 

sqlserver:sql = "select top 10 * from id not id(select top " + (pageNo-1)*pageSize + "id from articles)"

 

DataSource ds = new InitialContext().lookup(jndiurl);

Connection cn = ds.getConnection();

//"select * from user where id=?"  --->binary directive

PreparedStatement pstmt = cn.prepareSatement(sql);

ResultSet rs = pstmt.executeQuery()

while(rs.next())

{

out.println(rs.getString(1));

}

 

2.不可滚动的游标

pageSize=20;

pageNo = 5;

cn = null

stmt = null;

rs = null;

try

{

sqlserver:sql = "select  * from articles";

 

DataSource ds = new InitialContext().lookup(jndiurl);

Connection cn = ds.getConnection();

//"select * from user where id=?"  --->binary directive

PreparedStatement pstmt = cn.prepareSatement(sql);

ResultSet rs = pstmt.executeQuery()

for(int j=0;j<(pageNo-1)*pageSize;j++)

{

rs.next();

}

 

int i=0;

 

while(rs.next() && i<10)

{

i++;

out.println(rs.getString(1));

}

}

cacth(){}

finnaly

{

if(rs!=null)try{rs.close();}catch(Exception e){}

if(stm.........

if(cn............

}

 

3.可滚动的游标

pageSize=20;

pageNo = 5;

cn = null

stmt = null;

rs = null;

try

{

sqlserver:sql = "select  * from articles";

 

DataSource ds = new InitialContext().lookup(jndiurl);

Connection cn = ds.getConnection();

//"select * from user where id=?"  --->binary directive

PreparedStatement pstmt = cn.prepareSatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,...);

//根据上面这行代码的异常SQLFeatureNotSupportedException,就可判断驱动是否支持可滚动游标

 

ResultSet rs = pstmt.executeQuery()

rs.absolute((pageNo-1)*pageSize)

int i=0;

while(rs.next() && i<10)

{

i++;

out.println(rs.getString(1));

}

}

cacth(){}

finnaly

{

if(rs!=null)try{rs.close();}catch(Exception e){}

if(stm.........

if(cn............

}

 

2.1.8 用一条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),

10 (null,'李四','数学',90),

11 (null,'王五','语文',81),

12 (null,'王五','数学',100),

13 (null,'王五 ','英语',90);

14 

15 提示:当百思不得其解时,请理想思维,把小变成大做,把大变成小做,

16 

17 答案:
A: select distinct name from score  where  name not in (select distinct name from score where score<=80)

18 

19 B:select distince name t1 from score where 80< all (select score from score where name=t1);

20 

 

2.1.9 所有部门之间的比赛组合

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

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

2.1.10 每个月份的发生额都比101科目多的科目

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

准备数据的sql代码:

drop table if exists TestDB;

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),

10 (null,'101','1988-3-1',120),

11 (null,'101','1988-4-1',100),

12 (null,'101','1988-5-1',100),

13 (null,'101','1988-6-1',100),

14 (null,'101','1988-7-1',100),

15 (null,'101','1988-8-1',100);

16 --复制上面的数据,故意把第一个月份的发生额数字改小一点

17 insert into TestDB values

18 (null,'102','1988-1-1',90),

19 (null,'102','1988-2-1',110),

20 (null,'102','1988-3-1',120),

21 (null,'102','1988-4-1',100),

22 (null,'102','1988-5-1',100),

23 (null,'102','1988-6-1',100),

24 (null,'102','1988-7-1',100),

25 (null,'102','1988-8-1',100);

26 --复制最上面的数据,故意把所有发生额数字改大一点

27 insert into TestDB values

28 (null,'103','1988-1-1',150),

29 (null,'103','1988-2-1',160),

30 (null,'103','1988-3-1',180),

31 (null,'103','1988-4-1',120),

32 (null,'103','1988-5-1',120),

33 (null,'103','1988-6-1',120),

34 (null,'103','1988-7-1',120),

35 (null,'103','1988-8-1',120);

36 --复制最上面的数据,故意把所有发生额数字改大一点

37 insert into TestDB values

38 (null,'104','1988-1-1',130),

39 (null,'104','1988-2-1',130),

40 (null,'104','1988-3-1',140),

41 (null,'104','1988-4-1',150),

42 (null,'104','1988-5-1',160),

43 (null,'104','1988-6-1',170),

44 (null,'104','1988-7-1',180),

45 (null,'104','1988-8-1',140);

46 --复制最上面的数据,故意把第二个月份的发生额数字改小一点

47 insert into TestDB values

48 (null,'105','1988-1-1',100),

49 (null,'105','1988-2-1',80),

50 (null,'105','1988-3-1',120),

51 (null,'105','1988-4-1',100),

52 (null,'105','1988-5-1',100),

53 (null,'105','1988-6-1',100),

54 (null,'105','1988-7-1',100),

55 (null,'105','1988-8-1',100);

56 答案:
select distinct AccID from TestDB

57 where AccID not in 

58 (select TestDB.AccIDfrom TestDB,

59  (select * from TestDB where AccID='101') as db101

60 where TestDB.Occmonth=db101.Occmonth and TestDB.DebitOccur<=db101.DebitOccur

61 );

2.1.11统计每年每月的信息

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);


答案一、
select sales.year ,

(select t.amount from sales t where t.month='1' and t.year= sales.year) '1',

(select t.amount from sales t where t.month='1' and t.year= sales.year) '2',

(select t.amount from sales t where t.month='1' and t.year= sales.year) '3',

(select t.amount from sales t where t.month='1' and t.year= sales.year) as '4'

from sales  group by year;

 

2.1.12 显示文章标题,发帖人、最后回复时间

表: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);

 

答案:

select a.title,a.postuser,

(select max(postdate) from articles where parentid=a.id) reply

from articles a where a.parentid is null;

 

注释:子查询可以用在选择列中,也可用于where的比较条件中,还可以用于from从句中。

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

2.学生表 如下:
id   学号   姓名 课程编号 课程名称 分数
1        2005001  张三  0001      数学    69
2        2005002  李四  0001      数学    89
3        2005001  张三  0001      数学    69
A: delete from tablename where id not in(select min(id号) from tablename group by 学号,姓名,课程编号,课程名称,分数)

实验:

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);

//但是,如下语句没有问题:

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

//于是,我想先把分组的结果做成虚表,然后从虚表中选出结果,最后再将结果作为删除的条件数据。

delete from student2 where id not in(select mid from (select min(id) mid

from student2 group by name) as t);

或者:

delete from student2 where id not in(select min(id) from (select * from s

tudent2) as t group by t.name);

2.1.14   航空网的几个航班查询题:

表结构如下:

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 timestamp);

//航班本来应该没有日期部分才好,但是下面的题目当中涉及到了日期

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、查询起飞城市是北京的所有航班,按到达城市的名字排序

 

 

参与运算的列是我起码能够显示出来的那些列,但最终我不一定把它们显示出来。各个表组合出来的中间结果字段中必须包含所有运算的字段。

 

  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;

 

mysql> select flight.flightid,'北京' startcity, e.cityname from flight,city e wh

ere flight.endcityid=e.cityid and flight.startcityid=(select cityid from city wh

ere cityname='北京');

 

mysql> select flight.flightid,s.cityname,e.cityname from flight,city s,city e wh

ere flight.startcityid=s.cityid and s.cityname='北京' and flight.endCityId=e.cit

yID order by e.cityName desc;

 

 

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

select c1.CityName,c2.CityName,f.StartTime,f.flightID

from city c1,city c2,flight f

where f.StartCityID=c1.cityID

and f.endCityID=c2.cityID

and c1.cityName='北京'

and c2.cityName='上海'

3、查询具体某一天(2005-5-8)的北京到上海的的航班次数

select count(*) from

(select c1.CityName,c2.CityName,f.StartTime,f.flightID

from city c1,city c2,flight f

where f.StartCityID=c1.cityID

and f.endCityID=c2.cityID

and c1.cityName='北京'

and c2.cityName='上海'

and 查帮助获得的某个日期处理函数(startTime) like '2005-5-8%'

 

mysql中提取日期部分进行比较的示例代码如下:

select * from flight where date_format(starttime,'%Y-%m-%d')='1998-01-02'

2.1.15  查出比经理薪水还高的员工信息:

Drop table if not exists employees;

create table employees(id int primary key auto_increment,name varchar(50)

,salary int,managerid int references employees(id));

insert into employees values (null,' lhm',10000,null), (null,' zxx',15000,1

),(null,'flx',9000,1),(null,'tg',10000,2),(null,'wzg',10000,3);

 

Wzg大于flx,lhm大于zxx

 

解题思路:

     根据sql语句的查询特点,是逐行进行运算,不可能两行同时参与运算。

涉及了员工薪水和经理薪水,所有,一行记录要同时包含两个薪水,所有想到要把这个表自关联组合一下。

     首先要组合出一个包含有各个员工及该员工的经理信息的长记录,譬如,左半部分是员工,右半部分是经理。而迪卡尔积会组合出很多垃圾信息,先去除这些垃圾信息。

 

select e.* from employees e,employees m where e.managerid=m.id and e.sala

ry>m.salary;

2.1.16 求出小于45岁的各个老师所带的大于12岁的学生人数

数据库中有3个表 teacher 表,student表,tea_stu关系表。
teacher 表 teaID name age
student 表 stuID name age
teacher_student表 teaID stuID
要求用一条sql查询出这样的结果
1.显示的字段要有老师name, age 每个老师所带的学生人数
2 只列出老师age为40学生age为12以上的记录

预备知识:

      1.sql语句是对每一条记录依次处理,条件为真则执行动作(select,insert,delete,update

       2.只要是迪卡尔积,就会产生“垃圾”信息,所以,只要迪卡尔积了,我们首先就要想到清除“垃圾”信息

实验准备:

drop table if exists tea_stu;

drop table if exists teacher;

drop table if exists student;

      create table teacher(teaID int primary key,name varchar(50),age int);

      create table student(stuID int primary key,name varchar(50),age int);

      create table tea_stu(teaID int references teacher(teaID),stuID int references student(stuID));

insert into teacher values(1,'zxx',45), (2,'lhm',25) , (3,'wzg',26) , (4,'tg',27);

insert into student values(1,'wy',11), (2,'dh',25) , (3,'ysq',26) , (4,'mxc',27);

insert into tea_stu values(1,1), (1,2), (1,3);

insert into tea_stu values(2,2), (2,3), (2,4);

 insert into tea_stu values(3,3), (3,4), (3,1);

insert into tea_stu values(4,4), (4,1), (4,2) , (4,3);

 

结果:2à3,3à2,4à3

 

解题思路:(真实面试答题时,也要写出每个分析步骤,如果纸张不够,就找别人要)

1要会统计分组信息,统计信息放在中间表中:

select teaid,count(*) from tea_stu group by teaid;

 

2接着其实应该是筛除掉小于12岁的学生,然后再进行统计,中间表必须与student关联才能得到12岁以下学生和把该学生记录从中间表中剔除,代码是:

select tea_stu.teaid,count(*) total from student,tea_stu

where student.stuid=tea_stu.stuid and student.age>12 group by tea_stu.teaid

 

3.接着把上面的结果做成虚表与teacher进行关联,并筛除大于45的老师

select teacher.teaid,teacher.name,total from teacher ,(select tea_stu.tea

id,count(*) total from student,tea_stu where student.stuid=tea_stu.stuid and stu

dent.age>12 group by tea_stu.teaid) as tea_stu2 where teacher.teaid=tea_stu2.tea

id and teacher.age<45;

2.1.17 求出发帖最多的人

select authorid,count(*) total from articles

group by authorid

having total=

(select max(total2) from (select count(*) total2 from articles group by authorid) as t);

 

select t.authorid,max(t.total) from

select authorid,count(*) total from articles as t

这条语句不行,因为max只有一列,不能与其他列混淆。

 

select authorid,count(*) total from articles

group by authorid having total=max(total)也不行。

2.1.18 一个用户表中有一个积分字段,假如数据库中有100多万个用户,若要在每年第一天凌晨将积分清零,你将考虑什么,你将想什么办法解决?

alter table drop column score;

alter table add colunm score int;

可能会很快,但是需要试验,试验不能拿真实的环境来操刀,并且要注意,

这样的操作时无法回滚的,在我的印象中,只有inert update delete等DML语句才能回滚,

对于create table,drop table ,alter table等DDL语句是不能回滚。

 

 

解决方案一,update user set score=0;

解决方案二,假设上面的代码要执行好长时间,超出我们的容忍范围,那我就alter table user drop column score;alter table user add column score int。

 

下面代码实现每年的那个凌晨时刻进行清零。

Runnable runnable =

new Runnable(){

public void run(){

clearDb();

schedule(this,new Date(new Date().getYear()+1,0,0));

}

};

 

schedule(runnable,

new Date(new Date().getYear()+1,0,1));

2.1.19 一个用户具有多个角色,请查询出该表中具有该用户的所有角色的其他用户。

select count(*) as num,tb.id

from

 tb,

 (select role from tb where id=xxx) as t1

where

 tb.role = t1.role and tb.id != t1.id

group by tb.id

having

num = select count(role) from tb where id=xxx;

2.1.20  xxx公司的sql面试

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).

 

 (2)基于上述EMPLOYEES表写出查询:写出雇用日期在今年的,或者工资在[1000,2000]之间的,或者员工姓名(last_name)以’Obama’打头的所有员工,列出这些员工的全部个人信息。4分)

select * from employees

where Year(hiredDate) = Year(date())

or (salary between 1000 and 200)

or left(last_name,3)='abc';

 

(3) 基于上述EMPLOYEES表写出查询:查出部门平均工资大于1800元的部门的所有员工,列出这些员工的全部个人信息。4分)

mysql> select id,name,salary,deptid did from employee1 where (select avg(salary)

 from employee1 where deptid = did) > 1800;

 

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

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;

 

2.1.22  JDBC中的PreparedStatement相比Statement的好处

答:一个sql命令发给服务器去执行的步骤为:语法检查,语义分析,编译成内部指令,缓存指令,执行指令等过程。

select * from student where id =3----缓存--àxxxxx二进制命令

select * from student where id =3----直接取-àxxxxx二进制命令

select * from student where id =4--- -à会怎么干?

如果当初是select * from student where id =?--- -à又会怎么干?

 上面说的是性能提高

可以防止sql注入。

2.1.23写一个用jdbc连接并访问oracle数据的程序代码  

2.1.24  Class.forName的作用?为什么要用?

答:按参数中指定的字符串形式的类名去搜索并加载相应的类,如果该类字节码已经被加载过,则返回代表该字节码的Class实例对象,否则,按类加载器的委托机制去搜索和加载该类,如果所有的类加载器都无法加载到该类,则抛出ClassNotFoundException。加载完这个Class字节码后,接着就可以使用Class字节码的newInstance方法去创建该类的实例对象了。

有时候,我们程序中所有使用的具体类名在设计时(即开发时)无法确定,只有程序运行时才能确定,这时候就需要使用Class.forName去动态加载该类,这个类名通常是在配置文件中配置的,例如,spring的ioc中每次依赖注入的具体类就是这样配置的,jdbc的驱动类名通常也是通过配置文件来配置的,以便在产品交付使用后不用修改源程序就可以更换驱动类名。

2.1.25   大数据量下的分页解决方法

答:最好的办法是利用sql语句进行分页,这样每次查询出的结果集中就只包含某页的数据内容。再sql语句无法实现分页的情况下,可以考虑对大的结果集通过游标定位方式来获取某页的数据。

sql语句分页,不同的数据库下的分页方案各不一样,下面是主流的三种数据库的分页sql:

sql server:

String sql =

"select top " + pageSize + " * from students where id not in" +

 

 "(select top " + pageSize * (pageNumber-1) + " id from students order by id)" +

 

 "order by id";

 

mysql:

  

String sql =

"select * from students order by id limit " + pageSize*(pageNumber-1) + "," + pageSize;

oracle:

 

String sql =

 "select * from " +  

 (select *,rownum rid from (select * from students order by postime desc) where rid<=" + pagesize*pagenumber + ") as t" +

 "where t>" + pageSize*(pageNumber-1);

2.1.26 JDBC 查询学生成绩单, 把主要代码写出来考试概率极大.

Connection cn = null;

PreparedStatement pstmt =null;

Resultset rs = null;

try

{

Class.forname(driveClassName);

cn =  DriverManager.getConnection(url,username,password);

pstmt = cn.prepareStatement(“select  score.* from score ,student “ +

“where score.stuId = student.id and student.name = ?”);

pstmt.setString(1,studentName);

Resultset rs = pstmt.executeQuery();

while(rs.next())

{

system.out.println(rs.getInt(“subject”)  +  “    ” + rs.getFloat(“score”) );

}

}catch(Exception e){e.printStackTrace();}

finally

{

if(rs != null) try{ rs.close() }catch(exception e){}

if(pstmt != null) try{pstmt.close()}catch(exception e){}

if(cn != null) try{ cn.close() }catch(exception e){}

}

 

2.1.27  这段代码有什么不足之处?

try {
Connection conn = ...;
Statement stmt = ...;

ResultSet rs = stmt.executeQuery("select * from table1");

while(rs.next()) {

}
} catch(Exception ex) {
}

答:没有finally语句来关闭各个对象,另外,使用finally之后,要把变量的定义放在try语句块的外面,以便在try语句块之外的finally块中仍可以访问这些变量。

2.1.27 说出数据连接池的工作机制是什么?

J2EE服务器启动时会建立一定数量的池连接,并一直维持不少于此数目的池连接。客户端程序需要连接时,池驱动程序会返回一个未使用的池连接并将其表记为忙。如果当前没有空闲连接,池驱动程序就新建一定数量的连接,新建连接的数量有配置参数决定。当使用的池连接调用完成后,池驱动程序将此连接表记为空闲,其他调用就可以使用这个连接。

实现方式,返回的Connection是原始Connection的代理,代理Connection的close方法不是真正关连接,而是把它代理的Connection对象还回到连接池中。

2.1.28  为什么要用 ORM?  和 JDBC 有何不一样?

orm是一种思想,就是把object转变成数据库中的记录,或者把数据库中的记录转变成objecdt,我们可以用jdbc来实现这种思想,其实,如果我们的项目是严格按照oop方式编写的话,我们的jdbc程序不管是有意还是无意,就已经在实现orm的工作了。

现在有许多orm工具,它们底层调用jdbc来实现了orm工作,我们直接使用这些工具,就省去了直接使用jdbc的繁琐细节,提高了开发效率,现在用的较多的orm工具是hibernate。也听说一些其他orm工具,如toplink,ojb等

 

 

3.1. 有关数据库的常问面试题和笔试题?

1)学生,成绩,老师,课程联表查询有关数据库笔试题?

http://www.cnblogs.com/qixuejia/p/3637735.html 数据库笔试题(出题率99%)

 

3.2. 什么是存储过程,使用存储过程的好处?

存储过程是一组预编译的sql语句。

优点:

(1)允许模块化程序设计,就是说只需要创建一次过程,以后在程序中就可以调用该过程任意次。

(2)允许更快执行,如果某操作需要执行大量 SQL 语句或重复执行,存储过程比 SQL 语句执行的要快。

(3)减少网络流量,例如一个需要数百行的 SQL 代码的操作有一条执行语句完成,不需要在网络中发

送数百行代码。

(4) 更好的安全机制,对于没有权限执行存储过程的用户,也可授权他们执行存储过程。

存储过程的具体使用:http://www.cnblogs.com/yank/p/4235609.html

 

3.3. 谈谈你知道的sql性能优化?

a. 使用limit 1。在我们知道查询结果只有一条数据时加上LIMIT 1这样MySQL数据库引擎会在查询到一条数据后停止搜索,不在继续查询下一跳符合记录的数据

b. 使用Not Exists代替Not In。在多条件(多表)查询中,需排除某一特定条件时,使用Not Exists,因为Not In不能使用索引查询

c. 尽量不采用不使用索引进行数据操作的操作符。比如:in、not inis nullis not null<>等

d. mysql进行分库分表操作。

垂直切分:即将表按照功能模块、关系密切程度划分出来,部署到不同的库上。

水平切分:当一个表中的数据量过大时,我们可以把该表的数据按照某种规则,例如 userID 散列,进行划分,然后存储到多个结构相同的表,和不同的库上

 

3.4. 事务介绍

mysql和其它的数据库产品有一个很大的不同就是事务由存储引擎所决定,例如MYISAM,MEMORY,ARCHIVE都不支持事务,事务就是为了解决一组查询要么全部执行成功,要么全部执行失败。

mysql事务默认是采取自动提交的模式,除非显示开始一个事务

SHOW VARIABLES LIKE 'AUTOCOMMIT';

 

修改自动提交模式,0=OFF,1=ON

注意:修改自动提交对非事务类型的表是无效的,因为它们本身就没有提交和回滚   的概念,还有一些命令是会强制自动提交的,比如DLL命令、lock tables等。

SET AUTOCOMMIT=OFF或 SET AUTOCOMMIT=0

事务的ACID(四大)特性是什么?

答:数据库事务transanction正确执行的四个基本要素。ACID,原子性(Atomicity)、一致性(Correspondence)、隔离性(Isolation)、持久性(Durability)
1)原子性:整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
2)一致性:在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
3)隔离性:隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行 相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆, 必须串行化或序列化请 求,使得在同一时间仅有一个请求用于同一数据。
4)持久性:在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。

mysql有四种隔离级别分别是什么:

  未提交读READ UNCOMMITTED):未提交读隔离级别也叫读脏,就是事务可以读取其它事务未提交的数据。

      提交读READ COMMITTED):在其它数据库系统比如SQL Server默认的隔离级别就是提交读,已提交读隔离级别就是在事务未提交之前所做的修改其它事务是不可见的。

      可重复读REPEATABLE READ):保证同一个事务中的多次相同的查询的结果是一致的,比如一个事务一开始查询了一条记录然后过了几秒钟又执行了相同的查询,保证两次查询的结果是相同的,可重复读也是mysql的默认隔离级别。

      可串行化SERIALIZABLE):可串行化就是保证读取的范围内没有新的数据插入,比如事务第一次查询得到某个范围的数据,第二次查询也同样得到了相同范围的数据,中间没有新的数据插入到该范围中。

 

3.5. 内连接,左外连接,右外连接,全外连接,交叉连接?

两张简单的信息表来说明问题

test1:

 

test2:

 

答: 内连接  只连接匹配的行

     SELECT     dbo.test1.name, dbo.test1.sex, dbo.test2.name2, dbo.test2.age  

1. FROM         dbo.test1  inner JOIN dbo.test2  on test1.name =test2.name2

 

  左外连接包含左边表的全部行(不管右边的表中是否存在与它们匹配的行)以及右边

表中全部匹配的行

1. SELECT     dbo.test1.name, dbo.test1.sex, dbo.test2.name2, dbo.test2.age  

2. FROM         dbo.test1  left JOIN dbo.test2  on test1.name =test2.name2

 

 右外连接包含右边表的全部行(不管左边的表中是否存在与它们匹配的行)以及左边表

中全部匹配的行

1. SELECT     dbo.test1.name, dbo.test1.sex, dbo.test2.name2, dbo.test2.age  

2. FROM         dbo.test1  right JOIN dbo.test2  on test1.name =test2.name2

   

 全外连接包含左、右两个表的全部行,不管在另一边的表中是否存在与它们匹配行

1. SELECT     dbo.test1.name, dbo.test1.sex, dbo.test2.name2, dbo.test2.age  

2. FROM        dbo.test1  full outer JOIN dbo.test2  on test1.name =test2.name2

 

 交叉连接: 生成笛卡尔积——它不使用任何匹配或者选取条件,而是直接将一个数据

源中的每个行与另一个数据源的每个行一一匹配;

1. SELECT     dbo.test1.name, dbo.test1.sex, dbo.test2.name2, dbo.test2.age  

2. FROM         dbo.test1 CROSS JOIN   dbo.test2

 

 

3.6. oracle数据库之事务有哪些?

1.什么是事务

在数据库中事务是工作的逻辑单元,一个事务是由一个或多个完成一组的相关行为的 SQL语句组成,通过事务机制确保这一组SQL语句所作的操作要么都成功执行,完成整 个工作单元操作,要么一个也不执行。

如:网上转帐就是典型的要用事务来处理,用以保证数据的一致性。

2.事务特性

    原子性(Atomicity):一个事务里面所有包含的SQL语句是一个执行整体,不可分割, 要么都做,要么都不做。

一致性(Consistency):事务开始时,数据库中的数据是一致的,事务结束时,数据库 的数据也应该是一致的。

隔离性(Isolation):是指数据库允许多个并发事务同时对其中的数据进行读写和修改 的能力,隔离性可以防止事务的并发执行时,由于他们的操作命令交叉执行而导致的数 据不一致状态。

持久性 (Durability) : 是指当事务结束后,它对数据库中的影响是永久的,即便系统 遇到故障的情况下,数据也不会丢失。

     3.事务隔离级别

隔离级别

脏读

不可重复读

幻读

Read uncommitted(读未提交)

Read committed(读已提交)

Repeatable read(可重复读)

Serializable(串行读)

          

 

 

 

 

   Oracle默认的隔离级别是read committed。

Oracle支持上述四种隔离级别中的两种:read committed 和serializable。除此之外,Oralce中还定义Read only和Read write隔离级别。

Read only:事务中不能有任何修改数据库中数据的操作语句,是Serializable的一个子集。

Read write:它是默认设置,该选项表示在事务中可以有访问语句、修改语句,但不经常使用。

3.7. Oracle 创建存储过程怎么写?

       注意:oracle的存储过成是有一定难度的,看不懂的就说自己没用过。

create or replace procedure test_count
as
v_total number(1);
begin

select count(*) into v_total from TESTTABLE;
   DBMS_OUTPUT.put_line('总人数:'||v_total);
end;
--准备
--线对scott解锁:alter user scott account unlock; 
--应为存储过程是在scott用户下。还要给scott赋予密码
---alter user scott identified by tiger;
---去命令下执行
EXECUTE test_count;
----ql/spl中的sql中执行
begin
   -- Call the procedure
   test_count;
end;

参考资料:http://blog.csdn.net/o9109003234/article/details/24910039

3.8、如何使用Oracle的游标?

1.oracle中的游标分为显示游标和隐式游标 
2.显示游标是用cursor...is命令定义的游标,它可以对查询语句(select)返回的

条记录进行处理;隐式游标是在执行插入 (insert)、删除(delete)、修改(update) 和返回单条记录的查询(select)语句时由PL/SQL自动定义的。 
3. 显式游标的操作:打开游标、操作游标、关闭游标;PL/SQL隐式地打开SQL游标,并在它内部处理SQL语句,然后关闭它。

3.9Oracle中字符串用什么符号链接?

答: Oracle中使用 || 这个符号连接字符串 如 ‘abc|| d 

3.10Oracle是怎样分页的?

Oracle中使用rownum来进行分页, 这个是效率最好的分页方法,hibernate也是使用rownum来进行oralce分页的 
select * from 
  ( select rownum r,a from tabName where rownum <= 20 ) 
where r > 10  

3.11、什么是存储过程?它有什么优点?

答:存储过程是一组予编译的SQL语句,

 它的优点有:

  允许模块化程序设计,就是说只需要创建一次过程,以后在程序中就可以调用该过程

任意次。

  允许更快执行,如果某操作需要执行大量SQL语句或重复执行,存储过程比SQL语句执 行的要快。

  减少网络流量,例如一个需要数百行的SQL代码的操作有一条执行语句完成,不需要在 网络中发送数百行代码。

  更好的安全机制,对于没有权限执行存储过程的用户,也可授权他们执行存储过程。

3.12、存储过程和函数有什么区别?

  Oracle中的函数与存储过程的区别:

   1. 函数必须有返回值,而过程没有.

   2. 函数可以单独执行.而过程必须通过execute执行.

   3. 函数可以嵌入到SQL语句中执行.而过程不行.

      其实我们可以将比较复杂的查询写成函数.然后到存储过程中去调用这些函数.   

3.13 Oracle中的函数与存储过程的特点:

  1. 一般来说,存储过程实现的功能要复杂一点,而函数的实现的功能针对性比较强。

  2. 对于存储过程来说可以返回参数,而函数只能返回值或者表对象。

  3. 存储过程一般是作为一个独立的部分来执行,而函数可以作为查询语句的一个部分来调用,由于函数可以返回一个表对象,因此它可以在查询语句中位于FROM关键字的后面。

 

3.14. 非关系型数据库

1.1.1.1 1、Redis

1.1、什么是redis?

Redis 是一个基于内存的高性能key-value数据库

1.2 、Reids的特点?

Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB
Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存多种数据结构,此外单value的最大限制是1GB,不像 memcached只能保存1MB的数据,另外Redis也可以对存入的Key-Value设置expire时间

Redis主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。

1.3、 为什么redis需要把所有数据放到内存中?

Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以redis具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。在内存越来越便宜的今天,redis将会越来越受欢迎。
如果设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。

1.4、 Redis常见的性能问题都有哪些?如何解决?

1. Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。

 

2. Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。

 

3. Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。

4. Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内

1.5、redis最适合的场景有哪些?

1)、会话缓存(Session Cache)

2)、全页缓存(FPC)

3)、队列

4)、排行榜/计数器

5)、发布/订阅

 

3.15.数据库语句优化

1、Mysql sql语句优化:

Mysql语句优化:

1、问:where 子句中可以对字段进行null值判断吗?

select id from t where num is null

       答:最好不要给数据库留NULL,尽可能的使用 NOT NULL填充数据库.

不要以为 NULL 不需要空间,比如:char(100) 型,在字段建立时,空间 就固定了,不管是否插入值(NULL也包含在内),都是占用100个字符 的空间的,如果是varchar 这样的变长字段,null不占用空间。

可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:

select id from t where num = 0

 

2、问:select * from admin left join log on admin.admin_id = log.admin_id where log.admin_id>10  优化

优化为: select * from (select * from admin where admin_id>10) T1 lef join log on T1.admin_id = log.admin_id

答:使用JOIN 时候,应该用小的结果驱动大的结果(left join 左边表结果尽量小如果有条件应该放到左边先处理,right join 同理反向),同事尽量把牵涉到多表联合的查询拆分多个query(多个连表查询效率低,容易到之后锁表和阻塞)。

 3、注意LIKE 模糊查询的使用, 避免使用 %% ,可以使用 后面带% ,双%是不走索引的。

          例:select * from admin where admin name like %de’ 优化

       优化为 select * from admin where admin_name >='de' and admin_nam <'df' 

4、limit 的基数比较大时使用between。

         例:select * from admin order by admin_id limit 100000,10 优化

         优化为:select * from admin where admin_id between 100000 admin 100010 order by admin_id

5、 尽量避免在列上做运算,这样导致索引失效。

例:select * from admin where year(admin_time)>2014 优化

优化为: select * from admin where admin_time> '2014-01-01

 

1.1.1.2 2、oracle sql语句优化有哪些?

(1)选择最有效率的表名顺序

ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必

须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在

WHERE子句的末尾.

            

   2) WHERE子句中的连接顺序.

ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必   

须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在

WHERE子句的末尾.

3)SELECT子句中避免使用 ‘ * ‘  

4)在SQL*Plus , SQL*Forms和Pro*C中重新设置ARRAYSIZE参数, 可以增加每   

次数据库访问的检索数据量 ,建议值为200

      5) 删除重复记录:

最高效的删除重复记录方法 ( 因为使用了ROWID)例子:

1

2

DELETE FROM EMP E WHERE E.ROWID > (SELECT MIN(X.ROWID)

FROM EMP X WHERE X.EMP_NO = E.EMP_NO);

 

你可能感兴趣的:(面试)