1

我有这个查询(伪代码)

SELECT 
    a = 1,
    b = 2,
    c = CASE 
            WHEN ISNULL(
                         (SELECT MONTH(GETDATE()) <---long query
                         ), 0) = 0 THEN 'found'
            ELSE 
              SELECT MONTH(GETDATE())     <--- repeated long query
        END

问题是SELECT MONTH(GETDATE())which 实际上是很长的查询。

这个“长表达式”是否有任何解决方法不在查询中出现两次?

ps

我有一个计算SELECT MONTH(GETDATE())外部变量的解决方案......但我试图弄清楚是否有一个内联解决方案。

4

4 回答 4

5

您有多种选择:

  • 用户定义函数 (UDF)
  • 意见
  • 公用表表达式 (CTE)
  • 交叉/外部应用

根据处理数据的方式,将确定哪个是最合适的。您的问题没有提供足够的细节来明确提供建议,但这些值得一看。

使用 UDF 时要小心,因为它们会很快影响性能。我个人的经验法则是为简单的数据转换或数学计算编写一个 UDF。我尽量避免在函数中执行复杂的基于集合的操作,并且更喜欢视图或 CTE。

于 2012-05-17T14:59:05.553 回答
2

您的示例中子查询的特定使用模式可以这样重写:

…
c = COALESCE(CAST(NULLIF((subquery), 0) AS varchar(10)), 'found')
…

正如 Mikael Eriksson 在他的评论中正确指出的那样,您可能需要使用ISNULL而不是COALESCEhere,因为其中一个参数包含一个子查询,并且ISNULL在这种情况下可能(或者实际上将)更有效,如您所见详细说明在这个答案中。

所以这是固定版本:

…
c = ISNULL(CAST(NULLIF((subquery), 0) AS varchar(10)), 'found')
…

但是请注意,如果您最终切换到,如果您决定更改它ISNULL,则应该注意第二个字符串 ( ) 的长度。'found'问题是,ISNULL将(尝试)将第二个参数转换为第一个参数的确切类型,包括指定字符串的最大长度(10在这种情况下)。如果您的第二个参数变为类似于'NULL or zero is found'而不是 just 'found'ISNULL则不会返回整个字符串,而是仅返回前 10 个字符 ( 'NULL or ze')。因此,您还需要记住更改第一个参数的类型(varchar(20)例如,更改为 )。

于 2012-05-18T06:49:51.553 回答
1
SELECT 
    a = 1,
    b = 2,
    c = CASE 
            WHEN ISNULL([l], 0) = 0 THEN 'found'
            ELSE [l]
        END
from tbl
cross apply (
SELECT MONTH(GETDATE()) as [l]
) as [x]

此外,如果您的原始查询代表您实际获得的内容(即,如果“长表达式”返回 null,则返回一个值),请考虑使用COALESCEcase 语句而不是 case 语句。或者只是使用ISNULL([l], 'found')

于 2012-05-17T19:42:44.370 回答
-1

使用 CTE 的示例

;WITH CTE AS
(
    SELECT CASE WHEN ISNULL(MONTH(GETDATE()),0) = 0 
    THEN 'FOUND' ELSE  ISNULL(MONTH(GETDATE()),0) END Col1
),
SELECT a = 1,b = 2, C = col1
FROM Table1, CTE

如果你有任何钥匙,可以用来加入

SELECT a = 1,b = 2, C = CASE WHEN ISNULL(v.col1,0) = 0 THEN 'Found' ELSE v.col1 END
        FROM Table1 a
OUTER APPLY (SELECT ISNULL(MONTH(DateCol),0) Col1 FROM TABLEName b
                a.id = b.id) v
于 2012-05-17T15:03:31.843 回答