如何在查询中多次引用SQL代码段?

时间:2015-06-11 08:05:18

标签: sql-server tsql sql-server-2012

我需要将一些存储过程转换为视图,并且存储过程有很多DECLARE语句,这些语句创建了稍后在查询中引用的常量。例如

SELECT @FIRSTDAYLASTYEAR = DATEADD(YEAR, DATEDIFF(YEAR, '1901-01-01', DATEADD(YEAR, -1, getdate())), '1901-01-01')

我需要多次在单个查询中引用@FIRSTDAYLASTYEAR,在不必声明变量的情况下,最好的方法是什么?

例如考虑:

DECLARE @FIRSTDAYLASTYEAR datetime = DATEADD(YEAR, DATEDIFF(YEAR, '1901-01-01', DATEADD(YEAR, -1, getdate())), '1901-01-01')
select
    @FIRSTDAYLASTYEAR as FirstDayLastYear,
    Case when orderDate > @FIRSTDAYLASTYEAR then 'CurrentOrders' else 'ArchiveOrders' end as State
from
    orders

我不想重写为

select
    DATEADD(YEAR, DATEDIFF(YEAR, '1901-01-01', DATEADD(YEAR, -1, getdate())), '1901-01-01') as FirstDayLastYear,
    Case when orderDate > DATEADD(YEAR, DATEDIFF(YEAR, '1901-01-01', DATEADD(YEAR, -1, getdate())), '1901-01-01') then 'CurrentOrders' else 'ArchiveOrders' end as State
from
    orders

我希望能够在查询中以某种方式对@FIRSTDAYLASTYEAR进行别名。

修改

感谢您的回复,您认为这会有相同的表现吗?

select
    constants.FirstDayLastYear,
    Case when orderDate > constants.FirstDayLastYear then 'CurrentOrders' else 'ArchiveOrders' end as State
from
    orders o
cross join 
    (select 
        DATEADD(YEAR, DATEDIFF(YEAR, '1901-01-01', DATEADD(YEAR, -1, getdate())), '1901-01-01') as FirstDayLastYear
        ) as constants

我要问的原因是,此代码可能会在未来支持CTE的日期移植到另一个数据库平台。

5 个答案:

答案 0 :(得分:2)

您可以构造一个包含所有变量的单行的CTE,然后在查询中引用它:

WITH Consts as (
    SELECT DATEADD(YEAR, DATEDIFF(YEAR, '19010101', getdate()), '19000101')
           as FirstDayLastYear,
           DATEADD(YEAR, DATEDIFF(YEAR, '19010101', getdate()), '19001231')
           as LastDayLastYear
)
select
    c.FirstDayLastYear,
    Case when orderDate > c.FirstDayLastYear then 'CurrentOrders' else 'ArchiveOrders' end as State
from
    orders
       cross join
    Consts c

如果您有基于其他变量构建的变量,则可能需要具有多个级别的CTE。

答案 1 :(得分:1)

您还可以使用APPLY VALUES

SELECT   
  FirstDateLastYear as FirstDayLastYear,
  CASE WHEN orderDate > FirstDateLastYear THEN 'CurrentOrders' ELSE 'ArchiveOrders' END AS State
FROM orders
CROSS APPLY (VALUES(DATEADD(YEAR, DATEDIFF(YEAR, '1901-01-01', DATEADD(YEAR, -1, getdate())), '1901-01-01'))) AS date(FirstDateLastYear);

答案 2 :(得分:0)

您应该考虑像

这样的'常用表格式'
WITH vars AS (
  SELECT DATEADD(YEAR, DATEDIFF(YEAR, '1901-01-01', DATEADD(YEAR, -1, getdate())), '1901-01-01') as FirstDayLastYear) 
)
SELECT Case when orderDate > FirstDayLastYear) then 'CurrentOrders' else 'ArchiveOrders' end as State
... --- your actual select statement for the view ...
FROM orders, vars
...

答案 3 :(得分:0)

SQL Server中的视图中不允许使用局部变量 在您描述的情况下,我可能会创建一个视图来封装存储过程中使用的变量的值,然后在更大的视图中查询该视图作为子查询或派生表(根据您的需要)。

但是,这可能无法转换存储过程中的所有局部变量。对于不可能的情况,您可以创建一个用户定义的函数来封装局部变量的值,并以我使用该视图描述的相同方式使用它。

您可以创建cte而不是视图,但是如果您需要相同的逻辑来应用于多个视图,则必须为转换为的每个过程编写cte图。

答案 4 :(得分:0)

您可以创建标量函数:

CREATE FUNCTION fnPrevYear ( )
RETURNS date
AS
    BEGIN
        RETURN DATEADD(YEAR, DATEDIFF(YEAR, '1901-01-01', DATEADD(YEAR, -1, GETDATE())), '1901-01-01')
    END

并在需要时调用它:

SELECT dbo.fnPrevYear()  

但是大数据会很慢。您可以使用公用表表达式作为更好的替代方法。