source

GROUP BY 절에 나타나거나 집계 함수에서 사용해야 합니다.

lovecheck 2023. 5. 22. 21:10
반응형

GROUP BY 절에 나타나거나 집계 함수에서 사용해야 합니다.

이 발신자 '메이커'처럼 생긴 테이블이 있습니다.

cname wmname 평균의
캐나다의 조로 2.0000000000000000
스페인의 울퉁불퉁한 1.00000000000000000000
스페인의 usopp 5.0000000000000000

그리고 각 cname에 대한 최대 avg를 선택하고 싶습니다.

SELECT cname, wmname, MAX(avg)  FROM makerar GROUP BY cname;

하지만 오류가 발생할 것입니다.

ERROR:  column "makerar.wmname" must appear in the GROUP BY clause or be used in an   aggregate function 
LINE 1: SELECT cname, wmname, MAX(avg)  FROM makerar GROUP BY cname;

그래서 나는 이것을 합니다.

SELECT cname, wmname, MAX(avg)  FROM makerar GROUP BY cname, wmname;

그러나 이렇게 하면 의도된 결과를 얻을 수 없으며 아래의 잘못된 출력이 표시됩니다.

cname wmname 맥스.
캐나다의 조로 2.0000000000000000
스페인의 울퉁불퉁한 1.00000000000000000000
스페인의 usopp 5.0000000000000000

실제 결과는 다음과 같아야 합니다.

cname wmname 맥스.
캐나다의 조로 2.0000000000000000
스페인의 usopp 5.0000000000000000

이 문제를 해결하려면 어떻게 해야 합니까?

참고: 이 표는 이전 작업에서 만든 VIEW입니다.

예, 이것은 일반적인 집계 문제입니다.SQL3(1999) 이전에는 선택한 필드가 다음에 나타나야 합니다.GROUP BY조항[*]

이 문제를 해결하려면 하위 쿼리에서 집계를 계산한 다음 해당 집계와 결합하여 표시해야 하는 추가 열을 얻어야 합니다.

SELECT m.cname, m.wmname, t.mx
FROM (
    SELECT cname, MAX(avg) AS mx
    FROM makerar
    GROUP BY cname
    ) t JOIN makerar m ON m.cname = t.cname AND t.mx = m.avg
;

 cname  | wmname |          mx           
--------+--------+------------------------
 canada | zoro   |     2.0000000000000000
 spain  | usopp  |     5.0000000000000000

그러나 다음과 같이 단순해 보이는 창 기능도 사용할 수 있습니다.

SELECT cname, wmname, MAX(avg) OVER (PARTITION BY cname) AS mx
FROM makerar
;

이 방법을 사용하면 모든 레코드가 표시됩니다(창 기능이 그룹화되지 않음).그러나 올바른 값(즉, 최대 값)이 표시됩니다.cname수평)MAX각 행에 있는 국가를 위해, 그래서 그것은 당신에게 달려 있습니다:

 cname  | wmname |          mx           
--------+--------+------------------------
 canada | zoro   |     2.0000000000000000
 spain  | luffy  |     5.0000000000000000
 spain  | usopp  |     5.0000000000000000

유일한 솔루션을 보여줄 수 있는, 거의 틀림없이 덜 우아합니다.(cname, wmname)최대값과 일치하는 튜플은 다음과 같습니다.

SELECT DISTINCT /* distinct here matters, because maybe there are various tuples for the same max value */
    m.cname, m.wmname, t.avg AS mx
FROM (
    SELECT cname, wmname, avg, ROW_NUMBER() OVER (PARTITION BY avg DESC) AS rn 
    FROM makerar
) t JOIN makerar m ON m.cname = t.cname AND m.wmname = t.wmname AND t.rn = 1
;


 cname  | wmname |          mx           
--------+--------+------------------------
 canada | zoro   |     2.0000000000000000
 spain  | usopp  |     5.0000000000000000

[*]: 흥미롭게도, 비록 스펙이 그룹화되지 않은 분야를 선택할 수 있지만, 주요 엔진들은 그것을 별로 좋아하지 않는 것 같습니다.Oracle 및 SQL Server에서는 이를 전혀 허용하지 않습니다.Mysql은 기본적으로 허용했지만, 5.7 이후로 관리자는 이 옵션을 활성화해야 합니다.ONLY_FULL_GROUP_BY) 이 기능이 지원될 서버 구성에서 수동으로...

Postgres에서는 다음과 같은 특수 구문도 사용할 수 있습니다.

SELECT DISTINCT ON (cname) 
    cname, wmname, avg
FROM 
    makerar 
