關系型數據通常以規范化形式保存,就是說你應該盡可能少地重復數據;通常情況下,表與表之間僅通過各種鍵值實現關聯。進一步地講,規范化的含義就是:你不能在數據庫中保存計算後的值,而你只能在需要的時候臨時計算數據庫中保存的值。
對數據進行某些分析通常是很重要的。比方說,你或許想知道哪些產品的定單最多或者哪些定單的利潤最大。這些問題都要求你針對自己的SQL語句創建執行過濾規則的公式。其中最重要的語句之一就是GROUP BY子句。
Northwind數據庫中的定單
Northwind數據庫是包含在SQL Server安裝軟件中的兩個示范數據庫。這個數據庫雖然談不上完美無缺但也足夠滿足我們討論GROUP BY語句的目的了。原因之一是它工作原理清晰,運行良好,包含了一整套標准的數據表,比如Customers(客戶)、Orders(定單)、Order Details(定單細節)和處理定單的Products(產品)。
表的結構模式
如果你想查看各個定單的OrderID和ProductID ,以下的SQL命令可以滿足要求:
SELECT o.OrderID, od.ProductID
FROM Orders o, [Order Details] od
WHERE o.OrderID = od.OrderID
這樣你就通過OrderID字段把Orders和Order Details連接了起來。給出的結果列表即顯示各定貨條目的OrderID和ProductID。
你可以從這個列表中找到條目數量最大的定單。可是,再想想,要能簡單地要求數據庫計算出需要的條目數目不更方便嗎?如果你不關心單個條目而只想知道訂購條目數量最大的定單,那麼你可以采用以下的SQL語句:
SELECT o.OrderID, Count(od.ProductID) as NumItems
FROM Orders o, [Order Details] od
WHERE o.OrderID = od.OrderID
這樣就可以總計出產品的數量並用一個名為NumItems的新字段來顯示總數。可是,如果你執行該語句則可能得到以下錯誤:
Server: Msg 8118, Level 16, State 1, Line 1
選擇語句中的'o.OrderID'列是無效的,因為它沒有包含在匯集函數之內而且沒有相應的GROUP BY 子句。
在這種情況下,你實際上在總計ProductID,但OrderID卻沒有被計算總和或者有其他操作施加於其上。
其實這個示例中計算的並不是訂購產品條目的總數而是特定訂購產品條目的數目。換句話說,你可以看到某一特定定單包括三種產品,但卻並不能表示客戶各訂購了5種。你得到的正是按照定單統計的產品總量。你應該用GROUP BY字句來查看訂購產品的總數。
使用GROUP BY
使用GROUP BY就好比提出下面的問題:“我如何查看數據?“如果答案是“按照”某種要素來看那麼你就可能用到GROUP BY。就我們的例子來說,你希望按照定單查看產品的數量,所以你就可以用OrderID字段進行分組。此外,采用ORDER BY 子句可以更容易地找出訂購條目最多的定單。新的查詢語句如下所示:
SELECT o.OrderID, Count(od.ProductID) as NumItems
FROM Orders o, [Order Details] od
WHERE o.OrderID = od.OrderID
GROUP BY o.OrderID
ORDER BY NumItems DESC
現在你就得到問題的答案了。如圖B所示的部分結果,定單號11077訂購了25種產品,而排第2的最大定單則只訂購了6類產品。
理解規則
GROUP BY具有相當高的靈活性,當然你還得遵守相應的語法規則。比如說,你可以在ORDER BY 子句中包含多個表列。如果你想查看每一客戶訂購產品各個類型的數量,那麼你必須通過定單創建查詢把客戶連接到產品。圖A顯示的4表連接顯然就要用到了。之後你要根據客戶和產品進行分組同時對Order Details表內的Quantity列計算總和。查詢語句如下:
SELECT c.CompanyName, p.ProductName, Sum(od.Quantity) as TotalBought
FROM Customers c, Products p, Orders o, [Order Details] od
WHERE
c.CustomerID=o.CustomerID AND
o.OrderID=od.OrderID AND
od.ProductID=p.ProductID
GROUP BY c.CompanyName, p.ProductName
ORDER BY CompanyName, TotalBought DESC
查詢結果顯示出數據庫內每一客戶購買各類產品的總數。
同時,你還可以在查詢中置入多個匯集列。例如,假設你想查看的定單列表要顯示單一項目的最大購買量以及該定單的項目總數,那麼以下的語句就可以用Max函數來顯示單一項目的最大訂購量。這種方法還能對所購項目總量求和。
SELECT o.OrderID,
Max(od.Quantity) as TopItem,
Sum(od.Quantity) as TotalBought
FROM
Orders o,
[Order Details] od,
Products p
WHERE
o.OrderID = od.OrderID AND
od.ProductID=p.ProductID
GROUP BY o.OrderID
ORDER BY TotalBought DESC
現在你得到了定單、訂購量排前列的數量以及定單總項。
GROUP BY是過濾數據的一種強有力的工具。為了在你的SQL表內計算數據,它的功能不可小看。