2012-01-10 1 views
1

다음 표 A & 표 B (여기서 A는 B와 1 대 다수); A의 각 레코드에 대해 A. 에 대해 각 그룹에 대해 B의 해당 최대 레코드를 선택해야합니다. 즉 그룹화는 last_updated_time을 기준으로 수행됩니다.여기에서 max의 뚜렷 함을 선택하는 방법

SELECT taba.ws_name, tabb.b2a, max(tabb.last_update_time) 
FROM TabA taba, TabB tabb 
where taba.name = 'xyz' 
and taba.id = tabb.b2a 
group by taba.ws_name, tabb.b2a 

잘 작동합니다.

마지막 트랜잭션뿐만 아니라 "상태"를 선택해야 할 때 문제가 발생합니다. 상태가 실패하거나 성공할 수 있기 때문에 중복 선택이 발생합니다.

내 요구 사항은 과거의 어떤 "ws_name는"여러 실패의 기록뿐만 아니라 성공을 가지고 그래서

(나뿐만 아니라 상태를 표시해야하지만)에 관계없이 그 상태의 최대 레코드를 선택하는 것입니다 따라서 MAX updated_time은 두 그룹 ("실패"& "성공")에 대해 선택됩니다.

다음은 내가 시도한 쿼리이며 상태로 인해 선택된 복제본을 제거하는 방법에 대한 단서가 없습니다.

SELECT taba.ws_name, tabb.b2a, **tabb.status**, max(tabb.last_update_time) 
FROM TabA taba, TabB tabb 
where taba.name = 'xyz' 
and taba.id = tabb.b2a 
group by taba.ws_name, tabb.b2a, **tabb.status** 
+0

내가 직장에서 집에 돌아 왔을 때 내 SQL 뇌가 꺼졌지만 tabb.status별로 그룹화하지 않고 오류가 발생했습니다. –

+0

@JoachimIsaksson은 서버 유형에 따라 다릅니다. 포스트그레스와 같은 "엄격한"서버는 폭발 할 것입니다. mysql과 같이 "Lax"서버는 그렇지 않습니다. mysql의 경우 각 그룹에 대해 처음 발견 된 행을 반환합니다. – Bohemian

답변

0

보통, 당신은 다음, 최대 값을 선택하여 원하는 실제 값을 얻기 위해이 결과에 가입해야합니다. 예를 들어

는 :

SELECT  InnerQuery.*, 
      TabB.Status 

FROM  
      (SELECT  A.ws_name, 
         B.b2a, 
         max(B.last_update_time) AS MaxUpdatedTime 

      FROM  TabA A 
      INNER JOIN TabB B ON (A.id = B.b2a) 

      GROUP BY A.ws_name, 
           B.b2a) AS InnerQuery 
INNER JOIN 
      TabB ON (InnerQuery.b2a = TabB.b2A AND TabB.last_update_time = InnerQuery.MaxUpdatedTime) 

InnerQuery는 상태가없는 것을 제외하고 당신에게 당신이 원하는 모든 행을 제공합니다. 따라서 B에 다시 결합하여 일치하는 행의 상태를 가져옵니다.

즉, B의 모든 행을 가져 와서 B에 다시 결합하여 고유하게 식별 된 행의 상태 값을 가져옵니다. 왜냐하면 말하자면 상태를 소개하면 다른 수준의 그룹화가되기 때문입니다.

+0

덕분에, 'MaxUpdatedTime'이 몇 번에 대해 동일한 값을 가지므로 최대 시간을 기준으로 여기에 중복 값을 반환하기 때문에 첫 번째 선택에서 '고유'를 추가해야했습니다. – sid

0

당신은 중첩 된 SELECT이 필요합니다 :

SELECT 
    X.*, B.status 
FROM 
    (SELECT 
     taba.ws_name, 
     tabb.b2a, 
     max(tabb.last_update_time) AS maxtime 
    FROM 
     TabA taba, 
     TabB tabb 
    where 
     taba.name = 'xyz' and taba.id = tabb.b2a 
    group by 
     taba.ws_name, 
     tabb.b2a) X, 
    tabb B 
WHERE 
    X.b2a = B.b2a AND X.maxtime = B.last_update_time 

나는 또한 조인 절을 사용합니다. 이것은 테이블을 결합하는 '현대적인'방법입니다. TABB에 해당하는 레코드가없는 경우

SELECT 
    X.*, Y.status 
FROM 
    (SELECT 
      A.ws_name, 
      B.b2a, 
      max(B.last_update_time) AS maxtime 
     FROM 
      TabA A 
      INNER JOIN TabB B 
       ON A.id = B.b2a 
     WHERE 
      A.name = 'xyz' 
     GROUP BY 
      A.ws_name, 
      B.b2a) X, 
    INNER JOIN TabB Y 
     ON X.b2a = Y.b2a AND X.maxtime = Y.last_update_time 

난 당신이들 "LEFT 가입"에 의해 "내부 조인"의 교체는, 당신은 또한 타바의 레코드에 대한 결과를 얻을 수 있습니다.

0

사실 CTE를 사용할 수 있습니다.이 경우에는이 하위 쿼리를 사용하여 동일한 결과가 나오지만, 차이점은이 코드가 읽기 쉽다는 것입니다.

첫 번째 블록 (WITH)은 쿼리를 실행하여 최대 값과 해당 ID를 가져 와서 결과를 "임시 테이블"에 저장합니다.

그런 다음 두 번째 쿼리에서 CTE 쿼리 (첫 번째 쿼리)의 결과에서 얻은 최대 값을 사용하고 원본 쿼리의 결과를 제한하는 데 사용합니다.

WITH TabB_CTE(b2a, last_update_time) as 
(
    Select 
     b2a, max(last_update_time) As last_update_time 
    From 
     TabB 
    Group By b2a 
) 

SELECT 
    taba.ws_name, tabb.b2a, tabb.status, tabb.last_update_time 
FROM 
    TabA taba Join TabB tabb 
     On taba.id = tabb.b2a 
    Join TabB_CTE tabc 
     On tabc.b2a = tabb.b2a 
     And tabc.last_update_time = tabb.last_update_time 
where taba.name = 'xyz'