5.數據庫知識點總結

1.用兩種方式根據部門號從高到低,工資從低到高列出每個員工的信息。

employee:

    eid,ename,salary,deptid;

 select * from employee order by deptiddesc,salary

 2.列出各個部門中工資高於本部門的平均工資的員工數和部門號,並按部門號排序

創建表:

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

0),salary bigint,deptid int);

 

插入實驗數據:

mysql> insert into employee921values(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 employee921group by deptid;

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

tid tid from  employee921 where salary > (selectavg(salary) from employee921 where deptid = tid);

   效率低的一個語句,僅供學習參考使用(在group by之後不能使用where,只能使用having,在group by之前可以使用where,即表示對過濾後的結果分組):

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

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

()selectcount(*) ,tid

     from(

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

         from     employee921

         wheresalary >

              (selectavg(salary) from employee921 where deptid = tid)

     )as t

     groupby 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 anda.salary>b.avgsal;

3.存儲過程與觸發器必須講,經常被面試到?

create procedure insert_Student (_namevarchar(50),_age int ,out _id int)

begin

     insertinto student value(null,_name,_age);

     selectmax(stuId) into _id from student;

end;

 

call insert_Student('wfz',23,@id);

select @id;

 

mysql> create trigger update_StudentBEFORE update on student FOR EACH ROW

->select * from student;

觸發器不允許返回結果

 

createtrigger update_Student BEFORE update on student FOR EACH ROW 

insertinto  student value(null,'zxx',28);

mysql的觸發器目前不能對當前表進行操作

 

createtrigger update_Student BEFORE update on student FOR EACH ROW 

deletefrom articles  where id=8;

這個例子不是很好,最好是用刪除一個用戶時,順帶刪除該用戶的所有帖子

這裏要注意使用OLD.id

 

觸發器用處還是很多的,比如校內網、開心網、Facebook,你發一個日誌,自動通知好友,其實就是在增加日誌時做一個後觸發,再向通知表中寫入條目。因爲觸發器效率高。而UCH沒有用觸發器,效率和數據處理能力都很低。

存儲過程的實驗步驟:

mysql>delimiter |

mysql>create procedure insertArticle_Procedure (pTitle varchar(50),pBid int,out

 pId int)

    -> begin

    -> insert into article1value(null,pTitle,pBid);

    -> select max(id) into pId fromarticle1;

    -> end;

    -> |

Query OK, 0 rows affected (0.05 sec)

 

mysql>call insertArticle_Procedure('傳智播客',1,@pid);

    -> |

Query OK, 0 rows affected (0.00 sec)

 

mysql>delimiter ;

mysql>select @pid;

+------+

|@pid |

+------+

|3    |

+------+

1row in set (0.00 sec)

 

mysql>select * from article1;

+----+--------------+------+

|id | title        | bid  |

+----+--------------+------+

|1  | test         | 1   |

|2  | chuanzhiboke | 1    |

|3  | 傳智播客     | 1   |

+----+--------------+------+

3rows in set (0.00 sec)

 

觸發器的實驗步驟:

createtable board1(id int primary key auto_increment,name varchar(50),ar

ticleCountint);

 

createtable article1(id int primary key auto_increment,title varchar(50)

,bidint references board1(id));

 

delimiter|

 

createtrigger insertArticle_Trigger after insert on article1 for each ro

wbegin

    -> update board1 setarticleCount=articleCount+1 where id= NEW.bid;

    -> end;

    -> |

 

delimiter;

 

insertinto board1 value (null,'test',0);

 

insertinto article1 value(null,'test',1);

還有,每插入一個帖子,都希望將版面表中的最後發帖時間,帖子總數字段進行同步更新,用觸發器做效率就很高。下次課設計這樣一個案例,寫觸發器時,對於最後發帖時間可能需要用declare方式聲明一個變量,或者是用NEW.posttime來生成。

 

4.數據庫三範式是什麼?

第一範式(1NF):字段具有原子性,不可再分。所有關係型數據庫系統都滿足第一範式)

     數據庫表中的字段都是單一屬性的,不可再分。例如,姓名字段,其中的姓和名必須作爲一個整體,無法區分哪部分是姓,哪部分是名,如果要區分出姓和名,必須設計成兩個獨立的字段。

 

 第二範式(2NF):

第二範式(2NF)是在第一範式(1NF)的基礎上建立起來的,即滿足第二範式(2NF)必須先滿足第一範式(1NF)。

要求數據庫表中的每個實例或行必須可以被惟一地區分。通常需要爲表加上一個列,以存儲各個實例的惟一標識。這個惟一屬性列被稱爲主關鍵字或主鍵。

 

第二範式(2NF)要求實體的屬性完全依賴於主關鍵字。所謂完全依賴是指不能存在僅依賴主關鍵字一部分的屬性,如果存在,那麼這個屬性和主關鍵字的這一部分應該分離出來形成一個新的實體,新實體與原實體之間是一對多的關係。爲實現區分通常需要爲表加上一個列,以存儲各個實例的惟一標識。簡而言之,第二範式就是非主屬性非部分依賴於主關鍵字。

  

 第三範式的要求如下:

滿足第三範式(3NF)必須先滿足第二範式(2NF)。簡而言之,第三範式(3NF)要求一個數據庫表中不包含已在其它表中已包含的非主關鍵字信息。

所以第三範式具有如下特徵:
         1,每一列只有一個值
         2,每一行都能區分。
         3,每一個表都不包含其他表已經包含的非主關鍵字信息。

例如,帖子表中只能出現發帖人的id,而不能出現發帖人的id,還同時出現發帖人姓名,否則,只要出現同一發帖人id的所有記錄,它們中的姓名部分都必須嚴格保持一致,這就是數據冗餘。

 

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.  selecte.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 mwhere

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

 

表中允許適當冗餘,譬如,主題帖的回覆數量和最後回覆時間等

將姓名和密碼單獨從用戶表中獨立出來。這可以是非常好的一對一的案例喲!

 

sql語句全部大寫,特別是列名和表名都大寫。特別是sql命令的緩存功能,更加需要統一大小寫,sql語句à發給oracle服務器à語法檢查和編譯成爲內部指令à緩存和執行指令。根據緩存的特點,不要拼湊條件,而是用?和PreparedStatment

 

還有索引對查詢性能的改進也是值得關注的。

 

備註:下面是關於性能的討論舉例

 

4航班 3個城市

 

m*n

 

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

 

m + n

 

 

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

 

selectflight.id,'beijing',flight.flightTime from flight where startcityid = (selectcityid from city where cityname='beijing')

6.union和union all有什麼不同?

假設我們有一個表Student,包括以下字段與數據:

drop table student;

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

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

commit;

Union和UnionAll的區別。

select *
from student
where id < 4

union

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

結果將是

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

如果換成Union All連接兩個結果集,則返回結果是:

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

可以看到,Union和Union All的區別之一在於對重複結果的處理。

 

  UNION在進行錶鏈接後會篩選掉重複的記錄,所以在錶鏈接後會對所產生的結果集進行排序運算,刪除重複的記錄再返回結果。實際大部分應用中是不會產生重複的記錄,最常見的是過程表與歷史表UNION。如:
select * from gc_dfys
union
select * from ls_jg_dfys
  這個SQL在運行時先取出兩個表的結果,再用排序空間進行排序刪除重複的記錄,最後返回結果集,如果表數據量大的話可能會導致用磁盤進行排序。
 而UNION ALL只是簡單的將兩個結果合併後就返回。這樣,如果返回的兩個結果集中有重複的數據,那麼返回的結果集就會包含重複的數據了。
 從效率上說,UNION ALL 要比UNION快很多,所以,如果可以確認合併的兩個結果集中不包含重複的數據的話,那麼就使用UNION ALL,

7.分頁語句

取出sql表中第31到40的記錄(以自動增長ID爲主鍵)

sql server方案1

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

sql server方案2

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

 

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 articleslimit " + (pageNo-1)*pageSize + "," + pageSize;

oracle: sql = "select * from " +

                                                        "(selectrownum r,* from " +

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

                                                        "whererownum<= " + pageNo*pageSize +") tmp " +

                                 "wherer>" + (pageNo-1)*pageSize;

註釋:第7行保證rownum的順序是確定的,因爲oracle的索引會造成rownum返回不同的值

簡洋提示:沒有order by時,rownum按順序輸出,一旦有了order by,rownum不按順序輸出了,這說明rownum是排序前的編號。如果對order by從句中的字段建立了索引,那麼,rownum也是按順序輸出的,因爲這時候生成原始的查詢結果集時會參照索引表的順序來構建。

 

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

 

