2012-04-12 4 views
2

타임 라인의 각 날짜에 대해 일부 측정 값과 측정 된 날짜가있는 데이터 세트의 최신 N 데이터 포인트 평균을 표시하는 시간 표시 막대 보고서를 만들려고합니다. 날짜를 제공하기 위해 매일 달력 표가 채워져 있습니다. 나는 보여주기 위해 타임 라인을 계산할 수 전체 평균 전에 상당히 간단 상관 하위 쿼리 (실제 상황은 훨씬 더 복잡 이것보다이지만, 본질적이 단순화 될 수있다)과 그 날짜에 :상관 하위 쿼리에서 MySQL의 이동 평균을 계산하는 방법은 무엇입니까?

SELECT c.date 
,  ( SELECT AVERAGE(m.value) 
      FROM measures as m 
      WHERE m.measured_on_dt <= c.date 
     ) as `average_to_date` 
FROM calendar c 
WHERE c.date between date1 AND date2 -- graph boundaries 
ORDER BY c.date ASC 

나는 이것을 읽는 데 며칠을 보냈다. 그리고 나는 좋은 해결책을 찾지 못했다. 어떤 사람들은 LIMIT가 부질의 (LIMIT는 MySQL의 현재 버젼에서 서브 쿼리에서 지원된다)에서 작동 할 것이라고 제안했지만, LIMIT는 집계로 들어가는 행이 아니라 반환 세트에 적용되므로 추가 할 때 아무런 차이가 없다.

FRIM 문 내부에서 상관 하위 쿼리를 사용할 수 없기 때문에 집계되지 않은 SELECT를 LIMIT로 작성한 다음 집계 할 수 없습니다. 그래서 이것은 (슬프게도) 작동하지 않습니다 : 나는 영리한 이렇게 할 경우 내가 완전히 하위 쿼리 접근 방식을 피하고 볼 필요가 생각하고

SELECT c.date 
,  SELECT AVERAGE(last_5.value) 
     FROM ( SELECT m.value 
       FROM measures as m 
       WHERE m.measured_on_dt <= c.date 
       ORDER BY m.measured_on_dt DESC 
       LIMIT 5 
      ) as `last_5` 
FROM calendar c 
WHERE c.date between date1 AND date2 -- graph boundaries 
ORDER BY c.date ASC 

를 집계 한 후 사용자 변수와 함께/행 번호 기술을 결합 하지만 그 일을하는 동안 누군가가 더 나은 방법을 알고 있는지 물어볼 줄 알았습니까?

업데이트 : 좋아, 나는이 예제를 위해 단순화 한 솔루션을 가지고있다. 캘린더 날짜에서 측정 값을 거꾸로 번호 지정하기 위해 일부 사용자 변수 속임수에 의존합니다. 또한 하위 쿼리 대신 캘린더 테이블을 사용하여 교차 제품을 실행하지만 행 번호 지정 트릭을 실패하게하는 불행한 부작용이 있습니다 (사용자 변수는 클라이언트에 전송 될 때 평가됩니다. 행이 평가됩니다) 그래서이 문제를 해결하려면 쿼리를 한 단계 중첩시키고 결과를 순서대로 정렬 한 다음 해당 행 집합에 행 번호 지정 트릭을 적용해야합니다.

이 쿼리는 측정 값이있는 달력 날짜 만 반환하므로 전체 시간 표시 막대가 필요하면 달력을 선택하고이 결과 집합에 LEFT JOIN을 선택하면됩니다.

set @day = 0; 
set @num = 0; 
set @LIMIT = 5; 

SELECT date 
,  AVG(value) as recent_N_AVG 
FROM 
( SELECT * 
    ,  @num := if(@day = c.date, @num + 1, 1) as day_row_number 
    ,  @day := day as dummy 
    FROM 
    (SELECT c.full_date 
    ,  m.value 
    ,  m.measured_on_dt 
    FROM calendar c 
    JOIN measures as m 
    WHERE m.measured_on_dt <= c.full_date 
    AND  c.full_date BETWEEN date1 AND date2 
    ORDER BY c.full_date ASC, measured_on_dt DESC 
) as full_data 
) as numbered 
WHERE day_row_number <= @LIMIT 
GROUP BY date 

행 번호 트릭

는 더 복잡한 데이터에 일반화 될 수 있습니다 (내 조치까지 집계 필요 여러 차원에있다).

+0

솔루션 자체가 해결 되었습니까? 아니면 여전히 무언가에 집착하고 있습니까? 그렇다면 무엇입니까? 몇 가지 샘플 데이터를 제공하면 도움이 될 것입니다 ... – DRapp

+0

나는 그것을 해결했지만 해킹입니다. 일반적인 문제 여야합니다. 그래서 더 좋은 해결책이 있는지 궁금합니다. – Gruff

+0

각 그룹 후보별로 특정 번호를 원한다면 실제로 해킹 할 필요는 없습니다. SQL 변수는 해당 유형의 처리에 완벽합니다. – DRapp

답변

0

타임 라인 (1 개 값 매일)이 같은 첫 번째 시도 향상시킬 수있는 연속 인 경우 : 타임 라인이 거기에 구멍이

SELECT c.date, 
     (SELECT AVERAGE(m.value) 
     FROM measures as m 
     WHERE m.measured_on_dt 
        BETWEEN DATE_SUB(c.date, INTERVAL 5 day) AND c.date 
     ) as `average_to_date` 
FROM calendar c 
WHERE c.date between date1 AND date2 -- graph boundaries 
ORDER BY c.date ASC 

경우이 평균 미만 5 개 값을 초래할 것입니다.

+0

아니요, 유감스럽게도 측정 된 데이터는 확률 적이므로 작동하지 않습니다. – Gruff

+0

@Gruff 오, 당신의 새로운 정보에 대해 생각해 보겠습니다 ... – dgw

관련 문제