MySQL INNER JOIN은 두 번째 테이블에서 하나의 행만 선택합니다.


104

나는 users테이블과 테이블을 가지고 있으며 payments, 각 사용자에 대해 지불이있는 사용자는 payments테이블 에 여러 관련 지불이있을 수 있습니다 . 결제 한 모든 사용자를 선택하고 최근 결제 만 선택하고 싶습니다. 이 SQL을 시도하고 있지만 이전에 중첩 SQL 문을 시도한 적이 없으므로 내가 뭘 잘못하고 있는지 알고 싶습니다. 도움을 주셔서 감사합니다

SELECT u.* 
FROM users AS u
    INNER JOIN (
        SELECT p.*
        FROM payments AS p
        ORDER BY date DESC
        LIMIT 1
    )
    ON p.user_id = u.id
WHERE u.package = 1

답변:


148

에 대한 최신 날짜를 얻으려면 하위 쿼리가 필요합니다 user ID.

SELECT  a.*, c.*
FROM users a 
    INNER JOIN payments c
        ON a.id = c.user_ID
    INNER JOIN
    (
        SELECT user_ID, MAX(date) maxDate
        FROM payments
        GROUP BY user_ID
    ) b ON c.user_ID = b.user_ID AND
            c.date = b.maxDate
WHERE a.package = 1

1
@Fluffeh 당신은 아주 좋은 대답이 Part 1 - Joins and Unions있습니다. :) 북마크!
John Woo

1
감사합니다 메이트, 이런 종류의 상황을 위해 작성하고 올바른 SQL로 빠른 답변을 표시 한 다음 사람들 이 제안 된 코드를 이해할 수 있도록 해당 괴물에 대한 링크를 심층적으로 제안하십시오. 더 확장하기 위해 추가 할 계획입니다. 만약 당신이 좋아하면, 나는 ... 정말 코드에 대한 바이올린을 팝업해야에 참여에 오신 것을 환영합니다
Fluffeh

@JohnWoo 귀하의 답변에 감사드립니다. 완벽하게 작동했습니다. 그리고 Q & A에 대해 Fluffeh에게 감사드립니다. 조사해 보겠습니다!
Wasim

나는 단지 하나의 내부 조인을 사용하기 때문에 내 대답이 더 간단하고 빠르다고 생각합니다. 내가 틀렸나?
Mihai Matei 2012 년

2
내부 조인없이이 쿼리를 수행하는 방법이 있습니까? 테이블 c에서 최대 값을 반환하거나 일치하는 행이 없으면 null을 반환하고 싶습니다. JOIN을 LEFT JOIN으로 변경하면 분명히 작동하지 않습니다.
스콧

32
SELECT u.*, p.*
FROM users AS u
INNER JOIN payments AS p ON p.id = (
    SELECT id
    FROM payments AS p2
    WHERE p2.user_id = u.id
    ORDER BY date DESC
    LIMIT 1
)

이 솔루션은 동일한 사용자 및 날짜로 일부 결제가있을 때 올바르게 작동하기 때문에 허용 된 답변 보다 낫습니다 .


당신이 사용하는 좋은 접근 방식입니다. 하지만 하나의 제품에 대해 하나의 이미지를 가져 오는 것에 대해 질문이 있습니다. 한 제품에 많은 (4) 개의 이미지가 있지만 해당 제품에 대해 하나의 이미지 만 표시하고 싶습니다.
Ali Raza

사용하는 것이 매우 느릴 것이라고 생각하지 않습니까? 내부 조인에 대한 하위 쿼리의 모든 레코드를 처리하고 있기 때문입니다. 수락 된 답변은 사소한 조정 후에 가능한 최선의 답변이 될 수 있습니다.
Hamees A. Khan

@ HameesA.Khan, 쿼리 실행을 검사하지 않았습니다. 당신이 옳을 수도 있지만, 허용되는 솔루션은 너무 느릴 수있는 3 차원 조인을 만듭니다. 나는 조정이 사소 하지 않을 것입니다 (이것은 질문의 주제입니다).
Finesse

12
SELECT u.*, p.*, max(p.date)
FROM payments p
JOIN users u ON u.id=p.user_id AND u.package = 1
GROUP BY u.id
ORDER BY p.date DESC

sqlfiddle을 확인하십시오.


6
limit 1절은 OP가 원하는 것이 아닌 1 명의 사용자 만 반환합니다.
Fluffeh

6
@MateiMihai, 이것은 작동하지 않습니다. 쿼리는 최대 날짜가있는 전체 행이 아닌 최대 날짜 만 제공합니다. fiddle에서 볼 수 있습니다. datecolumn is different from max(p.date). payments테이블 에 더 많은 열을 추가하면 (예 cost
:)

