2017-12-06 3 views
1

Ich habe Schwierigkeiten, eine "mehrzeilige" Formel in U-SQL zu erstellen. Ich habe die Daten nach Datum sortiert, und für jeden möchte ich den ersten Wert von "Port" finden, der nicht dem Wert der aktuellen Zeile entspricht. In ähnlicher Weise möchte ich die letzte Zeile im Datumswert mit dem aktuellen Port-Wert finden, um herauszufinden, wie viele Tage ein Schiff im Hafen war. Beachten Sie, dass es sich dabei um die Zeile mit dem gleichen Anschlussnamen handelt, zwischen denen keine neuen/anderen Anschlüsse vorhanden sind.U-SQL Wie wähle ich den ersten Wert in einer Spalte, die sich von der aktuellen Zeile unterscheidet?

ich meine Daten bin Laden in wie folgt aus:

@res = SELECT 
     Port, 
     Date 
     FROM @data; 

Dies ist, wie mein Tag strukturiert:

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 | 

Wie ich möchte die Daten strukturiert werden:

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 

Ich bin neu in U-SQL und so habe ich ein bisschen Schwierigkeiten, wie man das angehen kann. Mein erster Instinkt wäre, eine Kombination aus LEAD()/LAG() und ROW_NUMBER() OVER (PARTITION BY xx ORDER BY Datum) zu verwenden, aber ich bin mir nicht sicher, wie ich genau den gewünschten Effekt erzielen kann.

Kann mir jemand in die richtige Richtung zeigen?

+0

Sind die Duplikate notwendig? –

Antwort

1

können Sie tun, was Sie brauchen, um mit den so genannten Ranking und Analytic Funktionen wie LAG, DENSE_RANK und die OVER Klausel, obwohl es nicht ganz einfach ist. Dieses einfache Rigging funktionierte für Ihre Testdaten. Ich würde vorschlagen, es gründlich mit einem größeren und komplexeren Datensatz zu testen.

// 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); 

Meine Ergebnisse:

Results

Verwandte Themen