DataSource ds = newInitialContext().lookup(jndiurl);

Connection cn = ds.getConnection();

//"select * from user whereid=?"  --->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 = newInitialContext().lookup(jndiurl);

Connection cn = ds.getConnection();

//"select * from user whereid=?"  --->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(Exceptione){}

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

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

}

 

3.可滾動的遊標

pageSize=20;

pageNo = 5;

cn = null

stmt = null;

rs = null;

try

{

sqlserver:sql = "select  * from articles";

 

DataSource ds = newInitialContext().lookup(jndiurl);

Connection cn = ds.getConnection();

//"select * from user whereid=?"  --->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(Exceptione){}

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

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

}

8.用一條SQL語句 查詢出每門課都大於80分的學生姓名 

name  kecheng   fenshu
張三    語文      81
張三    數學      75
李四    語文      76
李四    數學      90
王五    語文      81
王五    數學      100
王五    英語      90

準備數據的sql代碼:

create table score(id int primary keyauto_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);

 

提示:當百思不得其解時,請理想思維,把小變成大做,把大變成小做,

 

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

 

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

 

9.所有部門之間的比賽組合

一個叫department的表,裏面只有一個字段name,一共有4條紀錄,分別是a,b,c,d,對應四個球對,現在四個球對進行比賽,用一條sql語句顯示所有可能的比賽組合.

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

 

10.每個月份的發生額都比101科目多的科目

請用SQL語句實現:從TestDB數據表中查詢出所有月份的發生額都比101科目相應月份的發生額高的科目。請注意:TestDB中有很多科目,都有1-12月份的發生額。
AccID:科目代碼,Occmonth:發生額月份,DebitOccur:發生額。
數據庫名:JcyAudit,數據集:Select * fromTestDB

準備數據的sql代碼:

drop table if exists TestDB;

create table TestDB(id int primary keyauto_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);

答案:
select distinct AccID from TestDB

where AccID not in

       (selectTestDB.AccIDfrom TestDB,

          (select * from TestDB where AccID='101') asdb101

     whereTestDB.Occmonth=db101.Occmonth and TestDB.DebitOccur<=db101.DebitOccur

     );

 

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 ifexists sales;

create tablesales(id int auto_increment primary key,year varchar(10), month varchar(10),amount float(2,1));

insert intosales 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 ,

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

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

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

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

fromsales  group by year;

 

12.顯示文章標題,發帖人、最後回覆時間

表:id,title,postuser,postdate,parentid

準備sql語句:

drop table if exists articles;

create table articles(id intauto_increment primary key,title varchar(50), postuser varchar(10), postdatedatetime,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,

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

from articles a where a.parentid is null;

 

註釋:子查詢可以用在選擇列中,也可用於where的比較條件中,還可以用於from從句中。

13.刪除除了id號不同,其他都相同的學生冗餘信息

2.學生表 如下:
id
  學號  姓名課程編號 課程名稱 分數
1
        2005001 張三  0001     數學    69
2
        2005002 李四  0001     數學    89
3
        2005001 張三  0001     數學    69
A: delete from tablename where id
號 notin(select min(id號) from tablename group by 學號,姓名,課程編號,課程名稱,分數)

實驗:

create table student2(id intauto_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 notin(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 notin(select mid from (select min(id) mid

from student2 group by name) as t);

或者:

delete from student2 where id notin(select min(id) from (select * from s

tudent2) as t group by t.name);

14.航空網的幾個航班查詢題:

表結構如下:

flight{flightID,StartCityID,endCityID,StartTime}

city{cityID, CityName)

實驗環境:

create table city(cityID intauto_increment primary key,cityName varchar(20));

create table flight (flightID intauto_increment primary key,

     StartCityIDint references city(cityID),

     endCityID  int references city(cityID),

     StartTimetimestamp);

//航班本來應該沒有日期部分纔好,但是下面的題目當中涉及到了日期

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

     wheref.endcityid = c.cityid and startcityid =

     (selectc1.cityid from city c1 where c1.cityname = "北京")

     orderby c.cityname asc;

 

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

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

ere cityname='北京');

 

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

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

yID order by e.cityName desc;

 

 

2、查詢北京到上海的所有航班紀錄(起飛城市,到達城市,起飛時間,航班號)

selectc1.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 wheredate_format(starttime,'%Y-%m-%d')='1998-01-02'

15.查出比經理薪水還高的員工信息:

Drop table if not exists employees;

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

,salaryint,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 mwhere e.managerid=m.id and e.sala

ry>m.salary;

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.只要是迪卡爾積,就會產生“垃圾”信息,所以,只要迪卡爾積了,我們首先就要想到清除“垃圾”信息

實驗準備:

     droptable if exists tea_stu;

     droptable if exists teacher;

     droptable 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 referencesteacher(teaID),stuID int references student(stuID));

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

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

insertinto tea_stu values(1,1), (1,2), (1,3);

insertinto tea_stu values(2,2), (2,3), (2,4);

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

insertinto tea_stu values(4,4), (4,1), (4,2) , (4,3);

 

結果:2à3,3à2,4à3

 

解題思路:(真實面試答題時,也要寫出每個分析步驟,如果紙張不夠,就找別人要)

1要會統計分組信息,統計信息放在中間表中:

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

 

2接着其實應該是篩除掉小於12歲的學生,然後再進行統計,中間表必須與student關聯才能得到12歲以下學生和把該學生記錄從中間表中剔除,代碼是:

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

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

 

3.接着把上面的結果做成虛表與teacher進行關聯,並篩除大於45的老師

selectteacher.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>12group by tea_stu.teaid) as tea_stu2 where teacher.teaid=tea_stu2.tea

