2017-12-19 7 views
1

を構築:idは、パーティション変数であるSQL Serverウィンドウ機能:私はこのようになり、長手方向のデータのテーブル持っている歴史の文字列

enter image description here

periodするのは時間の次元で、かつvalです観測値

enter image description here

は、私はSQLのウィンドウ関数ではなく、カーソルでこれをやろうとしているが、問題は:

は、私はこのように、idの各パネルのためvalの歴史を構築したいです私は、列定義のhistの自己参照の性質を守っています。 1つの行/列を1つの期間ごとに作成する必要があるようです。例えば、私が来ることができる最も近いこのでした:

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 

enter image description here

私はそれが最終的に動作するために反復を行うスプールと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 
+1

は再帰CTEのように見える再帰クエリを使用してみてください。サンプルデータを消耗品フォーマットで掲載して、すべてを入力する必要はありませんか?スクリーンショットデータの作成方法は?または、削除したいカーソルを使用していました。 –

+1

ええ、再帰的クエリは解決策です。しかし、SQL Server 2017を使用している場合は、文字列[string_agg](https://docs.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql)の集約関数があります。 – Irdis

+0

@SeanLangeサンプルデータを生成するためのコードをいくつか掲載しました。希望の結果のスクリーンショットについては、私はそれを手動で作成しました。 Thx –

答えて

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 
+0

FOR XML PATHのように思えるのですが、これは本当に可能ですか? – DaniDev

+0

@DaniDevはい、実際にはSTUFFとFOR XMLの両方が必要です。 –

+0

ありがとう、これは近い将来、ある時点で非常に便利になるでしょう。 – DaniDev

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] 
関連する問題