2013-05-03 2 views
4

다음 표에서 distinct를 사용하고 싶습니다. 그러나 'PlayerID'열에서만 사용하고 싶습니다.오라클에서만 하나의 열에 만 구별

MATCHID PLAYERID  TEAMID MATCHDATE STARTDATE 
---------- ---------- ---------- --------- --------- 
     20   5   2 14-JAN-12 01-JUN-11 
     20   5   4 14-JAN-12 01-JUN-10 
     20   7   4 14-JAN-12 01-JUN-11 
     20   7   2 14-JAN-12 01-JUN-10 
     20   10   4 14-JAN-12 01-JUN-11 
     20   11   2 14-JAN-12 01-JUN-10 
     20   13   2 14-JAN-12 01-JUN-11 
     20   16   4 14-JAN-12 01-JUN-10 
     20   17   4 14-JAN-12 01-JUN-10 
     20   18   4 14-JAN-12 01-JUN-10 
     20   19   2 14-JAN-12 01-JUN-11 

그리고이 각각 'PlayerID'가장 높은 'STARTDATE'가 표시되도록 내가 원하는 것입니다 다음 행은 무시 : 이것은 내가 지금 무엇을 가지고

MATCHID PLAYERID  TEAMID MATCHDATE STARTDATE 
---------- ---------- ---------- --------- --------- 
     20   5   2 14-JAN-12 01-JUN-11 
     20   7   4 14-JAN-12 01-JUN-11 
     20   10   4 14-JAN-12 01-JUN-11 
     20   11   2 14-JAN-12 01-JUN-10 
     20   13   2 14-JAN-12 01-JUN-11 
     20   16   4 14-JAN-12 01-JUN-10 
     20   17   4 14-JAN-12 01-JUN-10 
     20   18   4 14-JAN-12 01-JUN-10 
     20   19   2 14-JAN-12 01-JUN-11 

현재 SQL :

SELECT pi.MatchID, pi.PlayerID, t.TeamID, m.MatchDate, pf.StartDate 
FROM Plays_In pi, Match m, Plays_A pa, Team t, Plays_For pf, Made_Up_Of muo, Season s 
WHERE pi.MatchID = m.MatchID 
AND m.MatchID = pa.MatchID 
AND pa.TeamID = t.TeamID 
AND pf.PlayerID = pi.PlayerID 
AND pf.TeamID = t.TeamID 
AND muo.MatchID = pi.MatchID 
AND muo.SeasonID = s.SeasonID 
AND pi.MatchID = '&match_id' 
AND m.MatchDate >= pf.StartDate 
ORDER BY pi.MatchID ASC, pi.PlayerID ASC, pf.StartDate DESC; 

오라클 데이터베이스입니다.

미리 감사드립니다.

+0

SQL-92가 20 년 이상 전에 표준화되기 전에 필요한 쉼표로 구분 된 목록 항목이 아니라 명시적인 JOIN 표기법을 사용하십시오. –

+0

도 참조하십시오 http://stackoverflow.com/questions/10515391/oracle-equivalent-of-postgres-distinct-on – Vadzim

답변

8

몇 점 ...

  • 것은 당신이 행을 필터링에 Made_Up_OfSeason을 조인 사용하지 않는 한, 당신은이 테이블을 필요가 없습니다. 나는 그들을 여기두고 갔다. 필요할 경우 다시 추가 할 수 있습니다.

  • Mark Tickner는 ANSI JOIN 구문을 사용해야합니다. 그것에 대한 좋은 점은 (표준이 아닌) 결합 된 테이블과 결합 논리를 바로 놓는 것입니다. 일단 익숙해지면 더 좋아질 것이라고 생각합니다.

  • PlayerID에 대해 최대 pf.StartDate인데 이는 ROW_NUMBER() 분석 기능에 가장 적합합니다. PARTITION BY pi.PlayerID ORDER BY pf.StartDate DESC은 기본적으로 각 플레이어의 가장 최근 정렬 날짜가있는 행에 값 1을 할당합니다. 외부는 1 순위를 가진 행을 제외한 모든 행을 필터링합니다.

  • 당신은 또한 RANK()DENSE_RANK() 분석 기능 순위를 할당 할 수 있지만 플레이어가 가장 최근 날짜 모든 동점 날짜 평가됩니다 # 1 넥타이를 가지고있는 경우 해당 선수에 대한 여러 행을 얻을 것이다 . 이와 같이 플레이어 당 하나의 행만 필요로하는 상황에서는 대신 ROW_NUMBER()을 사용하십시오.

모두 함께 넣고 당신은 얻을이 :

SELECT MatchID, PlayerID, TeamID, MatchDte, StartDate FROM (
    SELECT 
    pi.MatchID, 
    pi.PlayerID, 
    t.TeamID, 
    m.MatchDate, 
    pf.StartDate, 
    ROW_NUMBER() OVER (PARTITION BY pi.PlayerID ORDER BY pf.StartDate DESC) AS StartDateRank 
    FROM Plays_In pi 
    INNER JOIN Match m ON pi.MatchID = m.MatchID 
    INNER JOIN Plays_A pa ON m.MatchID = pa.MatchID 
    INNER JOIN Team t ON pa.TeamID = t.TeamID 
    INNER JOIN Plays_For pf ON pf.PlayerID = pi.PlayerID AND pf.TeamID = t.TeamID 
    WHERE pi.MatchID = '&match_id' 
    AND m.MatchDate >= pf.StartDate 
) 
WHERE StartDateRank = 1 
ORDER BY MatchID, PlayerID 

