避免在查询中重复SQL片段?

时间:2012-05-17 14:55:44

标签: sql-server sql-server-2008

我有这个查询(伪代码)

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())实际上是非常长的查询。

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

P.S。

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

4 个答案:

答案 0 :(得分:5)

您有多种选择:

  • 用户定义的函数(UDF)
  • 浏览
  • 公用表表达式(CTE)
  • CROSS / OUTER APPLY

根据数据的处理方式,确定最适合的数据。你的问题没有提供足够的细节来明确提出建议,但这些值得关注。

小心使用UDF,因为它们会迅速阻碍性能。我的经验法则是为简单的数据转换或数学计算编写UDF。我试图避免在函数中进行复杂的基于集合的操作,并且更喜欢视图或CTE。

答案 1 :(得分:2)

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

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

正如Mikael Eriksson在他的评论中正确指出的那样,你可能需要在这里使用ISNULL而不是COALESCE,因为其中一个参数包含子查询而ISNULL可能(或者事实上,在这种情况下会更有效率,正如你在this answer中所阐述的那样。

所以这是固定的ver:

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

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

答案 2 :(得分: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]

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

答案 3 :(得分:-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