|
我知道如何使用衍生表,但我仍然可以看到任何使用它们的真正优势。; m5 U! n5 c3 D# B) @, [
例如,下面的文章http://techahead.wordpress.com/2007/10/01/sql-derived-
# ?4 t3 f$ Z9 E9 p6 V8 R ]tables/在中间,作者试图显示使用衍生表的查询优于没有例子的查询。我们需要生成一份报告,以显示1996年每个客户下的订单总数。我们希望结果集包括所有客户,包括当年没有下订单的客户和从未下订单的客户(他使用)Northwind数据库)。, u+ b& y# }! C/ a' e$ x% \0 b% C
然而,当我比较这两个查询时,我看不到使用衍生表查询的任何优点(如果没有其他问题,使用衍生表似乎不会简化我们的代码,至少在这个例子中):
% ^% ]) ~' u q! a! J) F/ Q常规查询:
0 I7 Y7 P- y( B& ASELECT C.CustomerID,C.CompanyName,COUNT(O.OrderID) AS TotalOrdersFROM Customers C LEFT OUTER JOIN Orders O ON C.CustomerID = O.CustomerID AND YEAR(O.OrderDate) = 1996GROUP BY C.CustomerID,C.CompanyName使用派生表查询:& F6 @7 [$ e: a3 [
SELECT C.CustomerID,C.CompanyName,COUNT(dOrders.OrderID) AS TotalOrdersFROM Customers C LEFT OUTER JOIN (SELECT * FROM Orders WHERE YEAR(Orders.OrderDate) = 1996) AS dOrders ON C.CustomerID = dOrders.CustomerIDGROUP BY C.CustomerID,C.CompanyName也许这不是一个好例子,所以你能给我看一个例子,衍生表的好处更明显吗?+ X# ?8 q9 F, f/ s4 I2 w7 d
谢谢
+ e1 z' t( T5 x# C. d8 q回复GBN:
1 {2 x7 [: w8 _$ U/ m3 D在这种情况下,如果客户与产品无关,则无法同时捕获产品和订单汇总。
A! E% H" C6 x/ L: ^你能详细说明你的意思吗?以下查询不会产生与您查询相同的结果集:+ p0 _: S, G5 a8 O; G' ]. U
SELECT C.CustomerID,C.CompanyName, COUNT(O.OrderID) AS TotalOrders, COUNT(DISTINCT P.ProductID) AS DifferentProducts FROM Customers C LEFT OUTER JOIN Orders O ON C.CustomerID = O.CustomerID AND YEAR(O.OrderDate) = 1996 LEFT OUTER JOIN Products P ON O.somethingID = P.somethingID GROUP BY C.CustomerID,C.CompanyName回复到CADE ROUX:+ V) t+ G: s# k
此外,如果使用大量共享中间计算的表达式衍生列,则只有一组嵌套式衍生表或堆叠式衍生列CTE唯一的办法就是这样做:
+ ~. {4 O V: ?# y3 WSELECT x,y,z1,z2FROM ( SELECT * x y AS z1 x - y AS z2 FROM ( SELECT x * 2 AS y FROM A ) AS A) AS A以下查询不会产生与上述查询相同的结果:" c2 E* T5 s, M3 L
SELECT x,x * 2 AS y,x x*2 AS z1,x - x*2 AS z2FROM A / F! @" T3 H, g8 c7 {
解决方案: $ i% ^- T6 S8 C! U" n6 G
在你的例子中,衍生表并不是严格必要的。在许多情况下,你可能需要加入一个聚合物或类似的聚合物,而衍生物实际上是处理这个问题的唯一方法:9 E3 u3 K4 u9 k( Q4 L6 b/ D
SELECT *FROM ALEFT JOIN SELECT x,SUM(y) FROM B GROUP BY x) AS B ON B.x = A.x此外,如果使用大量共享中间计算的表达式衍生列,则只有一组嵌套式衍生表或堆叠式衍生列CTE唯一的办法就是这样做:
' k3 [5 J4 ~& A+ P! ~SELECT x,y,z1,z2FROM SELECT * x y AS z1 x - y AS z2 FROM SELECT x * 2 AS y FROM A ) AS A) AS A就可维护性而言,使用堆叠CTE或者衍生表(它们基本上是等效的)可以使代码更可读和可维护,并便于剪切和粘贴的重用和重化器通常很容易变平。$ i1 W# P' p9 A# c
我通常使用堆叠CTE而不是嵌套来提高可读性(两个例子相同):
* \ z2 t5 y4 ?0 a7 v+ c. `WITH B AS SELECT x,SUM(y) FROM B GROUP BY x)SELECT *FROM ALEFT JOIN B ON B.x = A.xWITH A1 AS SELECT x * 2 AS y FROM A),A2 AS SELECT * x y AS z1 x - y AS z2 FROM A1)SELECT x,y,z1,z2FROM A2关于你的问题:
" l3 C0 g& C$ C0 h1 ]SELECT x,x * 2 AS y,x x*2 AS z1,x - x*2 AS z2 FROM A这使x * 2代码重复3次。如果需要更改此业务规则,则必须在方更改-$ R& t Z& c0 F+ g; Y* r# H
注入缺陷的方法。当你只需要在一个地方定义和一致的中间计算时,情况就会变得更加复杂。
. h1 o" J g& i7 S( Q若能内联SQL8 o, M9 _3 K* q. E6 o( C* f2 I" H
Server标量用户定义函数(或者可以接受执行),这不是什么大问题,你可以简单地构建它UDF堆叠结果,优化器可以消除冗余调用。不幸的是,SQL
* A4 n7 e# c; u0 ^) F, c5 N3 S" ~! sServer的标量UDF大量行不能很好地处理。 |
|