복붙노트

[SQL] 어떻게 SQL의 다른 열을 기준으로 DISTINCT MAX (열 값)와 행을 선택할 수 있습니까?

SQL

어떻게 SQL의 다른 열을 기준으로 DISTINCT MAX (열 값)와 행을 선택할 수 있습니까?

내 표는 다음과 같습니다

id  home  datetime     player   resource
---|-----|------------|--------|---------
1  | 10  | 04/03/2009 | john   | 399 
2  | 11  | 04/03/2009 | juliet | 244
5  | 12  | 04/03/2009 | borat  | 555
3  | 10  | 03/03/2009 | john   | 300
4  | 11  | 03/03/2009 | juliet | 200
6  | 12  | 03/03/2009 | borat  | 500
7  | 13  | 24/12/2008 | borat  | 600
8  | 13  | 01/01/2009 | borat  | 700

나는 날짜의 최대 값을 잡고 각각 별개의 가정을 선택해야합니다.

것입니다 결과 :

id  home  datetime     player   resource 
---|-----|------------|--------|---------
1  | 10  | 04/03/2009 | john   | 399
2  | 11  | 04/03/2009 | juliet | 244
5  | 12  | 04/03/2009 | borat  | 555
8  | 13  | 01/01/2009 | borat  | 700

나는 시도했다 :

-- 1 ..by the MySQL manual: 

SELECT DISTINCT
  home,
  id,
  datetime AS dt,
  player,
  resource
FROM topten t1
WHERE datetime = (SELECT
  MAX(t2.datetime)
FROM topten t2
GROUP BY home)
GROUP BY datetime
ORDER BY datetime DESC

작동하지 않습니다. 데이터베이스 (187)를 보유하고 있지만, 결과 세트 (130 개)의 행을 갖는다. 결과는 가정의 일부 중복이 포함되어 있습니다.

-- 2 ..join

SELECT
  s1.id,
  s1.home,
  s1.datetime,
  s1.player,
  s1.resource
FROM topten s1
JOIN (SELECT
  id,
  MAX(datetime) AS dt
FROM topten
GROUP BY id) AS s2
  ON s1.id = s2.id
ORDER BY datetime 

아니. 모든 레코드를 제공합니다.

-- 3 ..something exotic: 

다양한 결과.

