T-SQL:创建查找并根据以前的值计算的列

时间:2014-08-24 21:31:25

标签: sql-server tsql sql-server-2012 common-table-expression

我希望有人可以指出我正确的方向来编写一个返回计算值的查询,该计算值使用查找来查找以前的值。例如,我有两个表,如下所示。我在一个视图中将它们连接在一起,但我需要添加一个额外的列,它给我一个以前的值:

CEO_Table:

CEO_Name      | FromDate   | ToDate       
-----------------------------------------
Glen Bryant   | 2000-11-30 | 2002-06-30
Bob Costa     | 2002-6-30  | 2004-9-15  
Gill Bogart   | 2004-9-15  | 2009-10-01  
Ben Olson     | 2009-10-01 | 2010-08-10  

Expense_Table:

Date       | AsOf_Expenses_Total_Millions (as Exp)
-----------------------------------------
2001-01-01 | 100
2002-01-01 | 300
2003-01-01 | 155
2004-01-01 | 350
2005-01-01 | 400
2006-01-01 | 600
2007-01-01 | 150
2008-01-01 | 200
2009-01-01 | 300
2010-01-01 | 500

我正在尝试使用这两个表构建一个视图,该视图添加了3个额外的列: CEO(在给定日期查找CEO); LastCEOExp(查看以前CEO的最后费用值); PercentChange(使用LastCEOExp计算百分比变化,使用公式(Exp - LastCEOExp)/(LastCEOExp)* 100)

CEO_Expenses_Change_Over_Time:

Date       | Exp | CEO_Name      | LastCEOExp | PercentChange
-------------------------------------------------------------------
2001-01-01 | 100 | Glenn Bryant  | NULL       | NULL
2002-01-01 | 300 | Glenn Bryant  | NULL       | NULL
2003-01-01 | 155 | Bob Costa     | 300        | -48%
2004-01-01 | 350 | Bob Costa     | 300        | 16%
2005-01-01 | 400 | Gill Bogart   | 350        | 14%
2006-01-01 | 600 | Gill Bogart   | 350        | 71%
2007-01-01 | 150 | Gill Bogart   | 350        | -57%
2008-01-01 | 200 | Gill Bogart   | 350        | -42%
2009-01-01 | 300 | Gill Bogart   | 350        | -14%
2010-01-01 | 500 | Ben Olson     | 300        | 66%

我已经加入了CEO_Name列,但是我遇到了LastCEOExp列的问题。一旦我将该列固定下来,我可以将PercentChange列放在一起。有人有什么建议吗?我猜我可以使用CTE来完成这项任务,但我不确定从哪里开始。以下是我的内容:

SELECT exp.[Date]
  ,exp.[Exp]
  ,ceo.[CEO_Name]
FROM [Expense_Table] exp
INNER JOIN [CEO_Table] ceo
ON exp.[Date] between ceo.[FromDate] and ceo.[ToDate]

3 个答案:

答案 0 :(得分:0)

我做了这样的代码,我使用

ROW_NUMBER(Transact-SQL) http://msdn.microsoft.com/en-us/library/ms186734.aspx

在你的情况下,ROW_NUMBER可以随着时间的推移然后你玩ROW_ID 你可以创建函数返回表SHIFT + 1 ROW_ID然后JOIN表,小心你需要在使用临时表,视图时为ROW_ID上的大集添加索引...

你创建函数的第二个选项(参数datetime)返回值将适用于小集合

SELECT A.*,PrevYear.*, cast(( ROUND((cast(A.[Exp] as float) - cast(PrevYear.[Exp] as float) ) / cast(A.[Exp] as float) * 100  ,2) ) as varchar) + '%' as  PercentChange from
(SELECT ROW_NUMBER() OVER(ORDER BY exp.[Date] DESC) AS Row, exp.[Date]
  ,exp.[AsOf_Expenses_Total_Millions] as [Exp]
  ,ceo.[CEO_Name]
FROM [Expense_Table] exp
INNER JOIN [CEO_Table] ceo
ON exp.[Date] between ceo.[FromDate] and ceo.[ToDate]
) A left join


(SELECT (ROW_NUMBER()  OVER(ORDER BY exp.[Date] DESC) -1) AS Row, exp.[Date]
  ,exp.[AsOf_Expenses_Total_Millions] as [Exp]
  ,ceo.[CEO_Name] as PrevCEO_Name
FROM [Expense_Table] exp
INNER JOIN [CEO_Table] ceo
ON exp.[Date] between ceo.[FromDate] and ceo.[ToDate]
) PrevYear

on A.row = PrevYear.row
order by A.row

答案 1 :(得分:0)

您需要熟悉SQL Server中的window functions。这是一个解决方案:

WITH
    tmp AS
    (
        SELECT      exp.Date,
                    CEO_Name,
                    exp.Exp,
                    DENSE_RANK() OVER (ORDER BY ceo.FromDate)       AS CEOOrder,
                    ROW_NUMBER() OVER (PARTITION BY ceo.CEO_Name ORDER BY exp.Date DESC)
                                                                    AS ExpOrder
        FROM        CEO_Table       ceo
        INNER JOIN  Expense_Table   exp     ON exp.Date BETWEEN ceo.FromDate AND ceo.ToDate
    )

SELECT      t1.Date,
            t1.CEO_Name,
            t1.Exp,
            t2.Exp                              AS LastCEOExp,
            (t1.Exp - t2.Exp) / t2.Exp * 100    AS PercentChange
FROM        tmp     t1
LEFT JOIN   tmp     t2  ON t1.CEOOrder = t2.CEOOrder + 1  -- This select the last CEO
                       AND t2.ExpOrder = 1                -- This select his last pay
ORDER BY    t1.CEOOrder, t1.ExpOrder DESC

SQL Fiddle

答案 2 :(得分:-1)

我认为领先/滞后可能会让你得到你想要的东西:

如果OBJECT_ID(N'tempdb .. ## lag_table 'N'U')不为空
下降表## lag_table;

创建表## lag_table(
[ID] [INT]身份(1,1)
,[模型] [数据类型为sysname]
,[残余] [十进制](9,2)
,[创建] [日期]
);

插入## lag_table
([模型],[残留],[创建])
值(N'modelA”,10,N'2013-01-01' ),
(N'modelA”,5,N'2011-01-01' ),
(N'modelA”,2,N'2009-01-01' );

-
- 码块端
---------------------------------------------- ----------------------------
-
- 代码块开始
---------------------------------------------- ----------------------------
-
- 选择基于一个规定的时间间隔或次数的在先值
选择[ID]
,[模型]
,[残余]
,铅([残留],1.0)
超过( 通过
分区[模型]
为了通过[创建]降序)为[铅]
,滞后([残留],1.0)
超过( 通过
分区[模型]
为了通过[创建]降序)为[滞后]
从## lag_table;