전자 메일 테이블에서 여러 행을 선택하고 보낸 사람별로 그룹화 할 수 있기를 원합니다. 내 쿼리는 다음과 같습니다.
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 ONLY_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
//dev.mysql : HTTPS를 .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
답변
다음은 한 가지 접근 방식입니다.
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가 창에서 임의로 레코드를 선택하기 때문에 현재 답변이 잘못되었습니다.
MySQL 5.6 또는 MySQL 5.7과 함께 사용 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()
대부분의 경우 사용되지 않는를 제거했습니다 .
답변
다음과 같이 GROUP BY로 쿼리를 래핑하여 ORDER 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 모드 사용) 결과를 예측할 수 없습니다.
먼저 fromEmail, MIN (읽기)을 선택한 다음 두 번째 쿼리 (또는 하위 쿼리)-제목을 선택해야합니다.
답변
나는 표시된 것보다 더 복잡한 쿼리에 대해이 두 가지 접근 방식으로 어려움을 겪었습니다. 하위 쿼리 접근 방식은 내가 어떤 인덱스를 입력하더라도 끔찍하게 비효율적이었고 Hibernate를 통해 외부 자체 조인을 얻을 수 없었기 때문입니다.
이를 수행하는 가장 좋은 (그리고 가장 쉬운) 방법은 필요한 필드의 연결을 포함하도록 구성된 항목별로 그룹화 한 다음 SELECT 절에서 표현식을 사용하여 끌어내는 것입니다. MAX ()를 수행해야하는 경우 MAX ()하려는 필드가 항상 연결된 엔티티의 가장 중요한 끝에 있는지 확인하십시오.
이를 이해하기위한 핵심은 이러한 다른 필드가 Max ()를 충족하는 엔티티에 대해 변하지 않는 경우에만 쿼리가 의미가 있으므로 정렬 측면에서 다른 연결 부분을 무시할 수 있다는 것입니다. 이 링크의 맨 아래에서이를 수행하는 방법을 설명합니다. http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-columns.html
필드의 연결을 미리 계산하기 위해 (트리거와 같은) 삽입 / 업데이트 이벤트를 얻을 수 있다면이를 인덱싱 할 수 있으며 쿼리는 그룹이 실제로 MAX를 원했던 필드 위에있는 것처럼 빠릅니다. ). 이를 사용하여 최대 여러 필드를 가져올 수도 있습니다. 중첩 된 집합으로 표현 된 다차원 트리에 대한 쿼리를 수행하는 데 사용합니다.
답변