idand teacher.age<45;

 

 

17.求出發帖最多的人:

select authorid,count(*) total fromarticles

group by authorid

having total=

(selectmax(total2) from (select count(*) total2 from articles group by authorid) ast);

 

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

(selectauthorid,count(*) total from articles )as t

這條語句不行,因爲max只有一列,不能與其他列混淆。

 

select authorid,count(*) total fromarticles

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

 

18.一個用戶表中有一個積分字段,假如數據庫中有100多萬個用戶,若要在每年第一天凌晨將積分清零,你將考慮什麼,你將想什麼辦法解決?

alter table drop column score;

alter table add colunm score int;

可能會很快,但是需要試驗,試驗不能拿真實的環境來操刀,並且要注意,

這樣的操作時無法回滾的,在我的印象中,只有inertupdate delete等DML語句才能回滾,

對於create table,drop table ,altertable等DDL語句是不能回滾。

 

 

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

解決方案二,假設上面的代碼要執行好長時間,超出我們的容忍範圍,那我就alter table user drop column score;alter table user add column scoreint

 

下面代碼實現每年的那個凌晨時刻進行清零。

Runnable runnable =

     newRunnable(){

         publicvoid run(){

              clearDb();

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

              }       

              };

 

schedule(runnable,

     newDate(new Date().getYear()+1,0,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;

19.公司的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 DepartmentsStructure:

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 (salarybetween 1000 and 200)

     orleft(last_name,3)='abc';

 

(3) 基於上述EMPLOYEES表寫出查詢:查出部門平均工資大於1800元的部門的所有員工,列出這些員工的全部個人信息。(4分)

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

 fromemployee1 where deptid = did) > 1800;

 

(4) 基於上述EMPLOYEES表寫出查詢:查出個人工資高於其所在部門平均工資的員工,列出這些員工的全部個人信息及該員工工資高出部門平均工資百分比。(5分)

selectemployee1.*,(employee1.salary-t.avgSalary)*100/employee1.salary

from employee1,

     (selectdeptid,avg(salary) avgSalary from employee1 group by deptid) as t

where employee1.deptid = t.deptid andemployee1.salary>t.avgSalary;

 

20.註冊Jdbc驅動程序的三種方式

 

21.用JDBC如何調用存儲過程

代碼如下:

package com.huawei.interview.lym;

 

import java.sql.CallableStatement;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.sql.Types;

 

public class JdbcTest {

 

     /**

      * @paramargs

      */

     public static voidmain(String[] args) {

         // TODO Auto-generated method stub

         Connectioncn = null;

         CallableStatementcstmt = null;     

         try {

              //這裏最好不要這麼幹,因爲驅動名寫死在程序中了

              Class.forName("com.mysql.jdbc.Driver");

              //實際項目中,這裏應用DataSource數據,如果用框架,

              //這個數據源不需要我們編碼創建,我們只需Datasource ds = context.lookup()

              //cn =ds.getConnection();          

              cn =DriverManager.getConnection("jdbc:mysql:///test","root","root");

              cstmt= cn.prepareCall("{call insert_Student(?,?,?)}");

              cstmt.registerOutParameter(3,Types.INTEGER);

              cstmt.setString(1,"wangwu");

              cstmt.setInt(2,25);

              cstmt.execute();

              //get第幾個,不同的數據庫不一樣,建議不寫

              System.out.println(cstmt.getString(3));

         } catch (Exception e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

         }

         finally

         {

 

              /*try{cstmt.close();}catch(Exceptione){}

              try{cn.close();}catch(Exceptione){}*/

              try {

                   if(cstmt != null)

                       cstmt.close();

                   if(cn != null)                  

                       cn.close();

              } catch (SQLException e) {

                   //TODO Auto-generated catch block

                   e.printStackTrace();

              }

         }

     }

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 whereid =?--- -à又會怎麼幹?

 上面說的是性能提高

可以防止sql注入。

23.寫一個用jdbc連接並訪問oracle數據的程序代碼

24.Class.forName的作用?爲什麼要用?

答:按參數中指定的字符串形式的類名去搜索並加載相應的類,如果該類字節碼已經被加載過,則返回代表該字節碼的Class實例對象,否則,按類加載器的委託機制去搜索和加載該類,如果所有的類加載器都無法加載到該類,則拋出ClassNotFoundException。加載完這個Class字節碼後,接着就可以使用Class字節碼的newInstance方法去創建該類的實例對象了。

有時候,我們程序中所有使用的具體類名在設計時(即開發時)無法確定,只有程序運行時才能確定,這時候就需要使用Class.forName去動態加載該類,這個類名通常是在配置文件中配置的,例如,spring的ioc中每次依賴注入的具體類就是這樣配置的,jdbc的驅動類名通常也是通過配置文件來配置的,以便在產品交付使用後不用修改源程序就可以更換驅動類名。

25.大數據量下的分頁解決方法。

答:最好的辦法是利用sql語句進行分頁,這樣每次查詢出的結果集中就只包含某頁的數據內容。再sql語句無法實現分頁的情況下,可以考慮對大的結果集通過遊標定位方式來獲取某頁的數據。

sql語句分頁,不同的數據庫下的分頁方案各不一樣,下面是主流的三種數據庫的分頁sql

sql server:

     Stringsql =

     "selecttop " + pageSize + " * from students where id not in" +

 

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

 

 "order by id";

 

mysql:

 

       Stringsql =

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

    

oracle:

 

       Stringsql =

      "select * from " + 

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

      "where t>" + pageSize*(pageNumber-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 “ +

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

     pstmt.setString(1,studentName);

     Resultsetrs = 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){}

}

 

 

27.這段代碼有什麼不足之處?

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

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

while(rs.next()) {

}
} catch(Exception ex) {
}

