복붙노트

[SQL] 다른 컬럼에서 순서에 따라 그룹에서 하나 개의 값을 선택

SQL

다른 컬럼에서 순서에 따라 그룹에서 하나 개의 값을 선택

나는 (가능 바이올린)이 테이블 탭이 있다고 가정합니다.

| g | a | b |     v |
---------------------
| 1 | 3 | 5 |   foo |
| 1 | 4 | 7 |   bar |
| 1 | 2 | 9 |   baz |
| 2 | 1 | 1 |   dog |
| 2 | 5 | 2 |   cat |
| 2 | 5 | 3 | horse |
| 2 | 3 | 8 |   pig |

나는 g으로 행을 그룹화하고있어, 각 그룹에 대해 나는 열 V에서 하나 개의 값을합니다. 그러나, 나는 어떤 값을 싶지 않아,하지만 난 최대 A를 행의 값을 원하고, 모든 이들로부터, 하나 최대의 b. 즉, 나의 ​​결과는해야한다

| 1 |   bar |
| 2 | horse |

나는 이것을 달성하기 위해 쿼리를 알고 :

SELECT grps.g,
(SELECT v FROM tab
 WHERE g = grps.g
 ORDER BY a DESC, b DESC
 LIMIT 1) AS r
FROM (SELECT DISTINCT g FROM tab) grps

하지만이 쿼리 오히려 추한 것이 좋습니다. 대부분은 진짜 성능 킬러 같은 느낌 종속 하위 쿼리를 사용하기 때문이다. 나는이 문제에 대한 쉬운 해결책이 있는지 궁금 그래서.

나는이 질문에 대한 기대 가능성이 가장 높은 대답은 이것에 대한 기능을 제공한다 MySQL의 (또는 MariaDB)에 대한에 추가 또는 패치 어떤 종류의 것입니다. 그러나 나는뿐만 아니라 다른 유용한 영감을 환영합니다. 종속 서브 쿼리없이 작동 뭐든지 대답 자격을 것입니다.

나는 그것을 사용하는 대부분의 경우에 여전히 유용 할 것으로 예상대로 솔루션은 단일 주문 컬럼에 대해 작동하는 경우, 즉 고양이와 말을 구분하지 수,뿐만 아니라 그 답을 제시 주시기 바랍니다. 예를 들어, 100 * A + B 여전히 단 하나의 표현을 사용하면서 두 열에서, 상기 데이터를 주문하는 것 방법이 될 것이다.

내가 마음에 몇 꽤 hackish 솔루션을 가지고 있고, 잠시 후에 추가 할 수도 있지만 내가 먼저보고 멋진 새로운 처음에 부어 여부를 확인할 수 있습니다.

그냥 그들을보고하여 다양한 답변을 비교하는 것은 매우 어렵습니다, 나는 그들에 대한 몇 가지 벤치 마크를 실행했습니다. 이것은 MySQL의 5.1을 사용하여, 내 자신의 바탕 화면에 실행되었습니다. 숫자는 하나 다른, 다른 시스템에 비교되지 않습니다. 성능이 응용 프로그램에 중요한 경우에 당신은 아마 당신의 실제 데이터와 자신의 시험을 수행해야한다. 새로운 답변이 올 때, 나는 내 스크립트에 추가 할 수 있으며 모든 시험을 다시 실행합니다.

그래서 내 자신의 솔루션은 지금까지 심지어 종속 하위 쿼리와 함께, 모든 나쁘지 않은 것 같다. 놀랍게도,뿐만 아니라 종속 하위 쿼리를 사용하고 난 따라서 같은, 수행 훨씬 더에 대한 간주 한 것이다 acatt에 의한 솔루션입니다. 아마 뭔가 MySQL의 최적화에 대처할 수 없습니다. RichardTheKiwi 제안 솔루션뿐만 아니라 좋은 전반적인 성능을 갖고있는 것 같아요. 다른 두 솔루션은 주로 데이터의 구조에 의존한다. 많은 그룹 작은 그룹으로, xdazz '접근 방식은 다른 모든 성능을 능가하는 반면 소수의 대형 그룹에 대한 민주당 원 수행 베스트 솔루션 (하지만 여전히 매우 좋지 않다).

