在 SQL 中使用复杂语句以多种方式多次查询
Using complex statements in SQL queries multiple times in multiple ways
我正在 Microsoft SQL Server 2008
上设计一个 View
,它应该建立在相当多的业务逻辑之上,这意味着有很多 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
代码很长,难以阅读,如果需要更改业务逻辑,我很可能会忘记更改。
我想到的明显解决方案是在子 select 中处理案例,或者由 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 引擎处于简单连接的子 select 中,它对 SQL 引擎有影响吗?
PS:我的 case 语句通常由几个函数组成,主要是 datetime
处理和转换。
我认为您不必 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
语句等中使用它们。它使代码更具可读性,并且不会为您花费额外的资源。
如果有什么不清楚或不符合您的标准 - 让我知道。
我正在 Microsoft SQL Server 2008
上设计一个 View
,它应该建立在相当多的业务逻辑之上,这意味着有很多 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
代码很长,难以阅读,如果需要更改业务逻辑,我很可能会忘记更改。
我想到的明显解决方案是在子 select 中处理案例,或者由 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 引擎处于简单连接的子 select 中,它对 SQL 引擎有影响吗?
PS:我的 case 语句通常由几个函数组成,主要是 datetime
处理和转换。
我认为您不必 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
语句等中使用它们。它使代码更具可读性,并且不会为您花费额外的资源。
如果有什么不清楚或不符合您的标准 - 让我知道。