source

MySQL "Group By" 및 "Order By"

lovecheck 2022. 10. 29. 10:06
반응형

MySQL "Group By" 및 "Order By"

메일 테이블에서 여러 행을 선택하여 보낸 사람별로 그룹화할 수 있도록 하고 싶습니다.내 쿼리는 다음과 같습니다.

SELECT 
    `timestamp`, `fromEmail`, `subject`
FROM `incomingEmails` 
GROUP BY LOWER(`fromEmail`) 
ORDER BY `timestamp` DESC

쿼리는 거의 원하는 대로 동작합니다.이 쿼리는 이메일로 그룹화된 레코드를 선택합니다.문제는 제목과 타임스탬프가 특정 전자 메일주소의 최신 레코드에 대응하고 있지 않다는 것입니다.

예를 들어 다음과 같이 반환될 수 있습니다.

fromEmail: john@example.com, subject: hello
fromEmail: mark@example.com, subject: welcome

데이터베이스 내의 레코드가 다음과 같은 경우:

fromEmail: john@example.com, subject: hello
fromEmail: john@example.com, subject: programming question
fromEmail: mark@example.com, subject: welcome

"프로그래밍 질문" 제목이 최신인 경우 MySQL이 이메일을 그룹화할 때 해당 레코드를 선택하도록 하려면 어떻게 해야 합니까?

간단한 해결책은 먼저 ORDER 을 사용하여 쿼리를 하위 선택 항목으로 묶고 나중에 GROUP BY를 적용하는 것입니다.

SELECT * FROM ( 
    SELECT `timestamp`, `fromEmail`, `subject`
    FROM `incomingEmails` 
    ORDER BY `timestamp` DESC
) AS tmp_table GROUP BY LOWER(`fromEmail`)

이건 조인을 사용하는 것과 비슷하지만 훨씬 더 멋져 보입니다.

GROUP BY 절과 함께 SELECT에서 비집약 열을 사용하는 것은 비표준입니다.MySQL은 일반적으로 처음 찾은 행의 값을 반환하고 나머지는 무시합니다.ORDER BY 절은 폐기된 열 값이 아닌 반환된 열 값에만 적용됩니다.

중요 업데이트 집계되지 않은 열을 선택하는 것은 실제로 작동했지만 신뢰해서는 안 됩니다.MySQL 설명서에 따르면 GROUP BY에서 이름이 지정되지 않은 각 비집약 열의 모든 값이 각 그룹에 대해 동일한 경우 주로 유용합니다.서버는 각 그룹에서 임의의 을 자유롭게 선택할 수 있기 때문에 같은 값이 아닌선택한 값은 불확실합니다.

5.7.5 현재 디폴트로는 OLY_FULL_GROUP_BY만 이니블로 되어 있기 때문에 비집약 컬럼은 쿼리 오류를 일으킵니다(ER_WRONG_FIELD_).WITH_GROUP)

아래 @mikep가 지적한 바와 같이 솔루션은 5.7 이상의 ANY_VALUE()사용하는 것입니다.

http://www.cafewebmaster.com/mysql-order-sort-group https://dev.mysql.com/doc/refman/5.6/en/group-by-handling.html https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html 를 참조해 주세요.https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_any-value

이미 회신에서 지적된 바와 같이 GROUP BY가 창에서 임의로 레코드를 선택하기 때문에 현재 답변이 잘못되었습니다.

5.을 MySQL 5.6과 함께 .ONLY_FULL_GROUP_BY올바른 (실제적인) 쿼리는 다음과 같습니다.

SELECT incomingEmails.*
  FROM (
    SELECT fromEmail, MAX(timestamp) `timestamp`
    FROM incomingEmails
    GROUP BY fromEmail
  ) filtered_incomingEmails
  JOIN incomingEmails USING (fromEmail, timestamp)
GROUP BY fromEmail, timestamp

쿼리를 효율적으로 실행하려면 적절한 인덱스가 필요합니다.

심플화를 위해서, 이 기능을 삭제했습니다.LOWER()대부분의 경우 사용되지 않습니다.

다음은 한 가지 접근법입니다.

SELECT cur.textID, cur.fromEmail, cur.subject, 
     cur.timestamp, cur.read
FROM incomingEmails cur
LEFT JOIN incomingEmails next
    on cur.fromEmail = next.fromEmail
    and cur.timestamp < next.timestamp
WHERE next.timestamp is null
and cur.toUserID = '$userID' 
ORDER BY LOWER(cur.fromEmail)

기본적으로 테이블 자체를 결합하여 이후의 행을 검색합니다.where 절에는 이후의 행을 사용할 수 없음을 나타냅니다.마지막 행만 표시됩니다.

타임스탬프가 같은 이메일이 여러 개일 경우 이 쿼리를 조정해야 합니다.이메일 테이블에 증분 ID 열이 있는 경우 다음과 같이 JOIN을 변경합니다.

LEFT JOIN incomingEmails next
    on cur.fromEmail = next.fromEmail
    and cur.id < next.id

GROUP BY는 주문 후 다음과 같이 GROUP BY로 쿼리를 정리하여 수행합니다.

SELECT t.* FROM (SELECT * FROM table ORDER BY time DESC) t GROUP BY t.from

SQL 표준에 따라 선택 목록에서 비집약 열을 사용할 수 없습니다.MySQL은 이러한 사용(사용되는 ULESS ONLY_FULL_GROUP_BY 모드)을 허용하지만 결과를 예측할 수 없습니다.

유일한_풀_그룹_바이

먼저 Email, MIN(읽기)에서 선택한 후 두 번째 쿼리(또는 하위 쿼리) - Subquery를 선택해야 합니다.

표시된 것보다 더 복잡한 쿼리에 대해 두 가지 접근법에 모두 어려움을 겪었습니다. 왜냐하면 서브쿼리 접근법은 어떤 인덱스를 넣어도 끔찍할 정도로 불충분하고, Hibernate를 통해 외부 셀프 조인을 얻을 수 없었기 때문입니다.

이를 위한 최선의(그리고 가장 쉬운) 방법은 필요한 필드의 연계를 포함하도록 구성된 것을 기준으로 그룹화한 후 SELECT 절의 식을 사용하여 필드를 추출하는 것입니다.MAX()를 실행할 필요가 있는 경우 MAX()를 덮어쓰는 필드가 항상 연결된 엔티티의 최상위 끝에 있는지 확인하십시오.

이를 이해하는 열쇠는 이러한 다른 필드가 Max()를 충족하는 엔티티에 대해 불변할 경우에만 쿼리가 의미가 있으므로 정렬 측면에서 다른 연결 부분은 무시해도 된다는 것입니다.이 링크의 맨 아래에 이 작업을 수행하는 방법에 대해 설명합니다.http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-columns.html

필드 연결을 미리 계산하기 위해 am insert/update 이벤트(트리거 등)를 가져올 수 있는 경우 인덱스를 작성할 수 있습니다.그러면 그룹 by가 실제로 MAX()로 하고 싶은 필드 위에 있는 것처럼 쿼리가 빨라집니다.이 명령을 사용하여 최대 여러 필드를 가져올 수도 있습니다.중첩된 집합으로 표현된 다차원 트리에 대한 쿼리를 수행할 때 사용합니다.

언급URL : https://stackoverflow.com/questions/1066453/mysql-group-by-and-order-by

반응형