1. 程式人生 > >sql常見面試題(2)

sql常見面試題(2)

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

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

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

1.     三個正規化

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

第一正規化(1NF):資料庫表中的欄位都是單一屬性的,不可再分。這個單一屬性由基本型別構成,包括整型、實數、字元型、邏輯型、日期型等。

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

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+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 可以省略

SELECTtop 10 *FROMAWHEREID not in (SELECTtop 30 idFROMA)

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

注意Full outer joinleft join, right joininner 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刪除重複資料記錄

有兩個意義上的重複記錄,一是完全重複的記錄,也即所有欄位均重複的記錄,二是部分關鍵欄位重複的記錄,比如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

² 如果表的結構和資料

表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  --- 不懂

第一個結果為什麼是零?因為:括號裡面得到了usertable的所有的名字,其中有兩個是NULL, in這個關鍵字的含義是or

類比,所以通過上面的例子我們知道,其實not in 產生了不確定的結果,因此返回給我們的是沒有任何結果。

我自己做實驗也嘗試了這個問題把表中的2,4去掉就會得到的是2

<code><span class="pln">A</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">select</span><span class="pln"> </span><span class="str">'true'</span><span class="pln"> </span><span class="kwd">where</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">)</span><span class="pln">
B</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">select</span><span class="pln"> </span><span class="str">'true'</span><span class="pln"> </span><span class="kwd">where</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">)</span></code>

<code><span class="kwd">select</span><span class="pln"> </span><span class="str">'true'</span><span class="pln"> </span><span class="kwd">where</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span></code>

加上一個not之後 變成and

<code><span class="kwd">select</span><span class="pln"> </span><span class="str">'true'</span><span class="pln"> </span><span class="kwd">where</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun"><></span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun"><></span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun"><></span><span class="pln"> </span><span class="kwd">null</span></code>

<code><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
which </span><span class="kwd">is</span><span class="pun">:</span><span class="pln">
    FALSE </span><span class="kwd">or</span><span class="pln"> FALSE </span><span class="kwd">or</span><span class="pln"> TRUE </span><span class="kwd">or</span><span class="pln"> UNKNOWN
which evaluates </span><span class="kwd">to</span><span class="pln"> 
    TRUE</span></code>

<code><span class="pln">    </span><span class="lit">3</span><span class="pln"> </span><span class="pun"><></span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun"><></span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun"><></span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
which evaluates </span><span class="kwd">to</span><span class="pun">:</span><span class="pln">
    TRUE </span><span class="kwd">and</span><span class="pln"> TRUE </span><span class="kwd">and</span><span class="pln"> UNKNOWN
which evaluates </span><span class="kwd">to</span><span class="pun">:</span><span class="pln">
    UNKNOWN</span></code>

The UNKNOWN is not the same as FALSE you can easily test it by calling:

<code><span class="kwd">select</span><span class="pln"> </span><span class="str">'true'</span><span class="pln"> </span><span class="kwd">where</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun"><></span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
</span><span class="kwd">select</span><span class="pln"> </span><span class="str">'true'</span><span class="pln"> </span><span class="kwd">where</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="pun">(</span><span class="lit">3</span><span class="pln"> </span><span class="pun"><></span><span class="pln"> </span><span class="kwd">null</span><span class="pun">)</span></code>

² 在以下的表的顯示結果中,以下語句的執行結果是(知識點: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.     英文

² 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') , -- isnullrollup造成的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