您现在的位置>>.Net中文社区>>数据库

sql 子查询优化

浏览量: 作者:佚名 来源:互联网

关于SQLServer2005的学习笔记——子查询

SQL Server 的子查询给人的感觉一向不是很好用, IN 子查询无法实现多列的子查询,很多情况下又需要进行自我的子查询操作,比如取员工的最新订单之类的问题。 以下 SQL 和案例来之于 一书,不过适当的做了些编排和自己的理解。 让我们先来看看 Oracle 是怎么处理子查询的

  1. CREATE TABLE Orders  
  2.  
  3.  ( OrderID VARCHAR2(6),  
  4.  
  5.  CustomerID VARCHAR2(6),   
  6.  
  7. EmployeeID INT, OrderDate DATE );   
  8.  
  9. TRUNCATE TABLE Orders;   
  10.  
  11. INSERT INTO Orders VALUES('110001','WBQ',1,TO_DATE('2000-01-11','YYYY-MM-DD'));   
  12.  
  13. INSERT INTO Orders VALUES('110002','WBQ',1,TO_DATE('2000-01-21','YYYY-MM-DD'));   
  14.  
  15. INSERT INTO Orders VALUES('110003','WBQ',2,TO_DATE('2000-01-11','YYYY-MM-DD'));  
  16.  
  17.  INSERT INTO Orders VALUES('110004','WBQ',3,TO_DATE('2000-02-01','YYYY-MM-DD'));   
  18.  
  19. INSERT INTO Orders VALUES('110005','CZH',1,TO_DATE('2000-02-01','YYYY-MM-DD'));   
  20.  
  21. INSERT INTO Orders VALUES('110006','CZH',2,TO_DATE('2000-03-01','YYYY-MM-DD'));   
  22.  
  23. INSERT INTO Orders VALUES('110007','CZH',2,TO_DATE('2000-03-01','YYYY-MM-DD'));   
  24.  
  25. INSERT INTO Orders VALUES('110008','KIDD',3,TO_DATE('2000-02-01','YYYY-MM-DD'));   
  26.  
  27. INSERT INTO Orders VALUES('110009','KIDD',1,TO_DATE('2000-04-01','YYYY-MM-DD'));   
  28.  
  29. INSERT INTO Orders VALUES('110010','KIDD',2,TO_DATE('2000-03-01','YYYY-MM-DD'));   
  30.  
  31. INSERT INTO Orders VALUES('110011','KIDD',3,TO_DATE('2000-02-01','YYYY-MM-DD'));   
  32.  
  33. INSERT INTO Orders VALUES('110012','CZH',3,TO_DATE('2000-01-10','YYYY-MM-DD'));  
  34.  
  35.  COMMIT;   
  36.  
  37. SELECT EmployeeID,OrderDate,OrderID,CustomerID FROM Orders ORDER BY EmployeeID,OrderDate,OrderID   
  38.  
  39. -- 层递直至实现唯一为止   
  40.  
  41. SELECT EmployeeID,OrderDate,OrderID,CustomerID FROM Orders   
  42.  
  43. WHERE (EmployeeID,OrderDate,OrderID) IN (SELECT EmployeeID,OrderDate,MAX(OrderID) FROM Orders            WHERE (EmployeeID,OrderDate) IN (SELECT EmployeeID,Max(OrderDate) FROM Orders GROUP BY EmployeeID) GROUP BY EmployeeID,OrderDate) ORDER BY EmployeeID,OrderDate,OrderID,CustomerID -- 多值,通常情况下该语句即可,不过在本例中 EmployeeID,OrderDate 并不唯一,导致结果非所需的   
  44.  
  45. SELECT EmployeeID,OrderDate,OrderID,CustomerID   
  46.  
  47. FROM Orders   
  48.  
  49. WHERE (EmployeeID,OrderDate) IN (SELECT EmployeeID,Max(OrderDate) FROM Orders GROUP BY EmployeeID)   
  50.  
  51. ORDER BY EmployeeID,OrderDate,OrderID,CustomerID   
  52.  
  53. --Error ,这是个错误的表达式  
  54.  
  55.  SELECT EmployeeID,OrderDate,OrderID,CustomerID FROM Orders   
  56.  
  57. WHERE (EmployeeID,OrderDate,OrderID) IN (SELECT EmployeeID,MAX(OrderDate),MAX(OrderID)   
  58.  
  59. FROM Orders GROUP BY EmployeeID)   
  60.  
  61. -- 使用分析函数,也可以实现相应的子查询   
  62.  
  63. SELECT EmployeeID,OrderDate,OrderID,CustomerID   
  64.  
  65. FROM ( SELECT EmployeeID,OrderDate,OrderID,CustomerID, RANK() OVER (PARTITION BY EmployeeID ORDER BY OrderDate DESC,OrderID DESC) Rank FROM Orders ) a WHERE a.Rank=1   
  66.  
  67. 让我们继续看看 SQL Server 是如何处理的  
  68.  
  69.  CREATE TABLE Orders  
  70.  
  71.  ( OrderID VARCHAR(6),  
  72.  
  73.  CustomerID VARCHAR(6),  
  74.  
  75.  EmployeeID INT,   
  76.  
  77. OrderDate DATETIME );  
  78.  
  79.  INSERT INTO Orders VALUES('110001','WBQ',1,'2000-01-11');   
  80.  
  81. INSERT INTO Orders VALUES('110002','WBQ',1,'2000-01-21');   
  82.  
  83. INSERT INTO Orders VALUES('110003','WBQ',2,'2000-01-11');   
  84.  
  85. INSERT INTO Orders VALUES('110004','WBQ',3,'2000-02-01');   
  86.  
  87. INSERT INTO Orders VALUES('110005','CZH',1,'2000-02-01');  
  88.  
  89.  INSERT INTO Orders VALUES('110006','CZH',2,'2000-03-01');  
  90.  
  91.  INSERT INTO Orders VALUES('110007','CZH',2,'2000-03-01');   
  92.  
  93. INSERT INTO Orders VALUES('110008','KIDD',3,'2000-02-01');   
  94.  
  95. INSERT INTO Orders VALUES('110009','KIDD',1,'2000-04-01');   
  96.  
  97. INSERT INTO Orders VALUES('110010','KIDD',2,'2000-03-01');   
  98.  
  99. INSERT INTO Orders VALUES('110011','KIDD',3,'2000-02-01');  
  100.  
  101.  INSERT INTO Orders VALUES('110012','CZH',3,'2000-01-10');   
  102.  
  103. COMMIT;  
  104.  
  105.  -- 多值,通常情况下该语句即可,不过在本例中 EmployeeID,OrderDate 并不唯一,导致结果非所需的   
  106.  
  107. SELECT EmployeeID,OrderDate,OrderID,CustomerID FROM Orders O1   
  108.  
  109. WHERE rderDate= (SELECT MAX(OrderDate) FROM Orders O2 WHERE O1.EmployeeID=O2.EmployeeID) ORDER BY EmployeeID,OrderDate,OrderID,CustomerID 等效于 Oracle 的以下语句  
  110.  
  111.  SELECT EmployeeID,OrderDate,OrderID,CustomerID FROM Orders   
  112.  
  113. WHERE (EmployeeID,OrderDate) IN (SELECT EmployeeID,Max(OrderDate)  
  114.  
  115.  FROM Orders GROUP BY EmployeeID) ORDER BY EmployeeID,OrderDate,OrderID,CustomerID   
  116.  
  117. 正确的 SQLServer 子查询写法,用两个 MAX 求得唯一值   
  118.  
  119. SELECT EmployeeID,OrderDate,OrderID,CustomerID FROM Orders O1 WHERE rderDate= (SELECT MAX(OrderDate) FROM Orders O2 WHERE O1.EmployeeID=O2.EmployeeID) AND rderID= (SELECT Max(OrderID) FROM Orders O2 WHERE O1.EmployeeID=O2.EmployeeID AND O1.OrderDate=O2.OrderDate) ORDER BY EmployeeID,OrderDate,OrderID,CustomerID   
  120.  
  121. -- 本例使用一种变通的方法,把几个应有的附加条件加进来然后返回,比较难以理解  
  122.  
  123.  SELECT CAST(SUBSTRING(BinStr,1,8) AS DATETIME) AS OrderDate, CAST(SUBSTRING(BinStr,9,6) AS VARCHARAS OrderID, CAST(SUBSTRING(BinStr,15,6) AS VARCHARAS CustomerID FROM (SELECT EmployeeID, MAX(CAST(OrderDate AS BINARY(8)) +CAST(OrderID AS BINARY(6)) +CAST(CustomerID AS BINARY(6))) AS BinStr FROM Orders GROUP BY EmployeeID) D;  
  124.  
  125.  -- 本例中在子查询中使用 TOP+Order 排序的方式获取相应的第一行值 SELECT EmployeeID,OrderDate,OrderID,CustomerID FROM Orders O1 WHERE rderID= (SELECT TOP(1) OrderID FROM Orders O2 WHERE O1.EmployeeID=O2.EmployeeID ORDER BY OrderDate DESC,OrderID DESC,CustomerID ) ORDER BY EmployeeID,OrderDate,OrderID,CustomerID  
  126.  
  127.  -- 本例使用了 IN 子查询,可以自定义返回的 TOP N 条数   
  128.  
  129. SELECT EmployeeID,OrderDate,OrderID,CustomerID FROM Orders O1 WHERE OrderID IN (SELECT TOP(1) OrderID FROM Orders O2 WHERE O1.EmployeeID=O2.EmployeeID ORDER BY OrderDate DESC,OrderID DESC,CustomerID ) ORDER BY EmployeeID,OrderDate,OrderID,CustomerID 
本站部份资源来于互联网,只供学习之用,不得用于商业,如有侵犯版权请联系告知,本站将第一时间删除!
站长QQ:373638128 邮箱:navy1015@126.com
copyright © 2008 .Net中文社区 ASPXCS.NET™.All Rights Reserved 滇ICP备08102132号