ORDER BY 
    cname, avg DESC ;

에서 그룹화되지 않은 필드와 집계되지 않은 필드를 지정할 때 문제가 발생했습니다.group by이 경우 엔진이 반환해야 하는 레코드의 필드를 알 수 없는 경우를 선택합니다.처음인가요?마지막인가요?일반적으로 집계 결과에 자연스럽게 해당하는 기록은 없습니다(min그리고.max예외).

그러나 필요한 필드도 집계해야 하는 해결 방법이 있습니다.사후 처리에서는 다음과 같이 작동해야 합니다.

SELECT cname, (array_agg(wmname ORDER BY avg DESC))[1], MAX(avg)
FROM makerar GROUP BY cname;

이렇게 하면 모든 wnames 배열이 생성되고 avg 순으로 정렬되며 첫 번째 요소가 반환됩니다(포스트gres 배열은 1 기반).

저는 "일반적인 집계 문제"에 대한 것이 아니라 잘못된 SQL 쿼리에 대한 것입니다."각 cname에 대한 최대 평균 선택"에 대한 단일 정답입니다.이라

SELECT cname, MAX(avg) FROM makerar GROUP BY cname;

결과는 다음과 같습니다.

 cname  |      MAX(avg)
--------+---------------------
 canada | 2.0000000000000000
 spain  | 5.0000000000000000

이 결과는 일반적으로 "각 그룹에 가장 적합한 결과는 무엇입니까?"라는 질문에 답합니다.우리는 스페인의 최고 결과는 5이고 캐나다의 최고 결과는 2입니다.그것은 사실이고 오류가 없습니다.wmname도 표시해야 하는 경우 "결과 집합에서 wmname을 선택하는 규칙은 무엇입니까?"라는 질문에 답해야 합니다.입력 데이터를 조금 변경하여 오류를 명확히 해 보겠습니다.

  cname | wmname |        avg           
--------+--------+-----------------------
 spain  | zoro   |  1.0000000000000000
 spain  | luffy  |  5.0000000000000000
 spain  | usopp  |  5.0000000000000000

쿼리를 할 때 과 같습니다.SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname;?요▁it까▁be▁should럴?spain+luffy또는spain+usopp왜? 쿼리에서 여러 개가 적합한 경우 "더 나은" wmname을 선택하는 방법이 결정되지 않으므로 결과도 결정되지 않습니다.그렇기 때문에 SQL 인터프리터에서 오류를 반환합니다. 쿼리가 올바르지 않습니다.

즉, "그룹 내에서 누가 최고인가?"라는 질문에는 정답이 없습니다.루피는 usopp보다 낫지 않습니다, 왜냐하면 usopp는 같은 "점수"를 가지고 있기 때문입니다.

SELECT t1.cname, t1.wmname, t2.max
FROM makerar t1 JOIN (
    SELECT cname, MAX(avg) max
    FROM makerar
    GROUP BY cname ) t2
ON t1.cname = t2.cname AND t1.avg = t2.max;

용사를 합니다.rank() 기능:

SELECT cname, wmname, avg
FROM (
    SELECT cname, wmname, avg, rank() 
    OVER (PARTITION BY cname ORDER BY avg DESC)
    FROM makerar) t
WHERE rank = 1;

메모

둘 중 하나는 그룹당 여러 개의 최대값을 보존합니다.max와 같은 평균 레코드가 둘 이상 있더라도 그룹당 하나의 레코드만 원한다면 @ypercube의 응답을 확인해야 합니다.

이것도 효과가 있는 것 같습니다.

SELECT *
FROM makerar m1
WHERE m1.avg = (SELECT MAX(avg)
                FROM makerar m2
                WHERE m1.cname = m2.cname
               )

최근에 다음을 사용하여 계산하려고 할 때 이 문제가 발생합니다.case when그리고 그것의 순서를 바꾼다는 것을 발견했습니다.which그리고.count문으로 문제를 해결할 수 있습니다.

SELECT date(dateday) as pick_day,
COUNT(CASE WHEN (apples = 'TRUE' OR oranges 'TRUE') THEN fruit END)  AS fruit_counter

FROM pickings

GROUP BY 1

를 사용하는 대신 - 후자에서 사과와 오렌지가 집계 함수에 나타나야 한다는 오류가 발생했습니다.

CASE WHEN ((apples = 'TRUE' OR oranges 'TRUE') THEN COUNT(*) END) END AS fruit_counter

언급URL : https://stackoverflow.com/questions/19601948/must-appear-in-the-group-by-clause-or-be-used-in-an-aggregate-function

반응형