在SQL查询中以多种方式多次使用复杂语句

时间:2015-05-04 07:45:49

标签: sql-server sql-server-2008 tsql query-optimization

我在View上设计一个Microsoft SQL Server 2008,它应该基于很多业务逻辑构建,这意味着有很多CASE WHEN THEN ELSE语句。问题是,查询中的其他位置经常需要一个CASE语句的结果,例如函数,联接和其他情况。这使得代码非常臃肿,难以阅读并且难以维护。

以下是此类视图的示例(字段和函数仅用于说明):

SELECT

    -- Random complicated case
    CASE
        WHEN A=B AND CAST(C AS int)=D AND DATEDIFF(DAY,E,F) > 5
        THEN D-A
        WHEN A<>B AND CAST(C AS int)=D AND DATEDIFF(DAY,E,F) > 5
        THEN D-A - 5
        WHEN A=B AND CAST(C AS int)<>D AND DATEDIFF(DAY,E,F) > 5
        THEN D-A - 10
        WHEN A<>B AND CAST(C AS int)<>D AND DATEDIFF(DAY,E,F) > 5
        THEN D-A - 15
    END AS ComplicatedCase

    -- Use of that same complicated case in another case
    CASE
        WHEN CASE
                WHEN A=B AND CAST(C AS int)=D AND DATEDIFF(DAY,E,F) > 5
                THEN D-A
                WHEN A<>B AND CAST(C AS int)=D AND DATEDIFF(DAY,E,F) > 5
                THEN D-A - 5
                WHEN A=B AND CAST(C AS int)<>D AND DATEDIFF(DAY,E,F) > 5
                THEN D-A - 10
                WHEN A<>B AND CAST(C AS int)<>D AND DATEDIFF(DAY,E,F) > 5
                THEN D-A - 15
             END > 300
        THEN CASE
                WHEN A=B AND CAST(C AS int)=D AND DATEDIFF(DAY,E,F) > 5
                THEN D-A
                WHEN A<>B AND CAST(C AS int)=D AND DATEDIFF(DAY,E,F) > 5
                THEN D-A - 5
                WHEN A=B AND CAST(C AS int)<>D AND DATEDIFF(DAY,E,F) > 5
                THEN D-A - 10
                WHEN A<>B AND CAST(C AS int)<>D AND DATEDIFF(DAY,E,F) > 5
                THEN D-A - 15
             END 
        ELSE NULL
    END AS AnotherCase

FROM SomeTable AS T
    -- Complicated case in join
    INNER JOIN AnotherTable AS AT
        ON  AT.ID = CASE
                        WHEN A=B AND CAST(C AS int)=D AND DATEDIFF(DAY,E,F) > 5
                        THEN D-A
                        WHEN A<>B AND CAST(C AS int)=D AND DATEDIFF(DAY,E,F) > 5
                        THEN D-A - 5
                        WHEN A=B AND CAST(C AS int)<>D AND DATEDIFF(DAY,E,F) > 5
                        THEN D-A - 10
                        WHEN A<>B AND CAST(C AS int)<>D AND DATEDIFF(DAY,E,F) > 5
                        THEN D-A - 15
                    END

代码很长,不可读,如果需要更改业务逻辑,我更可能忘记更改。

我遇到的一个明显的解决方案就是将子案例放在子选择中,或者由INNER JOINCROSS APPLY加入,如下所示:

-- Solution by CROSS APPLY sub-select
SELECT
    T1.ComplicatedCase,
    CASE
        WHEN ComplicatedCase > 300
        THEN ComplicatedCase
        ELSE NULL
    END AS AnotherCase

FROM SomeTable AS T
    CROSS APPLY
        (
        SELECT
            CASE
                WHEN A=B AND CAST(C AS int)=D AND DATEDIFF(DAY,E,F) > 5
                THEN D-A
                WHEN A<>B AND CAST(C AS int)=D AND DATEDIFF(DAY,E,F) > 5
                THEN D-A - 5
                WHEN A=B AND CAST(C AS int)<>D AND DATEDIFF(DAY,E,F) > 5
                THEN D-A - 10
                WHEN A<>B AND CAST(C AS int)<>D AND DATEDIFF(DAY,E,F) > 5
                THEN D-A - 15
            END AS ComplicatedCase
        FROM SomeTable AS ST
        WHERE T.ID = ST.ID
        ) AS T1

    INNER JOIN AnotherTable AS AT ON AT.ID = T1.ID

...并且工作正常,但我不知道查询性能是否会受到大规模影响(因为我不太了解引擎如何在内部处理这些内容)。

您是否有关于如何处理此类复杂语句的最佳实践?如果它是一个简单的连接子选择,它对SQL引擎是否重要?

PS:我的案例陈述通常由几个函数组成,主要是datetime处理和转换。

1 个答案:

答案 0 :(得分:2)

我不认为你必须var btns=''; var category = ["fur_", "fts_", "fas_"]; for(i = 1; i < category.length; i++){ btns +='<button type="button" class='+category[i]+' id= "myBtn'+i+'">Button</button>'; } document.getElementById('div').innerHTML = btns; var button = document.getElementById('myBtn1'); button.addEventListener('click', function () { alert('Clicked'); }, false); CROSS APPLY两次。

这应该有效:

SomeTable

SELECT T1.ComplicatedCase , CASE WHEN ComplicatedCase > 300 THEN ComplicatedCase ELSE NULL END AS AnotherCase FROM SomeTable AS T CROSS APPLY ( SELECT DATEDIFF(DAY, T.E, T.F) ) AS TT(DayDiff) CROSS APPLY ( SELECT CASE WHEN T.A = T.B AND CAST(T.C AS INT) = T.D AND TT.DayDiff > 5 THEN D - A WHEN T.A <> T.B AND CAST(T.C AS INT) = T.D AND TT.DayDiff > 5 THEN D - A - 5 WHEN T.A = T.B AND CAST(T.C AS INT) <> T.D AND TT.DayDiff > 5 THEN D - A - 10 WHEN T.A <> T.B AND CAST(T.C AS INT) <> T.D AND TT.DayDiff > 5 THEN D - A - 15 END ) AS T1(ComplicatedCase) INNER JOIN AnotherTable AS AT ON AT.ID = T1.ComplicatedCase; 允许您创建计算值并在CROSS APPLYJOINS语句中使用它们,等等。它使代码更具可读性,并且不应为您节省额外资源。

如果某些内容不清楚或不符合您的标准,请与我们联系。

相关问题