如何在SQL Server中的SELECT查询中使用变量

时间:2019-03-28 17:32:00

标签: sql-server aggregate-functions

我正在从MySQL迁移到SQL Server。以下是我在MySQL中进行的查询,但不确定如何在SQL Server中使用变量。

SET @listid = 0;

SELECT 
    list_id, last_updated, price, daily_return,
    @cumu_ret := ROUND(
        IF (@listid = list_id,
            IF(daily_return IS NULL, 1.0, @cumu_ret * (1 + daily_return)),
            IF(daily_return IS NULL, 1.0, last_cumulative_return * (1 + daily_return))), 10) AS cumulative_return,
    @listid := list_id AS set_id
FROM 
    daily_return 
ORDER BY 
    list_id, last_updated

SQL Server具有SUM() OVER函数,但理想情况下我需要PRODUCT() OVER

有什么想法我能做什么?

编辑:当我尝试以下查询...

 DECLARE @listid int = 0;
 DECLARE @cumu_ret decimal(24,10) = NULL;

SELECT 
    list_id, last_updated, price, daily_return,
    @cumu_ret = ROUND(
        IIF (@listid = list_id,
            IIF(daily_return IS NULL, 1.0, @cumu_ret * (1 + daily_return)),
            IIF(daily_return IS NULL, 1.0, last_cumulative_return * (1 + daily_return))), 10),
    @listid = list_id
FROM 
    #daily_return 
ORDER BY 
    list_id, last_updated

它抛出一个错误:

  

为变量分配值的SELECT语句不得与数据检索操作结合使用。

编辑2:

  

为变量分配值的SELECT语句不得与数据检索操作组合

错误是一种症状,而不是我的主要问题。我无法使用任何建议的解决方法。

我正在尝试使用PRODUCT() OVER功能。基本上,在该列中,我尝试获取先前的累积返回值,并将新行的值设置为先前的累积*(1 + daily_return)。

3 个答案:

答案 0 :(得分:0)

要实施产品汇总,请记住您的代数:

declare @t table (i int)
insert into @t(i) values (1),(2),(3),(4),(5)
select exp(sum(log(i))) product
from @t

输出

product
----------------------
120
  

我的数据为负数。

然后我们需要添加一些模块化算法:

declare @t table (i int)
insert into @t(i) values (-1),(-2),(3),(-4),(5)
select exp(sum(log(abs(i)))) 
       * case when sum(case when sign(i) = -1 then 1 else 0 end) % 2 = 1 then -1 else 1 end product
from @t

输出

product
----------------------
-120

答案 1 :(得分:0)

您的问题是,在SQL Sever中,您需要在SELECT语句之外设置变量(如使用DECLARE正确完成的操作一样)。

不允许这些行:

 @cumu_ret = ROUND(
        IIF (@listid = list_id,
            IIF(daily_return IS NULL, 1.0, @cumu_ret * (1 + daily_return)),
            IIF(daily_return IS NULL, 1.0, last_cumulative_return * (1 + daily_return))), 10),
    @listid = list_id

您想要更多类似这样的东西:

 DECLARE @listid int = 0;
 DECLARE @cumu_ret decimal(24,10) = NULL;
 SET @listid = list_id;
 SET @cumu_ret = select ROUND(
        IIF (@listid = list_id,
            IIF(daily_return IS NULL, 1.0, @cumu_ret * (1 + daily_return)),
            IIF(daily_return IS NULL, 1.0, last_cumulative_return * (1 + daily_return))), 10) as cumn_ret from #daily_return 

SELECT 
    list_id, last_updated, price, daily_return,
    @cumu_ret, @listid
FROM 
    #daily_return 
ORDER BY 
    list_id, last_updated

这可能需要进行一些修改-我只是想为您指明正确的方向...您可能还想研究对动态变量进行while循环

答案 2 :(得分:0)

根据David Browne的回答,以下是我目前所拥有的。这是一个很好的起点。在MySQL中,我能够以增量方式保存PRODUCT()OVER输出,而在MS SQL中可能无法这样做,并且可能需要使用游标...让我们看看。

WITH daily_return AS (
    SELECT 0 AS ID, 0 AS daily_return UNION ALL
    SELECT 1 AS ID, 0.1 AS daily_return UNION ALL
    SELECT 2 AS ID, -0.2 AS daily_return UNION ALL
    SELECT 3 AS ID, 0 AS daily_return UNION ALL
    SELECT 4 AS ID, -1.1 AS daily_return UNION ALL
    SELECT 5 AS ID, 0.3 AS daily_return UNION ALL
    SELECT 6 AS ID, 0.2 AS daily_return
)
select id, daily_return,
    (exp(sum(log(abs(1+daily_return))) over (order by id)))
    * (case when (sum(case when sign(1+daily_return) = -1 then 1 else 0 end) over (order by id)) % 2 = 1 then -1 else 1 end) product
from daily_return