好的數據庫面試題集合

http://blog.csdn.net/sandyzhs/article/details/4059709

 在整理準備數據庫面試的過程中,先是在網上一頓海搜,找到歷史面試題,然後一個骨頭一個骨頭的啃完,現在基本上這些問題(或者說叫做實踐)都沒有問題了。遇到的困難是:PL/SQL居多,T-SQL太少,所以需要篩選,修改答案,甚至有一些在T-SQL裏面還沒有支持。

下一步再把數據庫T-SQL經典教程在翻看一遍,基本上對數據庫就算告一段落了,前前後後共整整1個多月的時間(去年10.1是二週,下載是三週),學習的還行吧。

下面的就是全部內容,大段摘錄的,或者是抄的,我都寫了出處;有一些實在忘記了,請見諒:向大家共享知識,想必也是作者的本願吧。

1.     三個範式

即: 屬性唯一,   記錄唯一,   表唯一

第一範式(1NF):數據庫表中的字段都是單一屬性的,不可再分。這個單一屬性由基本類型構成,包括整型、實數、字符型、邏輯型、日期型等。

第二範式(2NF):數據庫表中不存在非關鍵字段對任一候選關鍵字段的部分函數依賴(部分函數依賴指的是存在組合關鍵字中的某些字段決定非關鍵字段的情況),也即所有非關鍵字段都完全依賴於任意一組候選關鍵字。      第三範式(3NF):在第二範式的基礎上,數據表中如果不存在非關鍵字段對任一候選關鍵字段的傳遞函數依賴則符合第三範式。所謂傳遞函數依賴,指的是如果存在"A → B → C"的決定關係,則C傳遞函數依賴於A。因此,滿足第三範式的數據庫表應該不存在如下依賴關係: 關鍵字段 → 非關鍵字段x → 非關鍵字段y 

2.     一些常識:http://www.enet.com.cn/article/2007/0802/

A20070802755140.shtml

² 簡要敘述一下SQL Server 2000中使用的一些數據庫對象

表格、視圖、用戶定義的函數,存儲過程,觸發器等。

² NULL是什麼意思

NULL這個值表示UNKNOWN(未知):它不表示“”(空字符串)。假設您的SQL Server數據庫裏有ANSI_NULLS,當然在默認情況下會有,對NULL這個值的任何比較都會生產一個NULL值。您不能把任何值與一個 UNKNOWN值進行比較,並在邏輯上希望獲得一個答案。您必須使用IS NULL操作符

使用ISNULL(var,value)來進行NULL判斷:當var爲NULL的時候,var = value,並且返回value

² 什麼是索引?SQL Server 2000裏有什麼類型的索引?

索引是一個數據結構,用來快速訪問數據庫表格或者視圖裏的數據。在SQL Server裏,它們有兩種形式:聚集索引非聚集索引。聚集索引在索引的葉級保存數據。這意味着不論聚集索引裏有表格的哪個(或哪些)字段,這些字段都會按順序被保存在表格,物理順序和邏輯順序一致。由於存在這種排序,所以每個表格只會有一個聚集索引。非聚集索引在索引的葉級有一個行標識符。它允許每個表格有多個非聚集索引。

² 什麼是主鍵?什麼是外鍵?

主鍵是表格裏的(一個或多個)字段,只用來定義表格裏的行;主鍵裏的值總是唯一的。外鍵是一個用來建立兩個表格之間關係的約束。這種關係一般都涉及一個表格裏的主鍵字段與另外一個表(可能是同一表)裏的字段。那麼這些相連的字段就是外鍵。

² 什麼是觸發器?SQL Server 2000有什麼不同類型的觸發器?

INSTEAD-OF和AFTER兩種觸發器。觸發器是一種專用類型的存儲過程,它被捆綁到表格或者視圖上。INSTEAD-OF觸發器是替代數據操控語言(DML)語句對錶格執行語句的存儲過程。例如,如果我有一個用於TableA的INSTEAD-OF-UPDATE觸發器,同時對這個表格執行一個更新語句,那麼INSTEAD-OF-UPDATE觸發器裏的代碼會執行,而不是我執行的更新語句則不會執行操作。

AFTER觸發器要在DML語句在數據庫裏使用之後才執行。這些類型的觸發器對於監視發生在數據庫表格裏的數據變化十分好用。

² 您如何確一個帶有名爲Fld1字段的TableB表格裏只具有Fld1字段裏的那些值,而這些值同時在名爲TableA的表格的Fld1字段裏?

第一個答案(而且是您希望聽到的答案)是使用外鍵限制。外鍵限制用來維護引用的完整性integrity。它被用來確保表格裏的字段只保存有已經在不同的(或者相同的)表格裏的另一個字段裏定義了的值。這個字段就是候選鍵(通常是另外一個表格的主鍵)。  另外一種答案是觸發器。觸發器可以被用來保證以另外一種方式實現與限制相同的作用,但是它非常難設置與維護,而且性能一般都很糟糕。由於這個原因,微軟建議開發人員使用外鍵限制而不是觸發器來維護引用的完整性。

² 對一個投入使用的在線事務處理表格(OLTP)有過多索引需要有什麼樣的性能考慮?

