我有一个纵向数据表,如下所示:
其中id
是分区变量,period
是时间维度,val
是观察值。
我想为val
的每个小组建立id
的历史记录,如下所示:
我正在尝试使用SQL窗口函数而不是游标,但我一直遇到的问题是hist
列定义的自引用性质。几乎看起来我必须每个周期创建一行/列。例如,我最接近的是:
IF OBJECT_ID('dbo.my_try', 'U') IS NOT NULL
DROP TABLE dbo.my_try;
GO
SELECT
id, period, val,
CASE
WHEN (
period = MIN(period)
OVER (PARTITION by id order by period ROWS
BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
) THEN CAST (val AS VARCHAR(60))
ELSE NULL
END AS hist
INTO my_try
FROM my_test
SELECT
id, period, val,
CASE
WHEN (
period = MIN(period) OVER
(PARTITION by id order by period ROWS
BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
) THEN hist
ELSE (
CONCAT(
val, ' | ', LAG(hist, 1) OVER (PARTITION by id order by period)
)
)
END AS hist2
FROM my_try
我必须假设迭代并执行hist3
等等,以便最终起作用。
是否可以使用SQL窗口函数完成此操作,或者光标是唯一的路径?
示例数据
以下是生成原始表的一些代码:
CREATE TABLE my_test (
id INT,
period INT,
val INT
)
BEGIN
DECLARE @id INT = 1;
DECLARE @period INT = 1;
WHILE @id <= 3
BEGIN
SET @period = 1
WHILE @period <= 3
BEGIN
INSERT INTO my_test VALUES (@id, @period, @period * POWER(10, @id))
SET @period = @period + 1
END
SET @id = @id + 1
END
END
答案 0 :(得分:2)
其实你不需要递归。您可以非常轻松地利用STUFF。当然,如果您在2017年,您可以使用上面建议的string_agg。但是,如果你像我一样,你的公司不是采用最新和最快的公司,你可以使用它。
select t1.id
, t1.period
, t1.val
, STUFF((select ' | ' + convert(varchar(10), val)
from my_test t2
where t2.id = t1.id
and t2.period <= t1.period
order by t1.period
FOR XML PATH('')), 1, 3,'')
from my_test t1
order by t1.id
, t1.period
答案 1 :(得分:1)
正如评论中所讨论的那样尝试使用递归查询
with cte as(
select id, [period], val, convert(varchar(max), val) as agg from my_try where [period] = 1
union all
select t.id, t.[period], t.val, CONCAT(c.agg, ' | ', t.val) from my_try t join cte c on c.[period] +1 = t.[period] and c.id = t.id
)
select * from cte order by id, [period]