答:沒有finally語句來關閉各個對象,另外,使用finally之後,要把變量的定義放在try語句塊的外面,以便在try語句塊之外的finally塊中仍可以訪問這些變量。

 

28.說出數據連接池的工作機制是什麼?

J2EE服務器啓動時會建立一定數量的池連接,並一直維持不少於此數目的池連接。客戶端程序需要連接時,池驅動程序會返回一個未使用的池連接並將其表記爲忙。如果當前沒有空閒連接,池驅動程序就新建一定數量的連接,新建連接的數量有配置參數決定。當使用的池連接調用完成後,池驅動程序將此連接表記爲空閒,其他調用就可以使用這個連接。

實現方式,返回的Connection是原始Connection的代理,代理Connection的close方法不是真正關連接,而是把它代理的Connection對象還回到連接池中。

 

29.爲什麼要用 ORM? 和 JDBC 有何不一樣?

orm是一種思想,就是把object轉變成數據庫中的記錄,或者把數據庫中的記錄轉變成objecdt,我們可以用jdbc來實現這種思想,其實,如果我們的項目是嚴格按照oop方式編寫的話,我們的jdbc程序不管是有意還是無意,就已經在實現orm的工作了。

現在有許多orm工具,它們底層調用jdbc來實現了orm工作,我們直接使用這些工具,就省去了直接使用jdbc的繁瑣細節,提高了開發效率,現在用的較多的orm工具是hibernate。也聽說一些其他orm工具,如toplink,ojb等。 
發佈了44 篇原創文章 · 獲贊 3 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章