2017-12-06 16 views
1

私はU-SQLで「複数行」の式を作成する方法に苦労しています。私は日付でデータを注文し、それぞれのために、現在の行の値と等しくない「ポート」の最初の値を探したいとします。同様の方法で、現在のポート値で日付値の最後の行を検索して、船舶がポートに何日間保管されているか調べます。ここには同じポート名の行がなければならないことに注意してください。間には新しい/他のポートはありません。U-SQL現在の行と異なる列の最初の値を選択する方法は?

私はこのように私のデータをロードしています:

@res = SELECT 
     Port, 
     Date 
     FROM @data; 

これは私の日が構成されている方法です。

Port  | Date  | 
Port A | 1/1/2017 | 
Port A | 1/1/2017 | 
Port A | 1/2/2017 | 
Port B | 1/4/2017 | 
Port B | 1/4/2017 | 
Port B | 1/4/2017 | 
Port B | 1/5/2017 | 
Port B | 1/6/2017 | 
Port C | 1/9/2017 | 
Port C | 1/10/2017 | 
Port C | 1/11/2017 | 
Port A | 1/14/2017 | 
Port A | 1/15/2017 | 

私はデータを構造化することがしたい方法:

Port  | Date  | Time in Port | Previous Port 
Port A | 1/1/2017 |  0   | N/A 
Port A | 1/1/2017 |  0   | N/A 
Port A | 1/2/2017 |  1   | N/A 
Port B | 1/4/2017 |  0   | Port A 
Port B | 1/4/2017 |  0   | Port A 
Port B | 1/4/2017 |  0   | Port A 
Port B | 1/5/2017 |  1   | Port A 
Port B | 1/6/2017 |  2   | Port A 
Port C | 1/9/2017 |  0   | Port B 
Port C | 1/10/2017 |  1   | Port B 
Port C | 1/11/2017 |  2   | Port B 
Port A | 1/14/2017 |  0   | Port C 
Port A | 1/15/2017 |  1   | Port C 

私はU-SQLを初めて使用しているので、これにアプローチする方法について少し問題があります。 私の最初の本能は、LEAD()/ LAG()とROW_NUMBER()OVER(PARTITION BY xx ORDER BY日付)の組み合わせを使用することですが、私が探している正確な効果を得る方法は不明です。

誰かが正しい方向に向いていますか?

+0

は、必要に応じて複製していますか? –

答えて

1

あなたはそれが完全に簡単ではないのですが、あなたは、いわゆるRankingAnalyticLAGなどの機能、DENSE_RANKOVER句で必要なものを行うことができます。このシンプルなリグはテストデータのために働きました。私はより大きくて複雑なデータセットを使って徹底的にテストすることを提案します。

// Test data 
@input = SELECT * 
    FROM (
     VALUES 
     ("Port A", DateTime.Parse("1/1/2017", new CultureInfo("en-US")), 0), 
     ("Port A", DateTime.Parse("1/1/2017", new CultureInfo("en-US")), 0), 
     ("Port A", DateTime.Parse("1/2/2017", new CultureInfo("en-US")), 1), 
     ("Port B", DateTime.Parse("1/4/2017", new CultureInfo("en-US")), 0), 
     ("Port B", DateTime.Parse("1/4/2017", new CultureInfo("en-US")), 0), 
     ("Port B", DateTime.Parse("1/4/2017", new CultureInfo("en-US")), 0), 
     ("Port B", DateTime.Parse("1/5/2017", new CultureInfo("en-US")), 1), 
     ("Port B", DateTime.Parse("1/6/2017", new CultureInfo("en-US")), 2), 
     ("Port C", DateTime.Parse("1/9/2017", new CultureInfo("en-US")), 0), 
     ("Port C", DateTime.Parse("1/10/2017", new CultureInfo("en-US")), 1), 
     ("Port C", DateTime.Parse("1/11/2017", new CultureInfo("en-US")), 2), 
     ("Port A", DateTime.Parse("1/14/2017", new CultureInfo("en-US")), 0), 
     ("Port A", DateTime.Parse("1/15/2017", new CultureInfo("en-US")), 1) 
    ) AS x (Port, Date, timeInPort); 



// Add a group id to the dataset 
@working = 
    SELECT Port, 
      Date, 
      timeInPort, 
      DENSE_RANK() OVER(ORDER BY Date) - DENSE_RANK() OVER(PARTITION BY Port ORDER BY Date) AS groupId 

    FROM @input; 


// Use the group id to work out the datediff with previous row 
@working = 
    SELECT Port, 
      Date, 
      timeInPort, 
      groupId, 
      Date.Date.Subtract((DateTime)(LAG(Date) OVER(PARTITION BY groupId ORDER BY Date) ?? Date)).TotalDays AS diff // datediff 

    FROM @working; 


// Work out the previous port, based on group id 
@ports = 
    SELECT Port, groupId 
    FROM @working 
    GROUP BY Port, groupId; 

@ports = 
    SELECT Port, groupId, LAG(Port) OVER(ORDER BY groupId) AS previousPort 
    FROM @ports; 


// Prep the final output 
@output = 
    SELECT w.Port, 
      w.Date.ToString("M/d/yyyy") AS Date, 
      SUM(w.diff) OVER(PARTITION BY w.groupId ORDER BY w.Date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS timeInPort, 
      p.previousPort 
    FROM @working AS w 
     INNER JOIN 
      @ports AS p 
     ON w.Port == p.Port 
      AND w.groupId == p.groupId; 


OUTPUT @output TO "/output/output.csv" 
ORDER BY Date, Port  
USING Outputters.Csv(quoting:false); 

マイ結果:

Results

関連する問題