2013-05-09 35 views
4

我繼承了一個我希望優化的舊SQL腳本,但經過多次測試後,我必須承認,我所有的測試都只是用重複塊創建大型SQL。我想知道是否有人可以針對以下模式提出更好的代碼(請參閱下面的代碼)。我不想使用臨時表(WITH)。爲了簡單起見,我只放了3個級別(表TMP_C,TMP_D和TMP_E),但原始SQL有8個級別。用於NOT IN的TSQL優化代碼

WITH 
TMP_A AS (
SELECT 
ID, 
Field_X 
FROM A 

TMP_B AS(
SELECT DISTINCT 
ID, 
Field_Y, 
CASE 
    WHEN Field_Z IN ('TEST_1','TEST_2') THEN 'CATEG_1' 
    WHEN Field_Z IN ('TEST_3','TEST_4') THEN 'CATEG_2' 
    WHEN Field_Z IN ('TEST_5','TEST_6') THEN 'CATEG_3' 
    ELSE 'CATEG_4' 
END AS CATEG 
FROM B 
INNER JOIN TMP_A 
ON TMP_A.ID=TMP_B.ID), 

TMP_C AS (
SELECT DISTINCT 
ID, 
CATEG 
FROM TMP_B 
WHERE CATEG='CATEG_1'), 

TMP_D AS (
SELECT DISTINCT 
ID, 
CATEG 
FROM TMP_B 
WHERE CATEG='CATEG_2' AND ID NOT IN (SELECT ID FROM TMP_C)), 

TMP_E AS (
SELECT DISTINCT 
ID, 
CATEG 
FROM TMP_B 
WHERE CATEG='CATEG_3' 
AND ID NOT IN (SELECT ID FROM TMP_C) 
AND ID NOT IN (SELECT ID FROM TMP_D)) 

SELECT * FROM TMP_C 
UNION 
SELECT * FROM TMP_D 
UNION 
SELECT * FROM TMP_E 

非常感謝您的幫助。

+0

不是'NOT IN'上'TMP_D'的'WHERE'條款的其他部分和'TMP_E'多餘的?由於類別不重疊,如'TMP_B'中定義的,在隨後的查詢中不需要檢查除類別以外的任何內容。這使得它們看起來像只在'UNION'返回時纔會過濾'CATEG_4'。 (是的,'distinct'在那裏。) – HABO 2013-05-09 15:39:27

+0

@HABO:如果ID是唯一的,它們將是多餘的,但事實並非如此。不幸的是,ID不是唯一的,我們可以使用ID = 10和Field_Z = TEST_1的記錄,也可以使用ID = 10但Field_Z = TEST_3的記錄。 – Bouzouki 2013-05-09 17:16:51

回答

3

首先,選擇DISTINCT將防止結果集中出現重複,這樣您就會過度使用條件。通過添加「WITH」定義並嘗試嵌套它們的使用使其更容易跟隨。數據最終都來自「B」表,其中也有「A」中的關鍵匹配。讓我們從這個開始吧......因爲您沒有使用結果集中(B)Field_Y或(A)Field_X的任何內容,請不要將它們添加到混淆中。

SELECT DISTINCT 
     B.ID, 
     CASE WHEN B.Field_Z IN ('TEST_1','TEST_2') THEN 'CATEG_1' 
      WHEN B.Field_Z IN ('TEST_3','TEST_4') THEN 'CATEG_2' 
      WHEN B.Field_Z IN ('TEST_5','TEST_6') THEN 'CATEG_3' 
      ELSE 'CATEG_4' 
      END AS CATEG 
    FROM 
     B JOIN A ON B.ID = A.ID 
    WHERE 
     B.Field_Z IN ('TEST_1', 'TEST_2', 'TEST_3', 'TEST_4', 'TEST_5', 'TEST_6') 

where子句將只包括那些你想要的類別合格值,而且還有每個每個類別的結果。

現在,如果您確實需要「Field_Y」或「Field_X」中的其他值,則會生成不同的查詢。但是,您的Tmp_C,Tmp_D和Tmp_E無論如何都只會詢問ID和CATEG列。

+0

可能是愚蠢的問題:'UNION'對排序有什麼影響,也就是說,TEST_3/4s之前原來是否會返回所有TEST_1/2s?如果不是原來的查詢真的很瘋狂。 (並且至少應該使用'UNION ALL'而不是'UNION'。) – Rup 2013-05-09 15:44:48

+0

@DRAPE:實際上,我們不需要Field_X或Field_Y作爲示例。我忘了將它們從(更復雜的)原始查詢中移除。現在看起來很簡單,我看你的答案。謝謝你的幫助。 – Bouzouki 2013-05-09 16:12:45

+1

@Rup:不,他們不需要根據我的理解排序的數據(這是一箇舊的查詢,我可以假設他們試圖做什麼)。這不是唯一的瘋狂! – Bouzouki 2013-05-09 16:16:04

0

這可能有更好的表現

SELECT DISTINCT B.ID, 'CATEG_1' 
    FROM 
     B JOIN A ON B.ID = A.ID 
    WHERE 
     B.Field_Z IN ('TEST_1', 'TEST_2') 
UNION 
SELECT DISTINCT B.ID, 'CATEG_2' 
    FROM 
     B JOIN A ON B.ID = A.ID 
    WHERE 
     B.Field_Z IN ('TEST_3', 'TEST_4') 
...