下面是我需要使用SQL
执行的数据集和计算类型ID Postdate Return LinkedValue
------------------------------
1001 7/1/2013 100 100
1001 7/2/2013 101 101
1001 7/3/2013 102 102*101/100
1001 7/4/2013 103 103*102*100/100
第一行的LinkedValue将等于返回值,但对于之后的每个连续行,它将是当前行的返回和为前一行计算的LinkedValue的乘积。
SQL中有没有办法实现这一目标?
答案 0 :(得分:0)
我认为这就是你要找的东西:
WITH cte_prep
AS (
SELECT
[rowid]
, [ID]
, [Postdate]
, [Return]
, RANK() OVER ( PARTITION BY ID ORDER BY Postdate ) AS P_Rank
FROM
[meta].[dbo].[return]
),
cte_recursive ( ID, Postdate, [Return], P_Rank, preturn, string, Level )
AS (
-- Anchor member definition
SELECT
e.ID
, e.Postdate
, e.[Return]
, e.P_Rank
, 10 AS preturn
, CAST(e.[return] AS NVARCHAR(MAX)) AS string
, 0 AS Level
FROM
cte_prep AS e
WHERE
e.P_Rank = 1
UNION ALL
-- Recursive member definition
SELECT
e.ID
, e.Postdate
, e.[Return]
, e.P_Rank
, d.[return] AS preturn
, CAST(d.string + ' * ' + CAST(e.[return] AS NVARCHAR(50)) AS NVARCHAR(MAX)) AS string
, Level + 1 AS Level
FROM
cte_prep AS e
INNER JOIN cte_recursive AS d
ON e.ID = d.ID AND
e.P_rank = d.P_rank + 1
)
SELECT
*
FROM
cte_recursive
答案 1 :(得分:0)
使用聚合作为窗口函数的聚合非常简单。
您没有指定DBMS,因此以下内容适用于PostgreSQL。
创建测试表:
create table adi (id integer, postdate date, return integer);
insert into adi (id, postdate, return)
values
(1001, date '2013-07-01', 100),
(1001, date '2013-07-02', 101),
(1001, date '2013-07-03', 102),
(1001, date '2013-07-04', 103);
创建一个乘以所有值的聚合:
create aggregate mult(bigint)
(
sfunc = int8mul,
stype=bigint
);
我们需要一个对行进行编号并保留第一行return
值的结果。这可以使用窗口函数来完成:
select id,
postdate,
return,
row_number() over (order by postdate) as rn,
first_value(return) over (order by postdate) as base_value
from adi
通过这个结果,我们可以创建最终查询:
with numbered as (
select id,
postdate,
return,
row_number() over (order by postdate) as rn,
first_value(return) over (order by postdate) as base_value
from adi
)
-- only get the first row, so that the return value of that
-- is not included in the running aggregate
select id,
postdate,
return,
return as linkedvalue
from numbered
where rn = 1
union all
select id,
postdate,
return,
(mult(return) over (order by postdate))::numeric / (case when rn > 2 then base_value else 1 end)
from numbered
where rn > 1;
返回以下结果:
id | postdate | return | linkedvalue
-----+------------+--------+------------
1001 | 2013-07-01 | 100 | 100
1001 | 2013-07-02 | 101 | 101.00
1001 | 2013-07-03 | 102 | 103.02
1001 | 2013-07-04 | 103 | 10611.06
除自定义聚合函数外,查询几乎是标准的ANSI SQL。如何为正在使用的DBMS定义一个取决于该DBMS。
如果没有创建自定义聚合的能力,可以使用递归CTE完成。以下是标准ANSI SQL,没有任何特定于产品的语法:
with recursive numbered as (
select id,
postdate,
return,
row_number() over (order by postdate) as rn,
first_value(return) over (order by postdate) as base_value
from adi
), calc as (
select id, postdate, return, return as linkedvalue, base_value, rn
from numbered
where rn = 1
union all
select c.id, c.postdate, c.return,
case when c.rn > 2 then (c.return * p.linkedvalue) else c.return end,
p.base_value,
c.rn
from numbered c
join calc p on c.rn - 1 = p.rn
where c.rn > 1
)
select id, postdate, return,
case when
rn > 2 then cast(linkedvalue as numeric) / 100
else linkedvalue
end as linkedvalue
from calc
order by postdate;