sourcecode

MySQL의 그룹화 전 순서

copyscript 2022. 11. 17. 21:22
반응형

MySQL의 그룹화 전 순서

여기서 비슷한 질문들을 많이 찾을 수 있지만 나는 어떤 질문도 그 질문에 적절하게 대답하지 못한다고 생각한다.

저는 지금 가장 인기 있는 질문부터 이어서 괜찮다면 그들의 예를 들어 보겠습니다.

이 경우 데이터베이스의 각 작성자에 대한 최신 게시물을 가져오는 작업이 수행됩니다.

예제 쿼리는 항상 반환되는 최신 게시물은 아니기 때문에 사용할 수 없는 결과를 생성합니다.

SELECT wp_posts.* FROM wp_posts
    WHERE wp_posts.post_status='publish'
    AND wp_posts.post_type='post'
    GROUP BY wp_posts.post_author           
    ORDER BY wp_posts.post_date DESC

현재 승인된 답변은 다음과 같습니다.

SELECT
    wp_posts.*
FROM wp_posts
WHERE
    wp_posts.post_status='publish'
    AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author
HAVING wp_posts.post_date = MAX(wp_posts.post_date) <- ONLY THE LAST POST FOR EACH AUTHOR
ORDER BY wp_posts.post_date DESC

안타깝게도 이 답변은 단순하고 잘못된 것이며 대부분의 경우 조직 쿼리보다 안정적인 결과를 얻을 수 없습니다.

가장 좋은 해결책은 폼의 서브쿼리를 사용하는 것입니다.

SELECT wp_posts.* FROM 
(
    SELECT * 
    FROM wp_posts
    ORDER BY wp_posts.post_date DESC
) AS wp_posts
WHERE wp_posts.post_status='publish'
AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author 

그럼 제 질문은 간단합니다.서브쿼리에 의존하지 않고 그룹화하기 전에 행을 정렬할 수 있는 방법이 있습니까?

편집: 이 질문은 다른 질문의 계속으로, 제 상황에 대한 자세한 내용은 조금 다릅니다.특정 게시물의 고유 식별자인 wp_posts.id도 있다고 가정할 수 있습니다.

「」의 ORDER BY이 문제에 대한 최선의 해결책은 아닙니다.

max(post_date)를 반환한 후 두 의 테이블에 합니다.post_author그리고 최대 날짜.

해결책은 다음과 같습니다.

SELECT p1.* 
FROM wp_posts p1
INNER JOIN
(
    SELECT max(post_date) MaxPostDate, post_author
    FROM wp_posts
    WHERE post_status='publish'
       AND post_type='post'
    GROUP BY post_author
) p2
  ON p1.post_author = p2.post_author
  AND p1.post_date = p2.MaxPostDate
WHERE p1.post_status='publish'
  AND p1.post_type='post'
order by p1.post_date desc

다음 샘플 데이터가 있는 경우:

CREATE TABLE wp_posts
    (`id` int, `title` varchar(6), `post_date` datetime, `post_author` varchar(3))
;

INSERT INTO wp_posts
    (`id`, `title`, `post_date`, `post_author`)
VALUES
    (1, 'Title1', '2013-01-01 00:00:00', 'Jim'),
    (2, 'Title2', '2013-02-01 00:00:00', 'Jim')
;

서브쿼리는 다음 항목의 최대 날짜와 작성자를 반환합니다.

MaxPostDate | Author
2/1/2013    | Jim

그런 다음 테이블에 다시 참여하기 때문에 두 값에 대해 해당 게시물의 전체 세부 정보가 반환됩니다.

SQL Fidle with Demo를 참조하십시오.

이 데이터를 정확하게 반환하기 위해 하위 쿼리를 사용하는 것에 대한 내 의견을 확장합니다.

로 MySQL로 이동하지 .GROUP BY SELECT 「」만 있으면, 「」가 됩니다.GROUP BY하지만 다른 이 10컬럼에 .다른 컬럼 값이 에 속한다는 보장은 없습니다.post_author열(열)이 a에 없는 경우GROUP BYMySQL my my my my my 。

집계 함수와 함께 하위 쿼리를 사용하면 매번 올바른 작성자 및 게시물이 반환됩니다.

