2013-05-09 163 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') 
...