程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> SqlServer數據庫 >> 關於SqlServer >> sql 子查詢優化

sql 子查詢優化

編輯:關於SqlServer

關於SQLServer2005的學習筆記——子查詢

 SQL Server 的子查詢給人的感覺一向不是很好用, IN 子查詢無法實現多列的子查詢,很多情況下又需要進行自我的子查詢操作,比如取員工的最新訂單之類的問題。 以下 SQL 和案例來之於 一書,不過適當的做了些編排和自己的理解。 讓我們先來看看 Oracle 是怎麼處理子查詢的

CREATE TABLE Orders

 ( OrderID VARCHAR2(6),

 CustomerID VARCHAR2(6),

EmployeeID INT, OrderDate DATE );

TRUNCATE TABLE Orders;

INSERT INTO Orders VALUES('110001','WBQ',1,TO_DATE('2000-01-11','YYYY-MM-DD'));

INSERT INTO Orders VALUES('110002','WBQ',1,TO_DATE('2000-01-21','YYYY-MM-DD'));

INSERT INTO Orders VALUES('110003','WBQ',2,TO_DATE('2000-01-11','YYYY-MM-DD'));

 INSERT INTO Orders VALUES('110004','WBQ',3,TO_DATE('2000-02-01','YYYY-MM-DD'));

INSERT INTO Orders VALUES('110005','CZH',1,TO_DATE('2000-02-01','YYYY-MM-DD'));

INSERT INTO Orders VALUES('110006','CZH',2,TO_DATE('2000-03-01','YYYY-MM-DD'));

INSERT INTO Orders VALUES('110007','CZH',2,TO_DATE('2000-03-01','YYYY-MM-DD'));

INSERT INTO Orders VALUES('110008','KIDD',3,TO_DATE('2000-02-01','YYYY-MM-DD'));

INSERT INTO Orders VALUES('110009','KIDD',1,TO_DATE('2000-04-01','YYYY-MM-DD'));

INSERT INTO Orders VALUES('110010','KIDD',2,TO_DATE('2000-03-01','YYYY-MM-DD'));

INSERT INTO Orders VALUES('110011','KIDD',3,TO_DATE('2000-02-01','YYYY-MM-DD'));

INSERT INTO Orders VALUES('110012','CZH',3,TO_DATE('2000-01-10','YYYY-MM-DD'));

 COMMIT;

SELECT EmployeeID,OrderDate,OrderID,CustomerID FROM Orders ORDER BY EmployeeID,OrderDate,OrderID

-- 層遞直至實現唯一為止

SELECT EmployeeID,OrderDate,OrderID,CustomerID FROM Orders

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 並不唯一,導致結果非所需的

SELECT EmployeeID,OrderDate,OrderID,CustomerID

FROM Orders

WHERE (EmployeeID,OrderDate) IN (SELECT EmployeeID,Max(OrderDate) FROM Orders GROUP BY EmployeeID)

ORDER BY EmployeeID,OrderDate,OrderID,CustomerID

--Error ,這是個錯誤的表達式

 SELECT EmployeeID,OrderDate,OrderID,CustomerID FROM Orders

WHERE (EmployeeID,OrderDate,OrderID) IN (SELECT EmployeeID,MAX(OrderDate),MAX(OrderID)

FROM Orders GROUP BY EmployeeID)

-- 使用分析函數,也可以實現相應的子查詢

SELECT EmployeeID,OrderDate,OrderID,CustomerID

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

讓我們繼續看看 SQL Server 是如何處理的

 CREATE TABLE Orders

 ( OrderID VARCHAR(6),

 CustomerID VARCHAR(6),

 EmployeeID INT,

OrderDate DATETIME );

 INSERT INTO Orders VALUES('110001','WBQ',1,'2000-01-11');

INSERT INTO Orders VALUES('110002','WBQ',1,'2000-01-21');

INSERT INTO Orders VALUES('110003','WBQ',2,'2000-01-11');

INSERT INTO Orders VALUES('110004','WBQ',3,'2000-02-01');

INSERT INTO Orders VALUES('110005','CZH',1,'2000-02-01');

 INSERT INTO Orders VALUES('110006','CZH',2,'2000-03-01');

 INSERT INTO Orders VALUES('110007','CZH',2,'2000-03-01');

INSERT INTO Orders VALUES('110008','KIDD',3,'2000-02-01');

INSERT INTO Orders VALUES('110009','KIDD',1,'2000-04-01');

INSERT INTO Orders VALUES('110010','KIDD',2,'2000-03-01');

INSERT INTO Orders VALUES('110011','KIDD',3,'2000-02-01');

 INSERT INTO Orders VALUES('110012','CZH',3,'2000-01-10');

COMMIT;

 -- 多值,通常情況下該語句即可,不過在本例中 EmployeeID,OrderDate 並不唯一,導致結果非所需的

SELECT EmployeeID,OrderDate,OrderID,CustomerID FROM Orders O1

WHERE rderDate= (SELECT MAX(OrderDate) FROM Orders O2 WHERE O1.EmployeeID=O2.EmployeeID) ORDER BY EmployeeID,OrderDate,OrderID,CustomerID 等效於 Oracle 的以下語句

 SELECT EmployeeID,OrderDate,OrderID,CustomerID FROM Orders

WHERE (EmployeeID,OrderDate) IN (SELECT EmployeeID,Max(OrderDate)

 FROM Orders GROUP BY EmployeeID) ORDER BY EmployeeID,OrderDate,OrderID,CustomerID

正確的 SQLServer 子查詢寫法,用兩個 MAX 求得唯一值

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

-- 本例使用一種變通的方法,把幾個應有的附加條件加進來然後返回,比較難以理解

 SELECT CAST(SUBSTRING(BinStr,1,8) AS DATETIME) AS OrderDate, CAST(SUBSTRING(BinStr,9,6) AS VARCHAR) AS OrderID, CAST(SUBSTRING(BinStr,15,6) AS VARCHAR) AS 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;

 -- 本例中在子查詢中使用 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

 -- 本例使用了 IN 子查詢,可以自定義返回的 TOP N 條數

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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved