2017-12-06 12 views
1

저는 U-SQL에서 "다중 행"수식을 만드는 방법에 어려움을 겪고 있습니다. Date에 의해 데이터를 정렬했으며 각각에 대해 현재 행의 값과 같지 않은 "Port"의 첫 번째 값을 찾고자합니다. 비슷한 방법으로 날짜 값의 마지막 행을 현재 포트 값으로 찾아서 선박이 포트에 몇 일 동안 있었는지 알아 내야합니다. 여기에 새로운 포트와 다른 포트가없는 동일한 포트 이름을 가진 행이 있어야합니다.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

당신은 완전히 간단하지 비록 당신이 LAG, DENSE_RANK 같은 소위 RankingAnalytic 기능과 OVER 절 무엇을해야 할 수 있습니다. 이 간단한 장비는 테스트 데이터를 처리하기 때문에 더 크고 복잡한 데이터 세트로 철저히 테스트 해 볼 것을 제안합니다.

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