對一個表格的索引越多,數據庫引擎用來更新、插入或者刪除數據所需要的時間就越多,因爲在數據操控發生的時候索引也必須要維護。

² 你可以用什麼來確保表格裏的字段只接受特定範圍裏的值?

Check限制,它在數據庫表格裏被定義,用來限制輸入該列的值。  觸發器也可以被用來限制數據庫表格裏的字段能夠接受的值,但是這種辦法要求觸發器在表格裏被定義,這可能會在某些情況下影響到性能。

² 返回參數總是由存儲過程返回,它用來表示存儲過程是成功還是失敗。返回參數總是INT數據類型。

OUTPUT參數明確要求由開發人員來指定,它可以返回其他類型的數據,例如字符型和數值型的值。(可以用作輸出參數的數據類型是有一些限制的。)您可以在一個存儲過程裏使用多個OUTPUT參數,而您只能夠使用一個返回參數。

² 什麼是相關子查詢?如何使用這些查詢?

相關子查詢是一種包含子查詢的特殊類型的查詢。查詢裏包含的子查詢會真正請求外部查詢的值,從而形成一個類似於循環的狀況。

11. 某一列允許NULL值,但希望確保所有的非空(Non-NULL)值都是唯一的  SQL Server沒有實現非NULL值唯一性的內建機制,因此需要通過自定義的trigger:

Create trigger mytrigger on t1 for insert, update as

BEGIN

IF (select max(cnt) from (select count(i.c1)as cnt

from t1, inserted i where t1.c1=i.c1 group by i.c1) x) > 1

ROLLBACK TRAN

END

3.     某列裏最大或最小的前幾個,或是大於或小於某一個值(最大值或平均值)的數據

http://www.blogjava.net/looline/archive/2006/12/08/86367.html

** HAVING子句對GROUP BY子句設置條件的方式與WHERE子句和SELECT語句交互的方式類似。WHERE子句搜索條件在進行分組操作之前應用;而HAVING搜索條件在進行分組操作之後應用。HAVING語法與WHERE語法類似,但HAVING可以包含聚合函數。HAVING子句可以引用選擇列表中出現的任意項。

² 顯示數據庫中的最後一條記錄的所有字段(ID是自增的)

SELECT top 1 * FROM Table_Name ORDER BY ID DESC -- 或者

SELECT * FROM Table_Name WHERE ID=(SELECT MAX (ID) FROM Table_Name)

² 顯示數據庫中的最後十條記錄的所有字段(ID 是自增的  DESC 做降序 ASC 做升序)

SELECT top 10 * FROM Table_Name ORDER BY ID DESC

² 對來自表 authors 的前十個作者的 state 列進行更新

UPDATE s SET s.saleprice = s.saleprice+2

FROM (SELECT TOP 10 * FROM sales ORDER BY saleid) AS t1, sales s

WHERE s.saleid=t1.saleid

-- 或者

UPDATE s SET s.saleprice = s.saleprice+2 FROM sales s

WHERE s.saleid in (SELECT TOP 10 saleid FROM sales ORDER BY saleid)

² 找出公司裏收入最高的前三名員工

select top 3 * from t1  order by a desc --或者

Select top 3 *, ROW_NUMBER() OVER(order by a DESC) as No from  t1

(根據分析,執行計劃中的順序:sort (order by )+ top 3, 然後是where等條件)

² 找出公司裏收入最高(低)的三->五名員工

select top 3 a from t1 where  a in ( select top 5 a from t1  order by a asc) order by a desc

--弊端:參與排序的一定要是index,或者unique,且選出來的只能是單一的一個列

-- 所以用下面的方法

SELECT top (10-3+1) * FROM (SELECT TOP 10 * FROM customers Order by zip asc)t order by zip desc

² 取出表A中第31條到第40條記錄(SQLServer,以自動增長的ID爲主鍵,注意:ID可能不是連續的。)

-- top 10 可以省略

SELECT top 10 * FROM A WHERE ID not in (SELECT top 30 id FROM A)

² 顯示出員工的平均工資大於3000元的部門名稱(用SQL語句)

注意Full outer join,left join, right join,inner join區別和聯繫

SELECT Dept_Name

FROM t_Dept

WHERE ID in (SELECT Dept_IDFROM t_Salary

GROUP BY Dept_ID             --對部門分組(即:相同部門的,進行同一操作)

Having avg(Salary)>3000)

² 找出那些工資高於他們所在部門的平均工資的員工

select last_name, dept_id, salary from s_emp a  where salary>(select avg(salary) from s_emp where dept_id=a.dept_id)

² 找出那些工資高於他們所在部門的 manager 的工資的員工。

 select id, last_name, salary, manager_id   from s_emp a   where salary>(select salary  from s_emp where id=a.manager_id)

²  有兩個表分別如下:  表A(varchar(32) NAME,int GRADE)

數據:ZHANGSHAN 80, LISI 60, WANGWU 84 表B(varchar(32) NAME,int AGE) 數據:ZHANGSHAN 26, LISI 24, WANGWU 26, WUTIAN 26 1)寫SQL語句得到如下查詢結果:  NAME      GRADE   AGE   ZHANGSHAN    80      26 LISI      60      24 WANGWU     84      26 WUTIAN      NULL    26

