복붙노트

[SQL] SQL은 조인 : 일대 다 관계의 마지막 기록을 선택

SQL

SQL은 조인 : 일대 다 관계의 마지막 기록을 선택

나는 고객의 테이블과 구매의 테이블이 있다고 가정. 각 구매 한 고객에 속한다. 나는 하나의 SELECT 문에서 최근 구매시 함께 모든 고객의 목록을 얻을 싶어요. 가장 좋은 방법은 무엇입니까? 인덱스 작성에 대한 어떤 조언을?

당신의 대답이 테이블 / 열 이름을 사용하십시오 :

그리고 더 복잡한 상황에서, 그것은 (성능 현명한) 고객 테이블에 마지막으로 구입을 바꾸어 데이터베이스를 비정규 화하는 것이 도움이 될 것입니다?

(구매) ID가 날짜별로 정렬이 보장되는 경우, 문이 LIMIT 1 같은 것을 사용하여 단순화 할 수 있습니까?

해결법

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

    1.이에 유래에 정기적으로 나타난 가장 큰-N 당 그룹 문제의 예입니다.

    이에 유래에 정기적으로 나타난 가장 큰-N 당 그룹 문제의 예입니다.

    여기에 내가 일반적으로 그것을 해결하는 것이 좋습니다 방법은 다음과 같습니다

    SELECT c.*, p1.*
    FROM customer c
    JOIN purchase p1 ON (c.id = p1.customer_id)
    LEFT OUTER JOIN purchase p2 ON (c.id = p2.customer_id AND 
        (p1.date < p2.date OR (p1.date = p2.date AND p1.id < p2.id)))
    WHERE p2.id IS NULL;
    

    설명 : 행 P1 주어는 동일한 고객과 나중에 (또는 관계의 경우, 나중에 ID에) 아무 행 (P2)가 없어야합니다. 우리가이 사실로 찾을 때, P1은 해당 고객에 대한 가장 최근의 구매입니다.

    인덱스에 관해서는, 나는 열 (CUSTOMER_ID, 날짜, ID)를 통해 구매에 복합 인덱스를 만들 것입니다. 즉 허락 외측 커버는 인덱스를 사용하여 수행 될 조인. 최적화 구현에 의존하기 때문에, 플랫폼에 테스트해야합니다. 최적화 계획을 분석하기 위해 RDBMS의 기능을 사용합니다. 예를 들면 MySQL을 설명한다.

    어떤 사람들은 대신 제가 위에서 보여 솔루션의 하위 쿼리를 사용하지만, 나는 내 솔루션이 해결의 관계에 더 쉽게하게 찾을 수 있습니다.

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

    2.또한 하위를 선택하여이 일을 시도 할 수

    또한 하위를 선택하여이 일을 시도 할 수

    SELECT  c.*, p.*
    FROM    customer c INNER JOIN
            (
                SELECT  customer_id,
                        MAX(date) MaxDate
                FROM    purchase
                GROUP BY customer_id
            ) MaxDates ON c.id = MaxDates.customer_id INNER JOIN
            purchase p ON   MaxDates.customer_id = p.customer_id
                        AND MaxDates.MaxDate = p.date
    

    선택은 모든 고객과 그들의 마지막 구입 일자에 가입해야합니다.

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

    3.당신은 데이터베이스를 지정하지 않았습니다. 그것이 하나를 사용하여 GROUP 것보다이 방법을 사용하는 것이 더 빠를 수 있습니다 분석 기능을 허용 한 경우 (확실히 빠른 오라클, 가장 가능성이 더 빨리 말 SQL 서버 버전에서, 다른 사람에 대해 알고하지 않습니다).

    당신은 데이터베이스를 지정하지 않았습니다. 그것이 하나를 사용하여 GROUP 것보다이 방법을 사용하는 것이 더 빠를 수 있습니다 분석 기능을 허용 한 경우 (확실히 빠른 오라클, 가장 가능성이 더 빨리 말 SQL 서버 버전에서, 다른 사람에 대해 알고하지 않습니다).

    SQL Server의 구문은 다음과 같습니다

    SELECT c.*, p.*
    FROM customer c INNER JOIN 
         (SELECT RANK() OVER (PARTITION BY customer_id ORDER BY date DESC) r, *
                 FROM purchase) p
    ON (c.id = p.customer_id)
    WHERE p.r = 1
    
  4. ==============================

    4.또 다른 방법은에서가 NOT 조건 EXISTS 사용하는 것입니다 당신 나중에 구매에 대한 테스트에 조인 조건 :

    또 다른 방법은에서가 NOT 조건 EXISTS 사용하는 것입니다 당신 나중에 구매에 대한 테스트에 조인 조건 :

    SELECT *
    FROM customer c
    LEFT JOIN purchase p ON (
           c.id = p.customer_id
       AND NOT EXISTS (
         SELECT 1 FROM purchase p1
         WHERE p1.customer_id = c.id
         AND p1.id > p.id
       )
    )
    
  5. ==============================

    5.나는 내 문제에 대한 해결책으로이 스레드를 발견했다.

    나는 내 문제에 대한 해결책으로이 스레드를 발견했다.

    내가 그들을 시도 때 성능이 낮았다. 벨로는 성능 향상을 위해 내 제안이다.

    With MaxDates as (
    SELECT  customer_id,
                    MAX(date) MaxDate
            FROM    purchase
            GROUP BY customer_id
    )
    
    SELECT  c.*, M.*
    FROM    customer c INNER JOIN
            MaxDates as M ON c.id = M.customer_id 
    

    이 도움이 될 것입니다 바랍니다.

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

    6.이 시도, 그것은 도움이 될 것입니다.

    이 시도, 그것은 도움이 될 것입니다.

    나는 내 프로젝트에서 이것을 사용하고 있습니다.

    SELECT 
    *
    FROM
    customer c
    OUTER APPLY(SELECT top 1 * FROM purchase pi 
    WHERE pi.customer_id = c.Id order by pi.Id desc) AS [LastPurchasePrice]
    
  7. ==============================

    7.당신의 PostgreSQL을 사용하는 경우 당신은 그룹의 첫 번째 행을 찾을 DISTINCT ON을 사용할 수 있습니다.

    당신의 PostgreSQL을 사용하는 경우 당신은 그룹의 첫 번째 행을 찾을 DISTINCT ON을 사용할 수 있습니다.

    SELECT customer.*, purchase.*
    FROM customer
    JOIN (
       SELECT DISTINCT ON (customer_id) *
       FROM purchase
       ORDER BY customer_id, date DESC
    ) purchase ON purchase.customer_id = customer.id
    

    PostgreSQL의 문서 - 고유에

    참고는 DISTINCT ON 필드 (들)이 있음 - 여기 CUSTOMER_ID - ORDER BY 절에서 가장 왼쪽 필드 (들)과 일치해야합니다.

    주의 : 이것은 표준이 아닌 절입니다.

  8. ==============================

    8.SQLite는에서 테스트 :

    SQLite는에서 테스트 :

    SELECT c.*, p.*, max(p.date)
    FROM customer c
    LEFT OUTER JOIN purchase p
    ON c.id = p.customer_id
    GROUP BY c.id
    

    최대 () 집계 함수는 최신 구매가 각 그룹에서 선택 (- 경우 일반적이다하지만 날짜 열이) (최대 최신 제공함으로써 형식으로되어 있다고 가정)되어 있는지 확인합니다. 같은 날짜에 구매를 처리하는 경우에 당신은 최대 (p.date, p.id)를 사용할 수 있습니다.

    인덱스의 측면에서, 내가 함께 구입에 인덱스를 사용합니다 (CUSTOMER_ID, 날짜, [당신은 당신의 선택에 반환 할 다른 구매 컬럼]).

    왼쪽 OUTER 확실히 구매를 적이없는 고객도 포함되어 있는지 확인합니다 (가입 INNER 반대) 가입.

  9. ==============================

    9.이것을 시도하십시오,

    이것을 시도하십시오,

    SELECT 
    c.Id,
    c.name,
    (SELECT pi.price FROM purchase pi WHERE pi.Id = MAX(p.Id)) AS [LastPurchasePrice]
    FROM customer c INNER JOIN purchase p 
    ON c.Id = p.customerId 
    GROUP BY c.Id,c.name;
    
  10. from https://stackoverflow.com/questions/2111384/sql-join-selecting-the-last-records-in-a-one-to-many-relationship by cc-by-sa and MIT license