2017-10-30 9 views
1

私は式をウインドウ内の最後の非NULL値をゲル化しようとしている:usqlウィンドウ式で最後の非NULL値を取得するにはどうすればいいですか?

LAST_VALUE([b]) OVER (ORDER BY Timestamp ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS bf 

残念ながら、それは動作しません。 カスタム集計関数を書きましたが、それも機能しません。

public class LastNonNull<T> : IAggregate<T, T> 
     where T : class 
    { 
     T last; 

     public override void Init() 
     { 
      last = null; 
     } 

     public override void Accumulate(T val) 
     { 
      if (val != null) 
      { 
       last = val; 
      } 
     } 

     public override T Terminate() 
     { 
      return last; 
     } 

    } 

使用しようとしています。私は、ユーザー定義のオブジェクトのどのような種類を使用することができ

AGG<DataLakeTest.LastNonNull<string>>([b]) OVER (ORDER BY Timestamp ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS bf 

Error E_CSC_USER_UNEXPECTEDOVERCLAUSE: Unexpected OVER clause. Description: An OVER clause must follow a ranking function call (such as RANK() or ROW_NUMBER()) or a WITHIN GROUP clause. Resolution: Make sure the OVER clause immediately follows a ranking function call or a WITHIN GROUP clause.

更新

スクリプト:

@tb1 = SELECT * FROM 
     (VALUES 
     (1, "Val1"), 
     (2, (string)null), 
      (3, "Val3"), 
      (5, (string) null), 
      (6, (string)null), 
      (7, "Val7"), 
      (8, "Val8") 
     ) AS T(Timestamp, a); 

@tb1 = 
    SELECT Timestamp, 
      ??? AS a 
    FROM @tb1; 

OUTPUT @tb1 TO "/test.csv" USING Outputters.Csv(outputHeader: true); 

予想される出力:

"Timestamp","a" 
1,"Val1" 
2,"Val1" 
3,"Val3" 
5,"Val3" 
6,"Val3" 
7,"Val7" 
8,"Val8" 

アップデート2:

残念ながら、私はLAG関数を使用することはできませんNULL以外の値の間のNULL値の数は不明であるためです。私は非常に巨大なテーブルを持っている場合、処理ステップが凍結するので、クロスジョインを使用することはできません。私の現在のソリューション(私はそれを使用して満足していない):

@tb1 = 
    SELECT Timestamp, 
      [a], 
      [a] != null && [a] != LEAD([a], 1) OVER(ORDER BY Timestamp ASC) AS aSwitch 
    FROM @tb1; 

@tb1 = 
    SELECT Timestamp, 
      [a], 
      SUM(aSwitch ? 1 : 0) OVER(ORDER BY Timestamp ASC ROWS UNBOUNDED PRECEDING) AS aGrp 
    FROM @tb1; 

@tb1 = 
    SELECT Timestamp, 
      FIRST_VALUE([a]) OVER(PARTITION BY aGrp ORDER BY Timestamp ASC) AS a 
    FROM @tb1; 

最終的な解決策:

public class ReplaceNullReducer : IReducer 
{ 
    string lastValue = null; 
    public override IEnumerable<IRow> Reduce(IRowset input, IUpdatableRow output) 
    { 
     foreach (var row in input.Rows) 
     { 
      var val = row.Get<string>("a"); 
      if (val != null) lastValue = val; 
      output.Set<string>("a", lastValue); 
      output.Set<int>("Timestamp", row.Get<int>("Timestamp")); 
      yield return output.AsReadOnly(); 
     } 
    } 
} 

USQL(何らかの理由で "ALL" オプションはE_CSC_USER_SYNTAXERRORエラーをトリガーするので、私はダム導入デバイス欄):

@tb1 = SELECT * FROM 
     (VALUES 
     (1, "Val1", 1), 
     (2, (string)null, 1), 
      (3, "Val3", 1), 
      (5, (string) null, 1), 
      (6, (string)null, 1), 
      (7, "Val7", 1), 
      (8, "Val8", 1) 
     ) AS T(Timestamp, a, device); 
@tb1 = REDUCE @tb1 PRESORT [Timestamp] ON device 
     PRODUCE [Timestamp] int, [a] string 
     USING new DataLakeTest.ReplaceNullReducer(); 
+0

いくつかのサンプルデータと期待される結果を提供してください。 – wBob

+0

入力データと期待出力を追加 –

+1

私は2,000万行のテストファイルを作成しました.UDOカスタムレデューサーは本当にうまくスケーリングされました。私の純粋なU-SQLのアプローチは絶対にひどくスケールされたので、私はそれを使用しないことをお勧めします。私はより効率的なアプローチを探しています。 – wBob

答えて

1

あなたが可能NULLで1行以上のものを持っていると仮定すると、あなたのソリューションが動作しているようです、またはカスタム減速を書くことができますプリソートされたリストで動作し、値を返します。

例えば、

@raw = SELECT * FROM 
    (VALUES 
     (1, "Val1"), 
     (2, (string) null), 
     (3, "Val3"), 
     (5, (string) null), 
     (6, (string) null), 
     (7, "Val7"), 
     (8, "Val8") 
    ) AS T(Timestamp, a); 

@res = REDUCE @raw PRESORT Timestamp ALL 
     PRODUCE Timestamp int, a string 
     USING new ReduceSample.ReplaceNullReducer(); 

それはヌル値が見つかるまで、それがnullではない(ヌル置換値を設定する)場合、値を取得する行をステップ再帰還元剤としてReplaceNullReducerを実装次にヌルを置換値で置き換えます。最初の値がヌル値の場合など、エッジケースをカバーするようにする必要があります。

次のブログ記事は、減速機の詳細があります:https://blogs.msdn.microsoft.com/azuredatalake/2016/06/27/how-do-i-combine-overlapping-ranges-using-u-sql-introducing-u-sql-reducer-udos/

+0

あなたがサンプルをコンパイルできません。もしALLを使用すると、E_CSC_USER_SYNTAXERROR:構文エラーが出ます。次のうちの1つが必要です:ASC DESCは、READYLYが必要です。 ')' '、' –

+0

Hmmm。あなたはALLを去らせることができますか?そして、あなたが書いた声明やusql(at)microsoft.comへの仕事リンクを私に送ってください。文書化された文法によると、ALLは許可されるべきですが、私はまだそれを試していません。 –

+1

フォローアップするだけです。 ALLとONの位置は現在明確に定義されていません。将来のリフレッシュで構文をクリーンアップします。 –

関連する問題