答:select * from A right join B on A.NAME = B.NAME 2)寫SQl語句根據名字(NAME)相同按年齡(AGE)分組得到不同年齡的人的平均成績,並寫出結果。

答:avg(grade) group by name, age

4.     橫表豎起來 請寫出 SQl 語句實現題目要求的結果:寫一個 SQL完成左邊的表變成右邊的表。

表的結構

要求結果

ProductID  SALE_YEAR   SALES 001          2001             10 002          2001            15 003          2002             12 003          2003             10

productID   2001  2002     2003    001        10      002        15      003               12       10

² 交叉表的列數是確定的 

select name,

sum(case subject when '數學' then source else 0 end) as '數學',

sum(case subject when '英語' then source else 0 end) as '英語',

sum(case subject when '語文' then source else 0 end) as '語文'

from   test   group   by   name

² 交叉表的列數是不確定的 

declare @sql varchar(8000)

set @sql = 'select name,'

select @sql = @sql + 'sum(case subject when '''+subject+'''

then source else 0 end) as '''+subject+''','

from (select distinct subject from test) as a

select @sql = left(@sql,len(@sql)-1) + ' from test group by name'

exec(@sql)

5.     SQLServer刪除重複數據記錄

http://www.cnblogs.com/luohoufu/archive/2008/06/05/1214286.html

有兩個意義上的重複記錄,一是完全重複的記錄,也即所有字段均重複的記錄,二是部分關鍵字段重複的記錄,比如Name字段重複,而其他字段不一定重複。

² 寫出 SQl 語句(或 SQL 語句組),查詢所有 id_no 重複的記錄。

select  dept_ID from salary

group by dept_ID having count(dept_ID) > 1

² 對於第一種重複,比較容易解決,使用

select distinct * from tableName 就可以得到無重複記錄的結果集。 如果該表需要刪除重複的記錄(重複記錄保留1條),可以按以下方法刪除 select distinct * into #Tmp from tableName truncate table tableName select * into tableName from #Tmp drop table #Tmp 發生這種重複的原因是表設計不周產生的,增加唯一索引列即可解決

² 這類重複問題通常要求保留重複記錄中的第一條記錄,操作方法如下:

假設有重複的字段爲Name,Address,要求得到這兩個字段唯一的結果集 select identity(int,1,1) as autoID, * into #Tmp from tableName select min(autoID) as autoID into #Tmp2 from #Tmp group by Name,autoID select * from #Tmp where autoID in(select autoID from #tmp2) 最後一個select即得到了Name,Address不重複的結果集(但多了一個autoID字段,實際寫時可以寫在select子句中省去此列)

² 部分關鍵字段重複,且記錄中有ID. (***這個比較實用***)

第一種方法可一次刪除所有重複的..(只保留重複中ID最小的記錄)。 delete from table where id not in ( select min(id) from table group by name)第二種方法每次只刪除重複中ID最大的一條記錄。

delete from table where id in ( select max(id) from table group by name having count(*)>1)

² 使用SQL程序刪除

declare @max integer,@id integer declare cur_rows cursor local for select 主字段,count(*) from 表名 group by 主字段 having count(*) > 1 open cur_rows fetch cur_rows into @id,@max while @@fetch_status=0 begin select @max = @max -1 set rowcount @max delete from 表名 where 主字段 = @id fetch cur_rows into @id,@max end close cur_rows set rowcount 0

² 自己還得出的辦法:

select * from user1 where id not in (select top 1 id from user1 where name = user1.name) -- 兩個name相等比較重要,否則就不對了。但是group by更加好一些

刪就這樣寫

delete from user1 where id not in (select top 1 id from user1 where name=user1.name)

delete from user where id not in ( select max(id) from user where name=user.name)

delete from user where id not in (select max(id) from user group by name having count(*) > 1)

其他方法

A:保留id最大(或者最小)的行,刪除其它行

--方法1

delete [user] from [user] t

inner join(select name,max(id) as id from [user] group by name) a

on t.name = a.name and t.id <> a.id

--方法2

delete [user] from [user] t

where exists(select * from [user] where name = t.name and id > t.id)

B:刪除所有重複的name行,一行也不留

delete [user] from [user] t

inner join

(select id from [user] a where exists(select * from [user] where name = a.name group by name having count(*) > 1)) as b

on t.id = b.id

6.     一些高難度的SQL

http://www.teecool.com/post/2007072807.html

² 如果表的結構和數據

表1:usertable USERID USERNAME  1 user1  2 null  3 user3  4 null  5 user5  6 user6

表2: usergrade;  USERID USERNAME GRADE  1 user1 90  2 null 80  7 user7 80  8 user8 90

那麼,執行語句 select count(*) from usergrade where username not in (select username from usertable);

select count(*) from usergrade g where not exists (select null from usertable t where t.userid=g.userid and t.username=g.username);

結果爲:語句1( 0 ) 語句2 ( 3 ) A: 0 B:1 C:2 D:3 E:NULL  --- 不懂

² 在以下的表的顯示結果中,以下語句的執行結果是(知識點:in/exists+rownum)

SQL> select * from usertable;  USERID USERNAME  1 user1  2 user2  3 user3  4 user4  5 user5

SQL> select * from usergrade;  USERNAME GRADE  user9 90  user8 80  user7 80  user2 90  user1 100  user1 80

那麼,執行語句Select count(*) from usertable t1 where username in  (select username from usergrade t2);

Select count(*) from usertable t1 where exists  (select 'x' from usergrade t2 where t1.username=t2.username );

以上語句的執行結果是:( c) (c )  A: 0 B: 1 C: 2 D: 3

count(*)和count(GRADE)有區別:前者統計NULL行;後者忽略NULL行

² 關聯更新

有表一的查詢結果如下,該表爲學生成績表select id,grade from student_grade  ID GRADE    1 50  2 40  3 70  4 80  5 30  6 90

表二爲補考成績表 select id,grade from student_makeup  ID GRADE  1 60  2 80  5 60

執行語句:  update student_grade s set s.grade =  (select t.grade from student_makeup t where s.id=t.id);

-- 這裏,把1、2、5更新爲對應的結果,但是3、4、6也會被更新,但是由於沒有對應的值,所以都被更新爲了NULL

請問之後查詢: select GRADE from student_grade where id = 3;結果爲: (c)

A: 0 B: 70 C: null D: 以上都不對

7.     英文

http://www.teecool.com/post/2007072808.html

² Question 1: calculating the Number of Days in a Month

declare @now datetime

--select @now = getdate()

select @now = '20090211'

-- 方法是:下月日-本月日的日期差。所以先構造本月日,在構造下月日,減

select datediff(dd, dateadd(dd, -1* datepart(dd, @now) + 1, @now),

dateadd(MM, 1, dateadd(dd, -1* datepart(dd, @now) + 1, @now)) )

-- 方法:下月日的前一天就是本月的月末,這一天的‘dd’就是本月天數。

select datepart(dd,

dateadd(dd,-1,dateadd(mm,1,cast(cast(year(getdate()) as varchar)

+'-'+cast(month(getdate()) as varchar)+'-01' as datetime))));

² Question2:How can I print "10 to 20" for books that sell for between $10 and $20,"unknown" for books whose price is null, and "other" for all other prices?

select bookid,bookname,

price=case when price is null then 'unknown'

when  price between 10 and 20 then '10 to 20' else price end

from books

Question3:to find duplicate values! Find authors with the same last name? You can use the table authors in datatabase pubs. I want to get the result: au_lname   number_dups  Ringer        2 Answer 3 select au_lname,number_dups=count(1) from authors group by au_lname

--count(1)和count(*)結果一樣,都是根據au_lname分組進行的組內全部統計

²  Question4:Can you create a cross-tab report in my SQL Server! How can I get the report about sale quality for each store and each quarter and the total sale quality for each quarter at year 1993?

  You can use the table sales and stores in datatabase pubs.  Table Sales record all sale detail item for each store. Column store_id is the id of each store, ord_date is the order date of each sale item, and column qty is the sale quality. Table stores record all store information. I want to get the result look like as below: Output:

stor_name  Total Qtr1  Qtr2  Qtr3  Qtr4   Barnum's   50 0  50 0  0 Bookbeat   55 25  30 0  0 Doc-U-Mat:   85 0  85 0  0 Fricative    60 35  0 0   25 Total     250 60 165 0  25

Answer 4:用動態SQL實現,前面有。不過看起來很複雜

use pubs

declare @s varchar(8000)

set @s='select isnull(stores.stor_name,''Total'') '

select @s=@s + ',[Qtr' + cast(datepart(q,ord_date) as char(1))

+ ']=sum(case when datepart(q,ord_date)='''