3
   SELECT u.* 
        FROM users AS u
        INNER JOIN (
            SELECT p.*,
             @num := if(@id = user_id, @num + 1, 1) as row_number,
             @id := user_id as tmp
            FROM payments AS p,
                 (SELECT @num := 0) x,
                 (SELECT @id := 0) y
            ORDER BY p.user_id ASC, date DESC)
        ON (p.user_id = u.id) and (p.row_number=1)
        WHERE u.package = 1

2

쿼리에 두 가지 문제가 있습니다.

  1. 모든 테이블과 하위 쿼리에는 이름이 필요하므로 하위 쿼리의 이름을 지정해야합니다 INNER JOIN (SELECT ...) AS p ON ....
  2. 가지고있는 하위 쿼리는 행 기간을 하나만 반환하지만 실제로 는 각 사용자에 대해 하나의 행 원합니다 . 이를 위해서는 최대 날짜를 얻기 위해 하나의 쿼리가 필요하고 전체 행을 얻기 위해 다시 자체 조인해야합니다.

에 대한 관계가 없다고 가정하면 다음을 payments.date시도하십시오.

    SELECT u.*, p.* 
    FROM (
        SELECT MAX(p.date) AS date, p.user_id 
        FROM payments AS p
        GROUP BY p.user_id
    ) AS latestP
    INNER JOIN users AS u ON latestP.user_id = u.id
    INNER JOIN payments AS p ON p.user_id = u.id AND p.date = latestP.date
    WHERE u.package = 1

당신이 사용하는 좋은 접근 방식입니다. 하지만 하나의 제품에 대해 하나의 이미지를 가져 오는 것에 대해 질문이 있습니다. 한 제품에 많은 (4) 개의 이미지가 있지만 해당 제품에 대해 하나의 이미지 만 표시하고 싶습니다.
Ali Raza 19

제 경우에는 이것이 가장 빠르다는 것을 알았습니다. 내가 한 유일한 변경 사항 From payments as p Where p.user_id =@user_id은 쿼리가 전체 테이블에 대해 그룹화를 수행 할 때만 선택한 사용자 데이터를 필터링하기 위해 하위 쿼리에 where 절을 추가 한 것 입니다.
Vikash Rathee

2

@John Woo의 답변은 비슷한 문제를 해결하는 데 도움이되었습니다. 나는 올바른 순서를 설정하여 그의 대답을 개선했습니다. 이것은 나를 위해 일했습니다.

SELECT  a.*, c.*
FROM users a 
    INNER JOIN payments c
        ON a.id = c.user_ID
    INNER JOIN (
        SELECT user_ID, MAX(date) as maxDate FROM
        (
            SELECT user_ID, date
            FROM payments
            ORDER BY date DESC
        ) d
        GROUP BY user_ID
    ) b ON c.user_ID = b.user_ID AND
           c.date = b.maxDate
WHERE a.package = 1

그래도 이것이 얼마나 효율적인지 잘 모르겠습니다.


2
SELECT U.*, V.* FROM users AS U 
INNER JOIN (SELECT *
FROM payments
WHERE id IN (
SELECT MAX(id)
FROM payments
GROUP BY user_id
)) AS V ON U.id = V.user_id

이것은 그것을 작동시킬 것입니다


1

Matei Mihai는 간단하고 효율적인 솔루션을 제공했지만 MAX(date)SELECT 부분을 삽입 할 때까지 작동하지 않으므로이 쿼리는 다음과 같이됩니다.

SELECT u.*, p.*, max(date)
FROM payments p
JOIN users u ON u.id=p.user_id AND u.package = 1
GROUP BY u.id

그리고 order by는 그룹화에 차이가 없지만 그룹별로 제공되는 최종 결과를 정렬 할 수 있습니다. 나는 그것을 시도했고 그것은 나를 위해 일했습니다.


1

ORDER BY 절에 여러 열이 필요한 경우 @valex에서 직접 영감을 얻은 내 대답은 매우 유용합니다.

    SELECT u.* 
    FROM users AS u
    INNER JOIN (
        SELECT p.*,
         @num := if(@id = user_id, @num + 1, 1) as row_number,
         @id := user_id as tmp
        FROM (SELECT * FROM payments ORDER BY p.user_id ASC, date DESC) AS p,
             (SELECT @num := 0) x,
             (SELECT @id := 0) y
        )
    ON (p.user_id = u.id) and (p.row_number=1)
    WHERE u.package = 1

1

이것을 시도 할 수 있습니다.

SELECT u.*, p.*
FROM users AS u LEFT JOIN (
    SELECT *, ROW_NUMBER() OVER(PARTITION BY userid ORDER BY [Date] DESC) AS RowNo
    FROM payments  
) AS p ON u.userid = p.userid AND p.RowNo=1

1
이 코드 스 니펫은 질문을 해결할 수 있지만 설명을 포함하면 게시물의 품질을 개선하는 데 실제로 도움이됩니다. 앞으로 독자를위한 질문에 답하고 있으며, 해당 사용자는 코드 제안 이유를 모를 수 있습니다.
Alessio
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.