해결법

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

    1.

    SELECT g, a, b, v
      FROM (
                SELECT *, 
                       @rn := IF(g = @g, @rn + 1, 1) rn, 
                       @g := g
                  FROM (select @g := null, @rn := 0) x, 
                       tab
              ORDER BY g, a desc, b desc, v
           ) X
     WHERE rn = 1;
    

    싱글 패스. 다른 모든 솔루션은 나에게 O (N ^ 2)를 찾습니다.

  2. ==============================

    2.이 방법은 하위 쿼리를 사용하지 않습니다.

    이 방법은 하위 쿼리를 사용하지 않습니다.

    SELECT t1.g, t1.v
    FROM tab t1
    LEFT JOIN tab t2 ON t1.g = t2.g AND (t1.a < t2.a OR (t1.a = t2.a AND t1.b < t2.b))
    WHERE t2.g IS NULL
    

    설명:

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

    3.대부분의 RDBMS는 특히이 문제에 적합한 구조를 가지고있다. MySQL은 그들 중 하나가 아닙니다.

    대부분의 RDBMS는 특히이 문제에 적합한 구조를 가지고있다. MySQL은 그들 중 하나가 아닙니다.

    세 가지 기본 접근 방식이 리드를.

    여러 개의 연속 서브 쿼리 ...

    SELECT
      yourTable.*
    FROM
      (SELECT g,    MAX(a) AS a FROM yourTable GROUP BY g   ) AS searchA
    INNER JOIN
      (SELECT g, a, MAX(b) AS b FROM yourTable GROUP BY g, a) AS searchB
        ON  searchA.g = searchB.g
        AND searchA.a = searchB.a
    INNER JOIN
      yourTable
        ON  yourTable.g = searchB.g
        AND yourTable.a = searchB.a
        AND yourTable.b = searchB.b
    

    MySQL은 제 2 서브 쿼리를 최적화하는 방법에 따라,이 또는 다른 옵션보다 더 확대됨에 될 수도 있고 그렇지 않을 수도 있습니다. 그것은, 그러나, 주어진 작업에 대한 가장 긴 (잠재적으로 최소 유지 보수) 코드입니다.

    세 개의 검색 필드에 지수를 가정하면, (g, A, B), I는 그룹 g의 큰 크기에 가장 수를 추정하는 것이다. 하지만 그 테스트해야합니다.

    g의 작은 그룹 크기, 난 @의 xdazz의 대답과 함께 갈 것입니다.

    편집하다

    브 루트 포스 방법도 있습니다.

    이것은 최선의 방법이 될 가능성이있다. 이 경우, 효과적으로 이러한 유형의 문제에 대처하기 위해 MySQL을의 최적화 능력의 condmenation입니다.

    즉 모든 엔진이 그것의 약점을 가지고있다. 나는 내가 RDBMS가 작동하고 내 선택을 할 수있는 방법을 이해하는 생각까지 그래서, 개인적으로, 나는 모든 것을 시도 :)

    편집하다

    예 ROW_NUMBER ()를 사용. (오라클, SQL 서버, PostgreSQL을, 등)

    SELECT
      *
    FROM
    (
      SELECT
        ROW_NUMBER() OVER (PARTITION BY g ORDER BY a DESC, b DESC) AS sequence_id,
        *
      FROM
        yourTable
    )
      AS data
    WHERE
      sequence_id = 1
    
  4. ==============================

    4.이것은 상관 쿼리를 사용하여 해결할 수 있습니다 :

    이것은 상관 쿼리를 사용하여 해결할 수 있습니다 :

    SELECT g, v
    FROM tab t
    WHERE NOT EXISTS (
        SELECT 1
        FROM tab
        WHERE g = t.g
            AND a > t.a
            OR (a = t.a AND b > t.b)
        )
    
  5. from https://stackoverflow.com/questions/12726549/select-one-value-from-a-group-based-on-order-from-other-columns by cc-by-sa and MIT license