+ cast(datepart(q,ord_date) as char(1)) + ''' then qty else 0 end)'

from Sales

group by datepart(q,ord_date)

set @s=@s + ' ,sum(qty) "Total" from Sales inner join stores on Sales.stor_id = stores.stor_id '

set @s=@s + ' where datepart(yyyy,ord_date) = ''1993'' '

set @s=@s + ' group by stores.stor_name WITH ROLLUP '

set @s=@s + ' order by stores.stor_name '

print @s

exec(@s)

-- print @s的結果是這樣的:

select isnull(stores.stor_name,'Total') , -- isnull把rollup造成的NULL值改成了Total,技巧

[Qtr1]=sum(case when datepart(q,ord_date)='1' then qty else 0 end),

[Qtr2]=sum(case when datepart(q,ord_date)='2' then qty else 0 end),

[Qtr3]=sum(case when datepart(q,ord_date)='3' then qty else 0 end),

[Qtr4]=sum(case when datepart(q,ord_date)='4' then qty else 0 end),

sum(qty) "Total"

from Sales inner join stores on Sales.stor_id = stores.stor_id 

where datepart(yyyy,ord_date) = '1993'

group by stores.stor_name WITH ROLLUP -- rollup是一個很重要的東西

order by stores.stor_name   -- order by,貌似不需要,或者用desc更好

²  Question5: The Fastest Way to Recompile All Stored Procedures I have a problem with a database running in SQL Server 6.5 (Service Pack 4). We moved the database (object transfer) from one machine to another last night, and an error (specific to a stored procedure) is cropping up. However, I can't tell which procedure is causing it. Permissions are granted in all of our stored procedures; is there a way from the isql utility to force all stored procedures to recompile?

Tips: sp_recompile can recomplie a store procedure each time

Answer 5:在執行存儲過程時,使用 with recompile 選項強制編譯新的計劃;使用sp_recompile系統存儲過程強制在下次運行時進行重新編譯

Question6: How can I add row numbers to my result set? In database pubs, have a table titles , now I want the result shown as below,each row have a row number, how can you do that? line-no  title_id  1          BU1032 2          BU1111 3          BU2075 4          BU7832 5          MC2222 6          MC3021 7          MC3026 Answer 6: -- row_number()的這種用法據我瞭解不行,他必須和over連用

select row_number() over(order by title_id) as line_no ,title_id from titles

²  Question 7: the difference of two SQL statements at performance of execution? Statement 1: if NOT EXISTS ( select * from publishers where state = ‘NY’)    SELECT ‘Sales force needs to penetrate New York market’ else   SELECT ‘We have publishers in New York’ Statement 2: if EXISTS ( select * from publishers where state = ‘NY’)    SELECT ‘We have publishers in New York’ else   SELECT ‘Sales force needs to penetrate New York market’ Answer 7: 不同點:初步感覺應該是第二個性能比較好,因爲不需要遍歷整個數據表,只要有一個存在的就可以結束。但是從執行計劃的時間和IO看,結果是一樣的。

²  Question9: How can I get a list of the stores that have bought both ‘bussiness’ and ‘mod_cook’ type books? In database pubs, use three table stores,sales and titles to implement this requestment. Now I want to get the result as below: stor_id stor_name 

... 7896 Fricative Bookshop ... ... ... Answer 9: use pubs

select distinct a.stor_id, a.stor_name from stores a,sales b,titles c

where a.stor_id=b.stor_id and b.title_id=c.title_id and c.type='business' and

exists(select 1 from sales k,titles g where stor_id=b.stor_id

and k.title_id=g.title_id and g.type='mod_cook');

-- 或者使用個連續的join也可以

select distinct a.stor_id, a.stor_name from stores a

join sales b on a.stor_id=b.stor_id

join titles c on b.title_id=c.title_id and c.type='business'

and exists (select * from  sales k,titles g where stor_id=b.stor_id

and k.title_id=g.title_id and g.type='mod_cook')

Question11: How can I list all book with prices greather than the average price of books of the same type? In database pubs, have a table named titles , its column named price mean the price of the book, and another named type mean the type of books. Now I want to get the result as below: type           title                                                   price  business     The Busy Executive’s Database Guide            19.9900 ... ... Answer 11: select distinct t1.price, t1.type from titles t1, titles t2

where t1.price <

( select avg(price) from titles t2 where t1.type = t2.type group by type )

-- 或者

select distinct t1.price, t1.type from titles t1

join titles

on t1.price <

( select avg(price) from titles t2 where t1.type = t2.type group by type )

8.     其他

http://www.teecool.com/post/2007071809.html

²  有訂單表SO_Table,單號字段RefNo VARCHAR(10),需要實現自動編號,格式爲YYYYMMXXXX,其中XXXX爲序號,如:2004050001,2004050002……2004059999等,採用Transact-SQL實現新訂單編號的思路。

思路:

1,IDENTITY(smallint, 100, 1)只有在select…into這樣的數據插入裏面可用;

2,6位長度的年月可以用:convert(char(6), getdate(), 112);

或者cast(datepart(YY, @date) as varchar(4)) +

right(cast(datepart(MM, @date)+100 as varchar(3)), 2)

3, 如果必須在SP裏面工作的話,可以獲得上次的最大序號,加1

²  有表T1,T2,現有一事務,在向表T1添加數據時,同時也必須向T2也添加數據,如何確何數據的完整性。

使用trigger可以做到;另外,添加過程要在一個transaction中進行;

²  如何求表中相鄰(按聚集索引相鄰)的兩條記錄的某字段的值之差

select s2.saleid, p=(s1.saleprice-s2.saleprice)

from

(select *, id=row_number() over(order by saleid) from sales)  s1,

(select *, id=row_number() over(order by saleid) from sales) s2

where s2.id-s1.id=1

-- 下面的辦法不行,因爲如果相鄰的ID不是連續的就不行了。另外,可以使用cursor

select a.source - b.source from test a, test b

where (a.id - b.id) = 1

order by a.id

²  如何刪除表中的重複數據。上面有答案。

²  人員情況表(employee)中字段包括,員工號(ID),姓名(name),年齡(age),文化程度(wh):包括四種情況(本科以上,大專,高中,初中以下),現在我要根據年齡字段查詢統計出:表中文化程度爲本科以上,大專,高中,初中以下,各有多少人,佔總人數多少。結果如下: 學歷       年齡      人數        百分比 本科以上   20        34           14 大專       20        33           13 高中       20        33           13 初中以下   20        100          40 本科以上   21        50           20 。。。。。。

Transact-SQL查詢語句如何寫?

-- Count(*) * 100 由group by限定;SELECT Count(*) FROM是總數。

SELECT wh AS 學歷,age as 年齡, Count(*) AS 人數,

Count(*) * 100 /(SELECT Count(*) FROM employee) AS 百分比

FROM employee GROUP BY wh,age

²  表一(AAA) 商品名稱a   商品總量b    A          100    B          120 表二(BBB) 商品名稱a   出庫數量b     A          10     A          20     B          10     B          20     B          30

用一條Transact-SQL語句算出商品A,B目前還剩多少?

select sum(b)

from (select * from a

union all select a, b*(-1) from b) x

group by a

²  找到連續編號中斷的那一個的最小值

select   min(t.id) as id   from   (select   id=id+1   from   tt) t        where   id   not   in   (select   id   from   tt)

9.     實際應用

A) 爲管理崗位業務培訓信息,建立3個表: S (S#,SN,SD,SA) S#,SN,SD,SA 分別代表學號、學員姓名、所屬單位、學員年齡 C (C#,CN ) C#,CN 分別代表課程編號、課程名稱 SC ( S#,C#,G ) S#,C#,G 分別代表學號、所選修的課程編號、學習成績

²  查詢選修課程名稱爲’稅收基礎’的學員學號和姓名

Select SN,SD FROM S  -- 實際上,使用3個join纔是合理的

Where [S#] IN(

Select [S#] FROM C,SC

Where C.[C#]=SC.[C#]

AND CN=N'稅收基礎')

²  查詢選修課程編號爲’C2’的學員姓名和所屬單位

Select S.SN,S.SD FROM S,SC

Where S.[S#]=SC.[S#]

AND SC.[C#]='C2'

²  查詢不選修課程編號爲’C5’的學員姓名和所屬單位

Select SN,SD FROM S

Where [S#] NOT IN(      -- not in是正確的。不能使用=,會遺漏

Select [S#] FROM SC

Where [C#]='C5')

²  4. 查詢選修全部課程的學員姓名和所屬單位 -- 1)RIGHT JOIN可產生NULL行;2)COUNT(*),COUNT(S#)的結果不同

-- 解釋:如果COUNT(*)<>COUNT(S#),

-- 說明C中有某個C#沒有在sc中出現,也就是說:這門課程沒有被S#同學選中。

Select SN,SD FROM S

Where [S#] IN(

Select [S#] FROM SC

RIGHT JOIN

C ON SC.[C#]=C.[C#] GROUP BY [S#]

HAVING COUNT(*)=COUNT([S#]))

²  5. 查詢選修了課程的學員人數

Select 學員人數=COUNT(DISTINCT [S#]) FROM SC

²  6. 查詢選修課程超過5門的學員學號和所屬單位

-- 關注having子句中的count()等聚合函數的使用

Select SN,SD FROM S

Where [S#] IN(

Select [S#] FROM SC

GROUP BY [S#]

HAVING COUNT(DISTINCT [C#])>5)

B)該題目中,很多都有歧義,所以只要掌握的基本的方法,不需要深究細節。

/*

S (SNO,SNAME) 學生關係。SNO 爲學號,SNAME 爲姓名

C (CNO,CNAME,CTEACHER) 課程關係。CNO 爲課程號,CNAME 爲課程名,CTEACHER 爲任課教師

SC(SNO,CNO,SCGRADE) 選課關係。SCGRADE 爲成績

*/

²  找出沒有選修過“李”老師講授課程的所有學生姓名

select distinct sname from s

where s.sno not in --因爲有這種情況:S.SNO不在SC中存在。

(select sno from sc,c where sc.CNO=c.cno and cteacher = '李')

²  列出有二門以上(含兩門)不及格課程的學生姓名及其平均成績

Select S.SNO,S.SNAME,AVG_SCGRADE=AVG(SC.SCGRADE)

FROM S,SC,(

Select SNO FROM SC Where SCGRADE<60

GROUP BY SNO HAVING COUNT(DISTINCT CNO)>=2

)A  -- 實際上,使用 IN 進行條件連接也行

-- where控制條件,having控制分組條件並聚合

Where S.SNO=A.SNO AND SC.SNO=A.SNO

GROUP BY S.SNO,S.SNAME

--下面是錯誤結果:它只是把沒有及格的科目進行了avg,並不是所有的科目的avg

select avg(sc.scgrade), s.sname

from s

join sc on sc.sno = s.sno and sc.scgrade < 60

group by s.sname having count(sc.scgrade)>=2

²  列出既學過“c1”號課程,又學過“c2”號課程的所有學生姓名

select s.sname

from s, (select * from sc

where sc.sno in (select sc.sno from sc where sc.cno = 'c1')

and sc.cno = 'c2') SS -- 把sc.sno in換爲exists也可以。兩種方案

where s.sno = ss.sno

²  列出“c1”號課成績比“s2”號同學該門課成績高的所有學生的學號

select sc.sno, sc.scgrade from sc

where sc.cno='c1' and

sc.scgrade>(select sc.scgrade from sc where sc.cno='c1' and sc.sno='s2')

²  列出“c1”號課成績比“c2”號課成績高的所有學生的學號及其“c1”號課和“c2”號課的成績

select sc1.sno, sc1.cno, sc1.scgrade

from sc sc1,

(select sc1.sno, sc1.cno, sc1.scgrade

from sc sc1, sc sc2

where sc1.cno='c1' and sc2.cno='c2' and sc1.scgrade>sc2.scgrade

and sc1.sno=sc2.sno) sc2

where sc2.sno=sc1.sno and (sc1.cno='c1' or sc1.cno='c2')

1.     老外的一套題

我需要一個模式和一些數據來運行所要考覈的查詢,列表A創建了所需的這些數據:

IF OBJECT_ID('Sales')>0    DROP TABLE Sales GO IF OBJECT_ID('Customers')>0  DROP TABLE Customers GO IF OBJECT_ID('Products')>0  DROP TABLE Products GO CREATE TABLE Customers(CustomerID INT IDENTITY PRIMARY KEY , FirstName VARCHAR(50), LastName VARCHAR(50), City VARCHAR(50), State CHAR(2), Zip VARCHAR(10) ) GO CREATE TABLE Products( ProductID TINYINT IDENTITY PRIMARY KEY , ProductName VARCHAR(20), RecommendedPrice MONEY, Category VARCHAR(10)) GO CREATE TABLE Sales(SaleID INT IDENTITY PRIMARY KEY , ProductID TINYINT NOT NULL REFERENCES Products(ProductID), CustomerID INT NOT NULL REFERENCES Customers(CustomerID), SalePrice MONEY NOT NULL,SaleDate SMALLDATETIME NOT NULL) GO INSERT INTO Products(ProductName,RecommendedPrice,Category)VALUES('DVD',105,'LivingRoom') INSERT INTO Products(ProductName,RecommendedPrice,Category)VALUES('Microwave',98,'Kitchen') INSERT INTO Products(ProductName,RecommendedPrice,Category)VALUES('Monitor',200,'Office') INSERT INTO Products(ProductName,RecommendedPrice,Category)VALUES('Speakers',85,'Office') INSERT INTO Products(ProductName,RecommendedPrice,Category)VALUES('Refrigerator',900,'Kitchen') INSERT INTO Products(ProductName,RecommendedPrice,Category)VALUES('VCR',165,'LivingRoom') INSERT INTO Products(ProductName,RecommendedPrice,Category)VALUES('CoffeePot',35,'Kitchen') GO INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('John','Miller','Asbury','NY','23433') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Fred','Hammill','Basham','AK','85675') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Stan','Mellish','Callahan','WY','38556') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Adrian','Caparzo','Denver','CO','12377') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Mike','Horvath','Easton','IN','47130') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Irwin','Wade','Frankfurt','KY','45902') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('George','Marshall','Gallipoli','ND','34908') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Frank','Costello','Honolulu','HI','23905') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Billy','Costigan','Immice','SC','75389') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Shelly','Sipes','Lights','AZ','35263') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Chirsty','Melton','Spade','CA','97505') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Amanda','Owens','Flask','CN','50386') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Brittany','Smits','Bourbon','KY','24207') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Kristy','Bryant','Tarp','FL','58960') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Kelly','Street','TableTop','ID','57732') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Tricia','Hill','Camera','ME','46738') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Holly','Raines','Compact','MS','35735') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Natalie','Woods','Woods','IN','87219') INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Wendy','Hilton','Action','KY','47093') GO INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(1,1,130,'2/6/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(2,2,97,'1/7/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(3,3,200,'8/8/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(4,4,80,'4/9/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(5,5,899,'10/10/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(6,6,150,'10/11/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(3,7,209,'12/12/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(4,8,90,'5/13/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(6,9,130,'6/14/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(2,14,85,'6/19/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(3,15,240,'9/20/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(1,16,99,'7/21/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(1,17,87,'3/22/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(2,18,99,'1/23/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(6,19,150,'3/24/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(5,5,900,'3/10/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(4,6,86,'8/11/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(2,7,88,'8/12/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(3,8,198,'12/13/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(1,9,150,'5/14/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(6,14,99,'7/19/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(6,15,104,'9/20/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(3,16,270,'2/21/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(4,17,90,'7/22/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(1,1,130,'3/6/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(2,2,102,'4/7/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(1,3,114,'11/8/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(5,4,1000,'5/9/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(5,5,1100,'10/10/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(3,6,285,'6/11/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(2,7,87,'10/12/2005') INSERT INTO Sales(ProductID,CustomerID,SalePrice,SaleDate) VALUES(3,8,300,'7/13/2005') GO

²  1:返回在2005年10月售出的所有產品的名稱、價格和客戶姓名,答案:

select c.FirstName,c.LastName, p.productname, s.SalePrice, s.saledate from products p,customers c, sales s where s.productid = p.productid and c.customerid = s.customerid and datepart(YY, s.saledate) = 2005 and datepart(MM, s.saledate) = 10 --或者下面的也行。根據執行計劃,二者是完全一樣的。 SELECT c.FirstName,c.LastName,p.ProductName,s.SalePrice FROM Sales s INNER JOIN Customers c ON s.CustomerID=c.CustomerID INNER JOIN Products p ON s.ProductID=p.ProductID WHERE s.SaleDate>='10/1/2005'AND s.SaleDate<'11/1/2005'

²  2:返回沒有購買產品並且位於客戶表格上的人的姓名及其客戶ID,答案:

select c.FirstName,c.LastName, c.customerid from customers c where c.customerid not in ( select distinct customerid from sales) --或者下面的。下面的是提供的答案;但是上面的效率更高,二者比42:58 SELECT c.CustomerID,c.FirstName,c.LastName FROM Sales s RIGHT OUTER JOIN Customers c ON s.CustomerID=c.CustomerID WHERE s.CustomerID IS NULL

3:返回客戶姓名、銷售價格、建議售價、建議售價和實際價格的差額,該差額必需是正數,答案見列表D:

SELECT c.FirstName,c.LastName,s.SalePrice,p.RecommendedPrice, ABS(s.SalePrice-p.RecommendedPrice) AS diff FROM Sales s INNER JOIN Customers c ON s.CustomerID=c.CustomerID INNER JOIN Products p ON s.ProductID=p.ProductID

²  4:根據產品類別計算平均價格,答案見列表E:

SELECT avg(s.SalePrice) as avg, p.category FROM Sales s  inner join products p on s.productid = p.productid group by p.category

²  5:將以下的客戶和銷售信息加入到數據庫中:

FirstName:Chris, LastName:Kringle, City:Henryville, State:IN, Zip:47126 ProductID:3, SalePrice:205, SaleDate:12/31/2005

 答案見列表F(關注SCOPE_IDENTITY(),這裏可以和@@identity互換):

INSERT INTO Customers(FirstName,LastName,City,State,Zip) VALUES('Chris','Kringle','Henryville','IN','47126') INSERT INTO Sales(CustomerID,ProductID,SalePrice,SaleDate) VALUES(SCOPE_IDENTITY(),3,205,'12/31/2005')

²  6:從數據庫中刪除來自緬因洲(‘ME’)的客戶,答案見列表G:(不過,delete s from...這樣的用法很怪,貌似這樣就可以把s這個名字引入進來了)

delete s from Sales s where s.CustomerID in (select CustomerID from Customers where State = 'ME') -- 或者下面的:(因爲不支持delete from A, B這樣的語法,所以用join) DELETE s FROM Sales s JOIN Customers c ON s.CustomerID=c.CustomerID WHERE c.State='ME' -- 然後 DELETE c FROM Customers c WHERE c.State='ME'

²  7:返回客戶購買了兩個或多個產品的平均售價和產品類別,答案:

SELECT AVG(s.SalePrice) avg, p.Category FROM Sales s, Products p where s.ProductID=p.ProductID and s.CustomerID in ( SELECT s.CustomerID FROM Sales s GROUP BY s.CustomerID HAVING COUNT(CustomerID)>=2) GROUP BY p.Category -- 或者 SELECT AVG(s.SalePrice) avg, p.Category FROM Sales s INNER JOIN ( SELECT s.CustomerID FROM Sales s GROUP BY s.CustomerID HAVING COUNT(CustomerID)>=2)x ON s.CustomerID=x.CustomerID INNER JOIN Products p ON s.ProductID=p.ProductID GROUP BY p.Category

²  8:將銷售在2005年6月10日到6月20日之間的產品的銷售價格升級爲建議售價:(這個還是不太明白,尤其是s.ProductID=s.ProductID,怪)

UPDATE s SET SalePrice=p.RecommendedPrice FROM Sales s INNER JOIN Products p ON s.ProductID=s.ProductID WHERE SaleDate>='6/10/2005' AND SaleDate<'6/21/2005'

²  9:根據產品種類計算建議售價超過實際售價10元及以上的銷售數量,答案見列表J:

SELECT count(s.SalePrice) count, p.Category FROM Sales s INNER JOIN Products p ON s.ProductID=p.ProductID where p.RecommendedPrice - s.SalePrice >= 10 GROUP BY p.Category -- 題目有歧義,所以,也可以這樣做: SELECT p.Category,COUNT(*)AS NumberOfSales FROM Sales s INNER JOIN Products p ON s.ProductID=p.ProductID GROUP BY p.Category HAVING AVG(p.RecommendedPrice)>=AVG(s.SalePrice)+10

²  10:不使用疊代構建,返回所由銷售產品的銷售日期,以及該日期之前的銷售額統計,以及該日期之前的銷售額統計,並按照該日期升序排列,答案:

SELECT s.SaleDate, s.SalePrice, ( SELECT SUM(SalePrice) FROM Sales s2 WHERE s2.SaleDate<=s.SaleDate )AS RunningTotal FROM Sales s ORDER BY s.SaleDate ASC

迄今爲止,只有2個人可以正確地回答出所有的問題。

平均大約爲50-60%,如果表現高於這個平均,那麼優秀的TSQL程序員,如果獲得了90%以上的得分,那麼他或她就是一位非常優異的程序員。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章