해결법

  1. ==============================

    1.당신은 너무 가까이! 당신이해야 할 일은 다음, 가정과의 최대 날짜 시간을 모두 선택 두 필드에 topten 테이블로 다시 조인 :

    당신은 너무 가까이! 당신이해야 할 일은 다음, 가정과의 최대 날짜 시간을 모두 선택 두 필드에 topten 테이블로 다시 조인 :

    SELECT tt.*
    FROM topten tt
    INNER JOIN
        (SELECT home, MAX(datetime) AS MaxDateTime
        FROM topten
        GROUP BY home) groupedtt 
    ON tt.home = groupedtt.home 
    AND tt.datetime = groupedtt.MaxDateTime
    
  2. ==============================

    2.내부 쿼리없이 GROUP BY없이 가장 빠른 MySQL의 솔루션 :

    내부 쿼리없이 GROUP BY없이 가장 빠른 MySQL의 솔루션 :

    SELECT m.*                    -- get the row that contains the max value
    FROM topten m                 -- "m" from "max"
        LEFT JOIN topten b        -- "b" from "bigger"
            ON m.home = b.home    -- match "max" row with "bigger" row by `home`
            AND m.datetime < b.datetime           -- want "bigger" than "max"
    WHERE b.datetime IS NULL      -- keep only if there is no bigger than max
    

    설명:

    자체가 집에 열을 사용하여 테이블에 가입하세요. LEFT의 사용 보장하지만 모든 테이블 m에서 행 결과 세트에 나타 가입. 표 B에 일치하지 않는 사람은 B의 컬럼에 대해 널 (NULL)이있을 것이다.

    조인의 다른 조건은 m 행의 행보다 날짜 열상에서 큰 값이 B의 행과 일치하도록 요청한다.

    질문에 게시 된 데이터를 사용하여, 왼쪽은 가입이 쌍을 생성합니다 :

    +------------------------------------------+--------------------------------+
    |              the row from `m`            |    the matching row from `b`   |
    |------------------------------------------|--------------------------------|
    | id  home  datetime     player   resource | id    home   datetime      ... |
    |----|-----|------------|--------|---------|------|------|------------|-----|
    | 1  | 10  | 04/03/2009 | john   | 399     | NULL | NULL | NULL       | ... | *
    | 2  | 11  | 04/03/2009 | juliet | 244     | NULL | NULL | NULL       | ... | *
    | 5  | 12  | 04/03/2009 | borat  | 555     | NULL | NULL | NULL       | ... | *
    | 3  | 10  | 03/03/2009 | john   | 300     | 1    | 10   | 04/03/2009 | ... |
    | 4  | 11  | 03/03/2009 | juliet | 200     | 2    | 11   | 04/03/2009 | ... |
    | 6  | 12  | 03/03/2009 | borat  | 500     | 5    | 12   | 04/03/2009 | ... |
    | 7  | 13  | 24/12/2008 | borat  | 600     | 8    | 13   | 01/01/2009 | ... |
    | 8  | 13  | 01/01/2009 | borat  | 700     | NULL | NULL | NULL       | ... | *
    +------------------------------------------+--------------------------------+
    

    마지막으로, 절 (B)의 열에서의 널 (NULL) (그들 위의 테이블에서 *로 표시된다)가 단지 한 쌍을 유지하는 곳; 인해에서 두 번째 조건이 수단은, 절 조인 m에서 선택된 행 날짜 열에서 가장 큰 값을 갖는다.

    은 SQL 안티 패턴을 읽어 다른 SQL 팁에 대한 데이터베이스 프로그래밍 책의 함정을 피하는.

  3. ==============================

    3.여기에 T-SQL 버전을 간다 :

    여기에 T-SQL 버전을 간다 :

    -- Test data
    DECLARE @TestTable TABLE (id INT, home INT, date DATETIME, 
      player VARCHAR(20), resource INT)
    INSERT INTO @TestTable
    SELECT 1, 10, '2009-03-04', 'john', 399 UNION
    SELECT 2, 11, '2009-03-04', 'juliet', 244 UNION
    SELECT 5, 12, '2009-03-04', 'borat', 555 UNION
    SELECT 3, 10, '2009-03-03', 'john', 300 UNION
    SELECT 4, 11, '2009-03-03', 'juliet', 200 UNION
    SELECT 6, 12, '2009-03-03', 'borat', 500 UNION
    SELECT 7, 13, '2008-12-24', 'borat', 600 UNION
    SELECT 8, 13, '2009-01-01', 'borat', 700
    
    -- Answer
    SELECT id, home, date, player, resource 
    FROM (SELECT id, home, date, player, resource, 
        RANK() OVER (PARTITION BY home ORDER BY date DESC) N
        FROM @TestTable
    )M WHERE N = 1
    
    -- and if you really want only home with max date
    SELECT T.id, T.home, T.date, T.player, T.resource 
        FROM @TestTable T
    INNER JOIN 
    (   SELECT TI.id, TI.home, TI.date, 
            RANK() OVER (PARTITION BY TI.home ORDER BY TI.date) N
        FROM @TestTable TI
        WHERE TI.date IN (SELECT MAX(TM.date) FROM @TestTable TM)
    )TJ ON TJ.N = 1 AND T.id = TJ.id
    

    편집하다 불행하게도, MySQL은 더 RANK () OVER 기능이 없습니다. 그러나 그것은 (일명 순위) Emulation 소프트웨어 분석의 MySQL과 기능을 참조 에뮬레이트 할 수 있습니다. 이 그래서 MySQL 버전입니다 :

    SELECT id, home, date, player, resource 
    FROM TestTable AS t1 
    WHERE 
        (SELECT COUNT(*) 
                FROM TestTable AS t2 
                WHERE t2.home = t1.home AND t2.date > t1.date
        ) = 0
    
  4. ==============================

    4.당신이 동일한 DATETIME의 각 가정을위한 두 개 이상의 행이있을 경우에도이 작동합니다 :

    당신이 동일한 DATETIME의 각 가정을위한 두 개 이상의 행이있을 경우에도이 작동합니다 :

    SELECT id, home, datetime, player, resource
    FROM   (
           SELECT (
                  SELECT  id
                  FROM    topten ti
                  WHERE   ti.home = t1.home
                  ORDER BY
                          ti.datetime DESC
                  LIMIT 1
                  ) lid
           FROM   (
                  SELECT  DISTINCT home
                  FROM    topten
                  ) t1
           ) ro, topten t2
    WHERE  t2.id = ro.lid
    
  5. ==============================

    5.나는이 당신에게 원하는 결과를 줄 것이라고 생각 :

    나는이 당신에게 원하는 결과를 줄 것이라고 생각 :

    SELECT   home, MAX(datetime)
    FROM     my_table
    GROUP BY home
    

    하지만 당신은뿐만 아니라 다른 열을 필요로하는 경우, 단지 원래 테이블과 조인하게 (마이클 라 Voie 응답을 확인)

    친애하는.

  6. ==============================

    6.명 (코멘트 기간이 1.5 년 범위)이 thread로 계속 실행하는 것 때문에이 훨씬 더 간단이되지 않습니다 :

    명 (코멘트 기간이 1.5 년 범위)이 thread로 계속 실행하는 것 때문에이 훨씬 더 간단이되지 않습니다 :

    (날짜 DESC BY topten ORDER SELECT * FROM) SELECT * FROM 홈페이지 TMP GROUP

    없음 집계 함수가 필요하지 ...

    건배.

  7. ==============================

    7.당신은이 일을 시도 할 수와 큰 테이블 쿼리 성능을 위해 더 좋을 것이다. 더 이상이 개 각 가정을위한 기록과 날짜가 다를 때 그것은 작동하지 않습니다. 더 나은 일반적으로 MySQL의 쿼리는 위의 마이클 라 Voie에서 하나입니다.

    당신은이 일을 시도 할 수와 큰 테이블 쿼리 성능을 위해 더 좋을 것이다. 더 이상이 개 각 가정을위한 기록과 날짜가 다를 때 그것은 작동하지 않습니다. 더 나은 일반적으로 MySQL의 쿼리는 위의 마이클 라 Voie에서 하나입니다.

    SELECT t1.id, t1.home, t1.date, t1.player, t1.resource
    FROM   t_scores_1 t1 
    INNER JOIN t_scores_1 t2
       ON t1.home = t2.home
    WHERE t1.date > t2.date
    

    또는 포스트 그레스 또는 그 DBS의 경우 분석 기능을 시도 제공하는

    SELECT t.* FROM 
    (SELECT t1.id, t1.home, t1.date, t1.player, t1.resource
      , row_number() over (partition by t1.home order by t1.date desc) rw
     FROM   topten t1 
     INNER JOIN topten t2
       ON t1.home = t2.home
     WHERE t1.date > t2.date 
    ) t
    WHERE t.rw = 1
    
  8. ==============================

    8.이것은 오라클에서 작동합니다 :

    이것은 오라클에서 작동합니다 :

    with table_max as(
      select id
           , home
           , datetime
           , player
           , resource
           , max(home) over (partition by home) maxhome
        from table  
    )
    select id
         , home
         , datetime
         , player
         , resource
      from table_max
     where home = maxhome
    
  9. ==============================

    9.

    SELECT  tt.*
    FROM    TestTable tt 
    INNER JOIN 
            (
            SELECT  coord, MAX(datetime) AS MaxDateTime 
            FROM    rapsa 
            GROUP BY
                    krd 
            ) groupedtt
    ON      tt.coord = groupedtt.coord
            AND tt.datetime = groupedtt.MaxDateTime
    
  10. ==============================

    10.SQL Server에 대한이 시도 :

    SQL Server에 대한이 시도 :

    WITH cte AS (
       SELECT home, MAX(year) AS year FROM Table1 GROUP BY home
    )
    SELECT * FROM Table1 a INNER JOIN cte ON a.home = cte.home AND a.year = cte.year
    
  11. ==============================

    11.

    SELECT c1, c2, c3, c4, c5 FROM table1 WHERE c3 = (select max(c3) from table)
    
    SELECT * FROM table1 WHERE c3 = (select max(c3) from table1)
    
  12. ==============================

    12.여기에 그룹의 MAX (날짜) 복제가 하나의 항목을 인쇄 MySQL 버전입니다.

    여기에 그룹의 MAX (날짜) 복제가 하나의 항목을 인쇄 MySQL 버전입니다.

    여기 http://www.sqlfiddle.com/#!2/0a4ae/1 테스트 할 수

    mysql> SELECT * from topten;
    +------+------+---------------------+--------+----------+
    | id   | home | datetime            | player | resource |
    +------+------+---------------------+--------+----------+
    |    1 |   10 | 2009-04-03 00:00:00 | john   |      399 |
    |    2 |   11 | 2009-04-03 00:00:00 | juliet |      244 |
    |    3 |   10 | 2009-03-03 00:00:00 | john   |      300 |
    |    4 |   11 | 2009-03-03 00:00:00 | juliet |      200 |
    |    5 |   12 | 2009-04-03 00:00:00 | borat  |      555 |
    |    6 |   12 | 2009-03-03 00:00:00 | borat  |      500 |
    |    7 |   13 | 2008-12-24 00:00:00 | borat  |      600 |
    |    8 |   13 | 2009-01-01 00:00:00 | borat  |      700 |
    |    9 |   10 | 2009-04-03 00:00:00 | borat  |      700 |
    |   10 |   11 | 2009-04-03 00:00:00 | borat  |      700 |
    |   12 |   12 | 2009-04-03 00:00:00 | borat  |      700 |
    +------+------+---------------------+--------+----------+
    
    SELECT *
    FROM (
        SELECT ord.*,
            IF (@prev_home = ord.home, 0, 1) AS is_first_appear,
            @prev_home := ord.home
        FROM (
            SELECT t1.id, t1.home, t1.player, t1.resource
            FROM topten t1
            INNER JOIN (
                SELECT home, MAX(datetime) AS mx_dt
                FROM topten
                GROUP BY home
              ) x ON t1.home = x.home AND t1.datetime = x.mx_dt
            ORDER BY home
        ) ord, (SELECT @prev_home := 0, @seq := 0) init
    ) y
    WHERE is_first_appear = 1;
    +------+------+--------+----------+-----------------+------------------------+
    | id   | home | player | resource | is_first_appear | @prev_home := ord.home |
    +------+------+--------+----------+-----------------+------------------------+
    |    9 |   10 | borat  |      700 |               1 |                     10 |
    |   10 |   11 | borat  |      700 |               1 |                     11 |
    |   12 |   12 | borat  |      700 |               1 |                     12 |
    |    8 |   13 | borat  |      700 |               1 |                     13 |
    +------+------+--------+----------+-----------------+------------------------+
    4 rows in set (0.00 sec)
    
    SELECT tt.*
    FROM topten tt
    INNER JOIN
        (
        SELECT home, MAX(datetime) AS MaxDateTime
        FROM topten
        GROUP BY home
    ) groupedtt ON tt.home = groupedtt.home AND tt.datetime = groupedtt.MaxDateTime
    +------+------+---------------------+--------+----------+
    | id   | home | datetime            | player | resource |
    +------+------+---------------------+--------+----------+
    |    1 |   10 | 2009-04-03 00:00:00 | john   |      399 |
    |    2 |   11 | 2009-04-03 00:00:00 | juliet |      244 |
    |    5 |   12 | 2009-04-03 00:00:00 | borat  |      555 |
    |    8 |   13 | 2009-01-01 00:00:00 | borat  |      700 |
    |    9 |   10 | 2009-04-03 00:00:00 | borat  |      700 |
    |   10 |   11 | 2009-04-03 00:00:00 | borat  |      700 |
    |   12 |   12 | 2009-04-03 00:00:00 | borat  |      700 |
    +------+------+---------------------+--------+----------+
    7 rows in set (0.00 sec)
    
  13. ==============================

    13.기본적으로 순위 = 1로 가장 최근의 행을 필터링 한 후 그룹별로 각 행에 대한 순위를 계산하고 하위 쿼리를 사용하여 그룹별로 가장 최근의 행을 GT는 또 다른 방법

    기본적으로 순위 = 1로 가장 최근의 행을 필터링 한 후 그룹별로 각 행에 대한 순위를 계산하고 하위 쿼리를 사용하여 그룹별로 가장 최근의 행을 GT는 또 다른 방법

    select a.*
    from topten a
    where (
      select count(*)
      from topten b
      where a.home = b.home
      and a.`datetime` < b.`datetime`
    ) +1 = 1
    

    데모

    여기에 더 나은 이해를 위해 각 행에 대한 순위를 나타내는 시각적 데모는 없다

    쿼리보다도 실패하고 위의 상황에 1 개 이상의 행을 반환합니다. 이 상황을 은폐하기 위해 위의 상황에서 떨어지는 촬영해야하는 행을 결정하는 또 다른 기준 / 매개 변수 / 열 필요가있을 것입니다. 보면 샘플 데이터 나 자동 증가 설정해야 기본 키 열 ID가 가정 설정. 우리는 CASE 문의 도움 등으로 같은 쿼리를 조정하여 가장 최근의 행을 선택하는이 열을 사용할 수 있도록

    select a.*
    from topten a
    where (
      select count(*)
      from topten b
      where a.home = b.home
      and  case 
           when a.`datetime` = b.`datetime`
           then a.id < b.id
           else a.`datetime` < b.`datetime`
           end
    ) + 1 = 1
    

    데모

    위 쿼리는 같은 날짜 값 중 가장 높은 ID를 가진 행을 선택합니다

    각 행의 순위없는 시각적 데모

  14. ==============================

    14.이 시도

    이 시도

    select * from mytable a join
    (select home, max(datetime) datetime
    from mytable
    group by home) b
     on a.home = b.home and a.datetime = b.datetime
    

    문안 인사 케이

  15. ==============================

    15.왜 사용하지은 : SELECT 집, MAX (날짜 시간) AS MaxDateTime, 플레이어, 홈 BY topten 그룹에서 자원 내가 뭐 놓친 거 없니?

    왜 사용하지은 : SELECT 집, MAX (날짜 시간) AS MaxDateTime, 플레이어, 홈 BY topten 그룹에서 자원 내가 뭐 놓친 거 없니?

  16. ==============================

    16.이것은 당신이 필요로하는 쿼리입니다 :

    이것은 당신이 필요로하는 쿼리입니다 :

     SELECT b.id, a.home,b.[datetime],b.player,a.resource FROM
     (SELECT home,MAX(resource) AS resource FROM tbl_1 GROUP BY home) AS a
    
     LEFT JOIN
    
     (SELECT id,home,[datetime],player,resource FROM tbl_1) AS b
     ON  a.resource = b.resource WHERE a.home =b.home;
    
  17. ==============================

    17.@Michae는 대답은 대부분의 경우 잘 작동합니다 가능하지만 아래와 같이 하나 실패.

    @Michae는 대답은 대부분의 경우 잘 작동합니다 가능하지만 아래와 같이 하나 실패.

    경우에는 다음과 같이 쿼리에 고유 추가하는 것이 모두 행, 필요없는 별개의 HomeID을 반환합니다 HomeID 및 날짜 시간 같은 쿼리를 가진 2 개 행이 있다면.

    SELECT DISTINCT tt.home  , tt.MaxDateTime
    FROM topten tt
    INNER JOIN
        (SELECT home, MAX(datetime) AS MaxDateTime
        FROM topten
        GROUP BY home) groupedtt 
    ON tt.home = groupedtt.home 
    AND tt.datetime = groupedtt.MaxDateTime
    
  18. ==============================

    18.쿼리 아래의 희망은 원하는 출력을 줄 것이다 :

    쿼리 아래의 희망은 원하는 출력을 줄 것이다 :

    Select id, home,datetime,player,resource, row_number() over (Partition by home ORDER by datetime desc) as rownum from tablename where rownum=1
    
  19. from https://stackoverflow.com/questions/612231/how-can-i-select-rows-with-maxcolumn-value-distinct-by-another-column-in-sql by cc-by-sa and MIT license