我正在 Microsoft SQL Server 2008
上设计一个View
,它应该构建在相当多的业务逻辑之上,这意味着有很多CASE WHEN THEN ELSE
语句。问题是,查询中的其他地方通常需要一个 CASE
语句的结果,例如函数、联接和其他情况。这使得代码变得极其臃肿,难以阅读和维护。
下面是此类 View 的示例(字段和函数仅用于说明):
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 JOIN
或 CROSS 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 引擎位于简单的连接子选择中,这对 SQL 引擎来说还重要吗?
PS:我的 case 语句通常由多个函数组成,主要是日期时间处理和转换。
最佳答案
我认为您不必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 APPLY
允许您创建计算值并在 JOINS
、WHERE
语句等中使用它们。它使代码更具可读性,并且不会为您花费额外的资源。
如果有些内容不清楚或不符合您的标准 - 请告诉我。
关于sql-server - 以多种方式在 SQL 查询中多次使用复杂语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30025067/