我可以稍后在同一视图中使用在 SQL Server 视图中计算的列吗?

Posted

技术标签:

【中文标题】我可以稍后在同一视图中使用在 SQL Server 视图中计算的列吗?【英文标题】:Can I use a column calculated in a SQL Server view later on in that same view? 【发布时间】:2011-12-21 20:10:58 【问题描述】:

假设我有以下观点:

Select 
    t1.StartMile, t2.EndMile,  t2.EndMile- t1.StartMile as TotMile
from 
   TableStarts as t1 
inner join 
   TableEnds as t2 on t1.Id = t2.Id  

有没有办法编辑视图以执行以下操作

Select  
    t1.StartMile, t2.EndMile, t2.EndMile - t1.StartMile as TotMile, 
    TotMile + 30  as EvenMoreMiles

我试过了,但报错:

列名“TotMile”无效

请不要告诉我使用t2.EndMile - t1.StartMile + 30 as EvenMoreMilesTotMiles 在我的实际代码中是一个很长的 case 语句。

我宁愿不必创建中间视图。

我使用的是 SQL Server 2005。

稍后添加

感谢您的所有回答。我会全部投票。

答案提出了以下新问题:

鉴于有数千行,TotMiles 如下所示,给出的哪个答案最有效?还是创建中间视图最有效?

CASE WHEN t .TaskType = 1  and  t .StartTime < '1/1/2012'  
               THEN (tv.EndMile - tv.StartMile )  
     WHEN NOT (t .Location1_PKey = c.pkey OR t .Location2_PKey = c.pkey)
              then (tv.EndMile - tv.StartMile )
     WHEN (tv.EndMile - tv.StartMile ) < 31  Then 0 
     ELSE  (tv.EndMile - tv.StartMile - 30 )
END AS MilesAdjusted2012,

【问题讨论】:

当谈到效率问题时,答案通常是“视情况而定”——我们不知道你的数据是什么样的,你有什么索引等等。我们也不知道是否甚至假设最差的解决方案对于您的目的已经足够有效,或者我们表现最好的答案仍然不足以满足您的情况/ 谢谢达米安。我很懒。 【参考方案1】:

您还可以使用更简洁的CROSS APPLY,特别是在您构建引用前面的别名的别名链时。

SELECT t1.StartMile,
       t2.EndMile,
       TotMile,
       EvenMoreMiles,
       AndYetMoreMiles
FROM   TableStarts AS t1
       INNER JOIN TableEnds AS t2
         ON t1.Id = t2.Id
       CROSS APPLY (SELECT t2.EndMile - t1.StartMile) A(TotMile)
       CROSS APPLY (SELECT TotMile + 30) A2(EvenMoreMiles)
       CROSS APPLY (SELECT EvenMoreMiles + 100) A3(AndYetMoreMiles)  

【讨论】:

请参阅我添加的效率问题部分 @LillLansey - 嵌套 CTE 或嵌套交叉应用都可能会评估一次表达式,如果这是您要问的?尽管您需要检查执行计划才能看到,但在这方面并不能保证太多。 @MartinSmith - CROSS APPLY 子句的顺序重要吗?您能否参考第一个子句中第二个子句中的字段? @JNK - 是的,因为这个原因,你不能。【参考方案2】:

你不能直接,但你可以建立子选择:

select StartMile,EndMile,TotMile,TotMile+30 as EvenMoreMiles from (
  Select t1.StartMile, t2.EndMile,  t2.EndMile- t1.StartMile as TotMile
  from 
  TableStarts as t1 
  inner join 
  TableEnds as t2 
  on t1.Id = t2.Id  
) t

或者使用公用表表达式:

;with FirstCalcs as (
  Select t1.StartMile, t2.EndMile,  t2.EndMile- t1.StartMile as TotMile
  from 
  TableStarts as t1 
  inner join 
  TableEnds as t2 
  on t1.Id = t2.Id  
)
select StartMile,EndMile,TotMile,TotMile+30 as EvenMoreMiles from FirstCalcs

如果要建立最终计算的多个级别,我通常更喜欢使用 CTE,因为否则大多数格式化方案都难以使选择、子选择、子子选择等变得简单读书。 CTE 可以包含对先前定义的 CTE 的引用:

;with CTE1 as (
    SELECT ...
), CTE2 as (
    SELECT ... FROM CTE1
), CTE3 as (
    SELECT ... FROM CTE2
), CTE4 as (
    SELECT ... FROM CTE2 ... CTE3
)
SELECT ... FROM CTE4 ... CTE1

【讨论】:

请参阅我添加的效率问题部分【参考方案3】:

尝试使用派生表。

SELECT 
  DerivedTable.*,
  TotMile + 30 as EvenMoreMiles
From (Select 
        t1.StartMile, 
        t2.EndMile, 
        t2.EndMile- t1.StartMile as TotMile
        FROM Table t1 
        Inner Join table2 t2 on t1.PK = t2.FK) DerivedTable

【讨论】:

请参阅我添加的效率问题部分【参考方案4】:

您可以使用公用表表达式 (CTE) 来执行此操作。这里有很多:http://www.4guysfromrolla.com/webtech/071906-1.shtml

基本上,

CREATE VIEW ... AS

WITH Mileage (StartMile, EndMile, TotMile) AS (Select t1.StartMile, t2.EndMile,  t2.EndMile- t1.StartMile as TotMile
from 
TableStarts as t1 
inner join 
TableEnds as t2 
on t1.Id = t2.Id) 

SELECT TotMile FROM Mileage

【讨论】:

请参阅我添加的效率问题部分

以上是关于我可以稍后在同一视图中使用在 SQL Server 视图中计算的列吗?的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 索引视图与 Oracle 物化视图

使用 SQL Server 将子查询结果重用于其他计算

是否可以在 SQL Server 中使用 nolock 更改视图?

在 SQL Server 中使用数据透视表作为视图

在 SQL Server 视图中使用快照隔离级别

在架构内创建多个视图 - SQL Server