마지막 요점 : 당신이 당신의 프런트 엔드로 PHP를 사용하고있을 수 있습니다 것처럼 보이는 WHERE pi.MatchID = '&match_id'mysql 기능을 기반으로하는 것은 할 수있는 질문. 그렇다면 mysqli 또는 PDO을 찾아보십시오. SQL 인젝션을 방지 할 수 있습니다. mysql 함수 (공식적으로 사용되지 않음)는 그렇지 않습니다.


부록 : @AndriyM에 많은 감사와 ROW_NUMBER에 대한 자세한 정보를 표시합니다.

ROW_NUMBER을 사용하면 플레이어에 가장 최근 날짜가있는 행이 두 개 이상인 경우 행 중 하나만 ROW_NUMBER = 1으로 지정되며 그 행은 다소 임의적으로 선택됩니다. 다음은 플레이어의 가장 최근의 날짜가 2013년 5월 1일이며, 플레이어가이 날짜와 세 개의 행이 곳의 예는 다음과 같습니다

pi.MatchID pi.PlayerID pf.StartDate 
---------- ----------- ------------ 
     100   1000 05/01/2013 <-- could be ROW_NUMBER = 1 
     101   1000 04/29/2013 
     105   1000 05/01/2013 <-- could be ROW_NUMBER = 1 
     102   1000 05/01/2013 <-- could be ROW_NUMBER = 1 
     107   1000 04/18/2013 

참고 위의 행의 하나ROW_NUMBER = 1 할당되며, 그것들 중 하나 일 수 있습니다. 오라클이 결정할 것입니다.

이 불확실성이 문제가되면 명확한 승자를 얻기 위해 추가 열을 주문하십시오.

지금 가장 pf.StartDate의 넥타이가 있다면
-- replace `ROW_NUMBER...` in the query above with this: 
    ROW_NUMBER() OVER (
     PARTITION BY pi.PlayerID 
     ORDER BY pf.StartDate DESC, pi.MatchID DESC) AS StartDateRank 

, 오라클이 가장 높은과 행의 부분 집합 내에서 pi.MatchID 최고를 찾습니다 :이 예를 들어, 가장 높은 pi.MatchIDROW_NUMBER = 1이 "true"로 결정하는 데 사용됩니다 pf.StartDate. 결과적으로 한 행만이 조건을 만족합니다.

pi.MatchID pi.PlayerID pf.StartDate 
---------- ----------- ------------ 
     100   1000 05/01/2013 
     101   1000 04/29/2013 
     105   1000 05/01/2013 <-- is ROW_NUMBER = 1: highest MatchID for 
            -- most recent StartDate (5/1/2013) 
     102   1000 05/01/2013 
     107   1000 04/18/2013 <-- not considered: has the highest MatchID but isn't 
            -- in the subset with the most recent StartDate 
+0

고마워요, 시험해 볼 것입니다. 후에. PHP 부분에 대해서는 matchID에서 테스트 목적으로 결과를 좀 더 읽기 쉽게 제한하고 쿼리를 보낸 직후 Oracle에 입력됩니다. –

+0

'OVER' 절이 어떻게 작동하는지 간결한 설명을 좋아합니다. 한편으로는'RANK'와'DENSE_RANK'의 차이점과 다른 한편으로는'ROW_NUMBER'의 차이점이 있습니다. 후자에 관해서는, 나는 넥타이가있을 때'ROW_NUMBER'가 순위를 잘못 지정하도록 언급 할 가치가 있다고 생각하기 때문에, 예측 가능해야한다면'ORDER BY' 절은 모든 유대 관계를 해결할만큼 구체적으로 만들어야합니다. (내 말은, 내가 편집 한 것을 직접 생각해 봤지만, 당신의 설명이 정말 좋은 흐름을 망칠 까봐 두려웠다.) –

+0

Thanks @ AndriyM - 훌륭한 피드백과 훌륭한 점! 나는 tiebreaking에 관한 섹션을 추가했다. –

0

INTERSECT을 사용하고 을 GROUP BY?

2

rank() 함수를 사용할 수 있습니다.

SELECT * FROM (
    SELECT pi.MatchID, pi.PlayerID, t.TeamID, m.MatchDate, pf.StartDate, 
    rank() over (partition by pi.PlayerID order by m.MatchDate desc, rowid) as RNK 
    FROM Plays_In pi, Match m, Plays_A pa, Team t, Plays_For pf, Made_Up_Of muo, Season s 
    WHERE pi.MatchID = m.MatchID 
    AND m.MatchID = pa.MatchID 
    AND pa.TeamID = t.TeamID 
    AND pf.PlayerID = pi.PlayerID 
    AND pf.TeamID = t.TeamID 
    AND muo.MatchID = pi.MatchID 
    AND muo.SeasonID = s.SeasonID 
    AND pi.MatchID = '&match_id' 
    AND m.MatchDate >= pf.StartDate 
) WHERE RNK = 1 
ORDER BY MatchID ASC, PlayerID ASC, StartDate DESC; 
+0

고마워요, 나중에 집에있을 때 저에게 줄 것입니다. –

관련 문제