Как использовать переменные в запросе SELECT в SQL Server - PullRequest
0 голосов
/ 28 марта 2019

Я мигрирую с 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: оператор

A SELECT, которыйприсвоение значения переменной не должно сочетаться с операциями извлечения данных

ошибка - это симптом, а не моя главная проблема.Я не могу использовать ни один из предложенных обходных путей.

Я пытаюсь запустить функциональность PRODUCT() OVER.По сути, в этом столбце я пытаюсь получить предыдущее совокупное возвращаемое значение и установить для новой строки значение предыдущего совокупного * (1 + daily_return).

Ответы [ 3 ]

0 голосов
/ 28 марта 2019

Ваша проблема в том, что в 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 цикл для динамических переменных

0 голосов
/ 28 марта 2019

Ниже приводится то, что у меня есть, основываясь на ответе Дэвида Брауна. Это хорошая отправная точка. В 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
0 голосов
/ 28 марта 2019

Чтобы реализовать агрегат Product, запомните свою алгебру:

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

output

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

output

product
----------------------
-120
...