GROUP BY 절에 나타나거나 집계 함수에 사용되어야합니다.
이 발신자 '메이커'처럼 보이는 테이블이 있습니다.
cname | wmname | avg
--------+-------------+------------------------
canada | zoro | 2.0000000000000000
spain | luffy | 1.00000000000000000000
spain | usopp | 5.0000000000000000
그리고 각 cname에 대한 최대 평균을 선택하고 싶습니다.
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 | max
--------+--------+------------------------
canada | zoro | 2.0000000000000000
spain | luffy | 1.00000000000000000000
spain | usopp | 5.0000000000000000
실제 결과는
cname | wmname | max
--------+--------+------------------------
canada | zoro | 2.0000000000000000
spain | 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과 SQLServer는 이것을 전혀 허용하지 않습니다. MySQL은 기본적으로 허용했지만 5.7 이후 관리자는 ONLY_FULL_GROUP_BY
이 기능을 지원하려면 서버 구성 에서이 옵션 ( )을 수동으로 활성화해야합니다 ...
Postgres에서는 특수 DISTINCT ON (expression)
구문을 사용할 수도 있습니다 .
SELECT DISTINCT ON (cname)
cname, wmname, avg
FROM
makerar
ORDER BY
cname, avg DESC ;
group by
선택 에서 그룹화되지 않은 필드와 집계되지 않은 필드를 지정할 때의 문제점 은 엔진이이 경우 어떤 레코드의 필드를 리턴해야하는지 알 수 없다는 것입니다. 처음인가요? 마지막인가요? 자연스럽게 집계 결과에 해당하는 (아무 기록 일반적으로 없습니다 min
및 max
예외가).
그러나 해결 방법이 있습니다. 필수 필드도 집계하십시오. posgres에서는 다음과 같이 작동합니다.
SELECT cname, (array_agg(wmname ORDER BY avg DESC))[1], MAX(avg)
FROM makerar GROUP BY cname;
이것은 avg 순서로 모든 wname의 배열을 생성하고 첫 번째 요소를 반환합니다 (postgres의 배열은 1을 기반으로 함).
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의 답변을 확인해야합니다.
저에게는 "일반적인 집계 문제"가 아니라 잘못된 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;
됩니까? 그것은이어야한다 spain+luffy
나 spain+usopp
? 왜? 되지 않은 결정 "더 나은"를 선택하는 방법을 쿼리에서 wmname을 여러 적합하면 결과도 결정되지 않도록. 이것이 SQL 인터프리터가 오류를 반환하는 이유입니다. 쿼리가 올바르지 않습니다.
다시 말해, " spain
그룹 에서 누가 최고 입니까?"라는 질문에 대한 정답은 없습니다. . Lopp은 usopp보다 낫지 않습니다. 왜냐하면 usopp는 동일한 "점수"를 갖기 때문입니다.
최근에를 사용하여 계산하려고 할 때이 문제가 발생 case when
하여 which
and 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
이것은 잘 작동하는 것 같습니다
SELECT *
FROM makerar m1
WHERE m1.avg = (SELECT MAX(avg)
FROM makerar m2
WHERE m1.cname = m2.cname
)
'Programing' 카테고리의 다른 글
REST 웹 서비스를 사용하여 메타 데이터가있는 파일을 어떻게 업로드합니까? (0) | 2020.04.16 |
---|---|
서브 프로세스에서 'shell = True'의 실제 의미 (0) | 2020.04.16 |
java.util.Set에 get (int index)이없는 이유는 무엇입니까? (0) | 2020.04.16 |
서브 클래스는 개인 필드를 상속합니까? (0) | 2020.04.16 |
어떤 MVVM 프레임 워크를 사용해야합니까? (0) | 2020.04.16 |