을 사용할 수 .ORDER BY에서 """를 할 수 ." "" " " " " " " 를 적용할 수 .GROUP BYSELECT 이 은 SQL list 를 포함한 되지 않습니다.

솔루션에서는 GROUP BY 절의 확장을 사용하여 일부 필드별로 그룹화할 수 있습니다(이 경우,post_author

GROUP BY wp_posts.post_author

집계되지 않은 열을 선택합니다.

SELECT wp_posts.*

절별 그룹에 나열되지 않거나 집계 함수(MIN, MAX, COUNT 등)에서 사용되지 않는 것.

GROUP BY 절 확장자 올바른 사용

이 기능은 집계되지 않은 열의 모든 값이 모든 행에 대해 동일한 경우에 유용합니다.

를 들어,, 표가 , 가 있다.GardensFlowers )name텃밭flower" " " " ) :

INSERT INTO GardensFlowers VALUES
('Central Park',       'Magnolia'),
('Hyde Park',          'Tulip'),
('Gardens By The Bay', 'Peony'),
('Gardens By The Bay', 'Cherry Blossom');

여러 개의 꽃이 자라는 정원에서 자라는 모든 꽃들을 뽑아내려고 합니다.그런 다음 다음과 같은 하위 쿼리를 사용해야 합니다.

SELECT GardensFlowers.*
FROM   GardensFlowers
WHERE  name IN (SELECT   name
                FROM     GardensFlowers
                GROUP BY name
                HAVING   COUNT(DISTINCT flower)>1);

할 HAVING 을 HAVING 상태로 할 수 .HAVING COUNT(DISTINCT flower)=1 MySql에서는 같은 기능을 도 있습니다.

SELECT   GardensFlowers.*
FROM     GardensFlowers
GROUP BY name
HAVING   COUNT(DISTINCT flower)=1;

서브쿼리도 표준 SQL도 아닌 단순합니다.

GROUP BY 절 확장자가 잘못 사용됨

그러나 모든 행에 대해 같지 않은 집계되지 않은 열을 선택하면 어떻게 됩니까?MySql이 선택한 열 값은 무엇입니까?

MySql은 항상 처음 발견한 값을 선택하는 것 같습니다.

과 일치하는지 하려면 " " "를 .GROUP BY따라서 서브쿼리를 사용해야 합니다.이데올로기 때문에

MySql이 항상 처음 만나는 행을 선택한다는 가정 하에 GROUP BY 앞에 행을 정렬하고 있습니다.그러나 안타깝게도 설명서를 주의 깊게 읽어보면 이 가정이 사실이 아님을 알 수 있습니다.

항상 동일하지는 않은 집계되지 않은 열을 선택할 경우 MySql은 자유롭게 값을 선택할 수 있으므로 실제로 표시되는 값은 불확실합니다.

집계되지 않은 컬럼의 첫 번째 값을 얻기 위한 이 트릭이 많이 사용되고 있다는 것을 알 수 있습니다.또, 통상은, 거의 항상 유효합니다만, 때때로(자신의 부담으로) 사용하고 있습니다.하지만 문서화되어 있지 않기 때문에 이러한 행동에 의존할 수 없습니다.

이 링크(ypercube 감사합니다!)GROUP BY trick has optimized away는 아마도 다른 최적화 엔진 때문에 동일한 쿼리가 MySql과 MariaDB 간에 다른 결과를 반환하는 상황을 보여줍니다.

그러니 이 속임수가 통한다면, 그건 그냥 운에 달려 있는 거야.

다른 질문에 대해 인정된 답변은 잘못된 것 같습니다.

HAVING wp_posts.post_date = MAX(wp_posts.post_date)

wp_posts.post_date으로 그 으로 결정되지 첫 이 될 이 높습니다.post_date 매겨지지 않은 에 첫 번째 GROUP BY 트릭이 무엇인지 알 수 .post_date맞닥뜨린.

한 작가의 유일한 게시물인 게시물이 반환될 수 있지만, 이마저도 항상 확실한 것은 아닙니다.

생각할 수 있는 해결책

저는 이것이 가능한 해결책이라고 생각합니다.

SELECT wp_posts.*
FROM   wp_posts
WHERE  id IN (
  SELECT max(id)
  FROM wp_posts
  WHERE (post_author, post_date) = (
    SELECT   post_author, max(post_date)
    FROM     wp_posts
    WHERE    wp_posts.post_status='publish'
             AND wp_posts.post_type='post'
    GROUP BY post_author
  ) AND wp_posts.post_status='publish'
    AND wp_posts.post_type='post'
  GROUP BY post_author
)

내부 질의에서 모든 작성자의 최대 게시 날짜를 반환합니다.그리고 같은 저자가 이론적으로 동시에 두 개의 글을 올릴 수 있다는 점을 고려하여 최대 아이디만 얻고 있습니다.그런 다음 최대 ID를 가진 모든 행을 반환합니다.IN 절 대신 join을 사용하면 더 빠르게 만들 수 있습니다.

하다면)ID만 하고 ID1 > ID2, '다'라는 이기도 합니다.post_date1 > post_date2그럼 더 간단하게 쿼리를 할 수 있는데, 이것이 사실인지는 잘 모르겠습니다.)

네가 읽을 내용은 좀 엉성하니까 집에서 시도하지 마!

SQL에서는 일반적으로 "아니오"라고 대답합니다.다만, 이 경우,GROUP BY(@bluefeet에서 언급), MySQL에서는 YES입니다.

(post_status, post_type, post_author, post_date)에 BTREE 인덱스가 있다고 가정합니다.후드 아래 색인은 어떻게 생겼나요?

(post_status='post', post_type='user A', post_date='2012-12-01', post_status='post_status='post_status=', post_author='user A', post_type=') (post_status='post_status=', post_status=', post_status='post_status='post-atus='post-auter='))

즉, 데이터는 모든 필드를 기준으로 오름차순으로 정렬됩니다.

GROUP BY으로는 그룹화 그룹화 필드)에 따라 됩니다.post_author은 post_status, post_type에 WHEREclause인덱스가 첫 .)을 .「 」 「 」 「 」 「 」 「 」 「 」 「 」

(post_status='post', post_type='user A', post_date='2012-12-01'), post_status='post', post_type='post_author='user B', post_date='2012-10-01')

★★★★★★★★★★★★★★★★★.GROUP BYMySQL my my my my 。 당신이 했을 때post_user내림차순으로 우리의 지수를 역순으로 지나가며, 여전히 실제로 마지막 그룹마다 첫 번째 기록을 남긴다.

그것은

...
WHERE wp_posts.post_status='publish' AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author DESC

우리에게 줄 것이다

(post_status='post', post_type='user B', post_date='2012-12-01') (post_status='post', post_type='post', post_author='user A', post_date='-12-31')

이제 post_date별로 그룹화 결과를 주문하면 원하는 데이터를 얻을 수 있습니다.

SELECT wp_posts.*
FROM wp_posts
WHERE wp_posts.post_status='publish' AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author DESC
ORDER BY wp_posts.post_date DESC;

주의:

이것은 이 특정 질문에 대해 추천할 만한 것이 아닙니다.이 경우 @bluefeet에서 제안하는 내용을 약간 수정한 버전을 사용합니다.하지만 이 기술은 매우 유용할 수 있습니다.그룹의 마지막 레코드 검색하기

함정:이 접근법의 단점은 다음과 같습니다.

  • 쿼리 결과는 인덱스에 따라 달라지며, 이는 SQL 정신에 반한다(인덱스는 쿼리 속도를 높일 뿐이다).
  • 인덱스는 쿼리에 대한 영향을 전혀 알지 못합니다(앞으로 사용자나 다른 사용자가 인덱스를 너무 많은 리소스를 소비하여 변경함으로써 성능뿐만 아니라 쿼리 결과를 손상시킬 수 있음).
  • 만약 당신이 질문의 작동 방식을 이해하지 못한다면, 아마도 당신은 한 달 안에 설명을 잊어버릴 것이고, 그 질문은 당신과 당신의 동료들을 혼란스럽게 할 것이다.

하드 케이스에서의 퍼포먼스가 장점입니다.정렬에 @bluefeet후 이는 @'s query를 로 합니다).(post_status, post_type, post_author, post_date)인덱스도 작성됩니다).

제안사항:

말씀드렸듯이, 이러한 쿼리로 인해 MySQL은 임시 테이블에서 대량의 데이터를 정렬하는 데 시간을 낭비하게 됩니다.페이징이 필요한 경우(즉, LIMIT가 관련된 경우) 대부분의 데이터가 손실됩니다.정렬된 데이터의 양을 최소화합니다. 즉, 하위 쿼리의 최소 데이터를 정렬하고 제한한 다음 테이블 전체에 다시 참여합니다.

SELECT * 
FROM wp_posts
INNER JOIN
(
  SELECT max(post_date) post_date, post_author
  FROM wp_posts
  WHERE post_status='publish' AND post_type='post'
  GROUP BY post_author
  ORDER BY post_date DESC
  -- LIMIT GOES HERE
) p2 USING (post_author, post_date)
WHERE post_status='publish' AND post_type='post';

위에서 설명한 접근방식을 사용한 동일한 쿼리:

SELECT *
FROM (
  SELECT post_id
  FROM wp_posts
  WHERE post_status='publish' AND post_type='post'
  GROUP BY post_author DESC
  ORDER BY post_date DESC
  -- LIMIT GOES HERE
) as ids
JOIN wp_posts USING (post_id);

SQLFiddle에 대한 실행 계획에 대한 모든 쿼리입니다.

이거 드셔보세요. 작성자에게 최신 게시 날짜 목록을 받아보세요.바로 그거야

SELECT wp_posts.* FROM wp_posts WHERE wp_posts.post_status='publish'
AND wp_posts.post_type='post' AND wp_posts.post_date IN(SELECT MAX(wp_posts.post_date) FROM wp_posts GROUP BY wp_posts.post_author) 

max 함수 및 그룹 함수만 사용

    select max(taskhistory.id) as id from taskhistory
            group by taskhistory.taskid
            order by taskhistory.datum desc

아니요. 그룹화하기 전에 레코드를 정렬하는 것은 의미가 없습니다. 그룹화는 결과 집합을 변형시킵니다.서브쿼리 방식이 선호됩니다.이 작업이 너무 느릴 경우, 예를 들어 각 작성자의 마지막 게시물 ID를 별도의 표에 저장하거나 각 작성자에게 게시물 중 마지막 게시물인 부울 열을 삽입하여 표 설계를 변경해야 합니다.

요약하자면 표준 솔루션은 상관없는 서브쿼리를 사용하고 있으며 다음과 같습니다.

SELECT x.*
  FROM my_table x
  JOIN (SELECT grouping_criteria,MAX(ranking_criterion) max_n FROM my_table GROUP BY grouping_criteria) y
    ON y.grouping_criteria = x.grouping_criteria
   AND y.max_n = x.ranking_criterion;

MySQL의 오래된 버전 또는 매우 작은 데이터 세트를 사용하는 경우 다음 방법을 사용할 수 있습니다.

SELECT x.*
  FROM my_table x
  LEFT
  JOIN my_table y
    ON y.joining_criteria = x.joining_criteria
   AND y.ranking_criteria < x.ranking_criteria
 WHERE y.some_non_null_column IS NULL;  

이것이 이미 제안되었는지 여부는 알 수 없지만 SQL함수를 사용할 수 있습니다.

SELECT * FROM (
      SELECT wp_posts.*, ROW_NUMBER() OVER (PARTITION BY wp_posts.post_author ORDER BY post_date DESC) rank
      FROM wp_posts
      WHERE wp_posts.post_status = 'publish'
      AND wp_posts.post_type = 'post'
  ) AS T
WHERE rank = 1

모든 행이 "순위 지정"된 다음 각 첫 번째 행을 선택하면 됩니다.

나는 성능에 대한 어떤 단서도 가지고 있지 않다는 것을 인정하지만, 내가 아는 한 그것은 꽤 받아들일 수 있을 것이다.

혹시나 해서.저는 이런 걸 여러 번 했어요.

select * from 
  (select max(some_quantity) over (partition by id1, id2) as max_quantity, t.*
  from table_name t) tt 
where tt.max_quantity=tt.some_quantity;

의 최대 입니다.some_quantity.

GROUP BY 없이도 일관된 결과를 얻을 수 있는 사용자 정의 변수를 사용하는 솔루션을 소개합니다.목표는 연속된 하나의 셀의 최대값이 아니라 전체 행을 가져오는 것이었습니다.아래의 예를 참조해 주세요.

SET @product_id := 0;

SELECT
    products.order_code,
    purchases.`date`,
    purchases.price
FROM products
LEFT JOIN (       
    SELECT
        purchases.`date`,
        purchases.price,
        IF(@product_id = purchases.product_id, 0, 1) AS is_last,
        @product_id := purchases.product_id AS product_id
    FROM purchases
    ORDER BY purchases.product_id ASC, purchases.id DESC
) purchases ON products.id = purchases.product_id
WHERE purchases.is_last = 1
ORDER BY products.order_code ASC;

성능은 잘 모르겠지만, 5만 줄의 구매표에서는 0.1초였습니다.성능이 향상되면 알려주세요.

** 대규모 데이터셋과 함께 사용하면 하위 쿼리가 성능에 나쁜 영향을 미칠 수 있습니다**

원래 쿼리

SELECT wp_posts.*
FROM   wp_posts
WHERE  wp_posts.post_status = 'publish'
       AND wp_posts.post_type = 'post'
GROUP  BY wp_posts.post_author
ORDER  BY wp_posts.post_date DESC; 

수정된 쿼리

SELECT p.post_status,
       p.post_type,
       Max(p.post_date),
       p.post_author
FROM   wp_posts P
WHERE  p.post_status = "publish"
       AND p.post_type = "post"
GROUP  BY p.post_author
ORDER  BY p.post_date; 

가 쓰고 있기 max select clause> ==>max(p.post_date)서브 셀렉트 쿼리를 회피하고 그룹화 기준 뒤에 최대 컬럼으로 정렬할 수 있습니다.

첫째, 선택 시 *를 사용하지 마십시오. *는 성능에 영향을 미치고 그룹 사용을 방해합니다.다음 쿼리를 사용해 보십시오.

SELECT wp_posts.post_author, wp_posts.post_date as pdate FROM wp_posts
WHERE wp_posts.post_status='publish'
AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author           
ORDER BY pdate DESC

ORDER BY에서 테이블을 지정하지 않고 별칭만 지정하면 선택 결과가 정렬됩니다.

언급URL : https://stackoverflow.com/questions/14770671/mysql-order-by-before-group-by

반응형