간단한 조회쿼리를 작성하다가 기억하고싶은 부분이 있어서 기록해본다.
조건 및 쿼리 작성 의도
- pk가 아닌 '검색어' 컬럼 SCT가 핵심
- 테이블에 검색어가 들어가는데, 이때 똑같은 검색어가 몇번이고 중복되어들어갈수있다. 단, 일련번호와 등록 시점이 다름.
- 이때 SCT를 중복을 제거한 상태로 목록에 불러오고 중복된 횟수를 나란히 출력한다.
- 즉 출력 목록은 그룹화되고 중복이 제거된 검색어, 검색어별 중복검색횟수.
- - 정렬기준은 중복 횟수의 내림차순
[미동작 쿼리]
- 중복제거된 검색어 기준으로 GROUP BY를 해야하고, 동시에 ORDER BY는 검색된 최신날짜를 기준으로 정렬하고싶었다.
- 그런데 문제는 아래와 같이 작성하면 전체 검색어의 총개수와 그룹화되고 정렬된 검색어의 총개수가 안맞는다는 점이었다.
- 문제상황 :
중복제거된 검색어 수 (DISTINCT SCT)
=/=
그룹화되고 정렬화된 검색어수 (GROUP BY,ORDER BY)
SELECT
DISTINCT CEIL(COUNT(DISTINCT SCT) OVER() / 1) AS TOT_CNT /* 중복제거된 검색어들의 총 개수 */
, SCT /* 검색어 */
, COUNT(SCT) AS DUP_SCT /* 동일한 검색어 검색 횟수 */
, REG_DT /* 등록일(검색일) */
FROM TN_SCT
WHERE 1=1
AND TO_CHAR(REG_DT, 'YYYYMMDD') >= '20240106'
AND TO_CHAR(REG_DT, 'YYYYMMDD') <= '20240108'
GROUP BY SCT, REG_DT
ORDER BY MAX(REG_DT) DESC
;
- 검색결과 GROUP BY, ORDER BY를 조합함으로서 생략되는 데이터, 혹은 중복되는 데이터가 발생하고
- 그결과 검색어수가 불일치한 원인이 되는 것 같았다.
- 챗지피티에도 질문해보았다.
쿼리의 결과가 예상과 다른 이유는 GROUP BY 구문과 COUNT(DISTINCT SCT) OVER()의 사용 방식에 있습니다.
COUNT(DISTINCT SCT) OVER()은 윈도우 함수로서, 전체 결과 집합에 대해 중복을 제거하고 그 결과의 총 개수를 계산합니다. 즉, COUNT(DISTINCT SCT) OVER()는 GROUP BY와는 관계없이 전체 데이터에 대한 중복 없는 SCT의 개수를 계산합니다.
반면에 GROUP BY SCT, REG_DT를 사용한 부분은 각각의 그룹에 대해 SCT와 REG_DT의 조합을 기준으로 그룹을 형성하고, 각 그룹에 대해 COUNT(SCT)를 계산합니다. 이는 SCT와 REG_DT의 조합에 따라 여러 그룹이 형성되기 때문에 COUNT(SCT)의 결과가 COUNT(DISTINCT SCT) OVER()와 다를 수 있습니다.
결론적으로, COUNT(DISTINCT SCT) OVER()는 전체 결과 집합에 대한 중복 없는 SCT의 개수를 계산하고, GROUP BY SCT, REG_DT는 SCT와 REG_DT의 조합에 따라 그룹을 형성하고 각 그룹의 SCT 개수를 계산합니다. 따라서 두 개의 결과가 서로 다를 수 있습니다.
- 하나씩 제거해보니 조건에서 등록날짜만 제거하면 검색어 결과수가 일치했다.
- 그래서 REG_DT를 ORDER BY에서 그룹기준 정렬하는게 아니라 SELECT 목록으로 빼고 ALIAS를 줘보았다.
[동작 쿼리]
SELECT
DISTINCT CEIL(COUNT(DISTINCT SCT) OVER() / 1) AS TOT_CNT /* 중복제거된 검색어들의 총 개수 */
, SCT /* 검색어 */
, COUNT(SCT) AS DUP_SCT /* 동일한 검색어 검색 횟수 */
, MAX(REG_DT) AS REG_DT /* 등록일(검색일) */
FROM TN_SCT
WHERE 1=1
AND TO_CHAR(REG_DT, 'YYYYMMDD') >= '20240106'
AND TO_CHAR(REG_DT, 'YYYYMMDD') <= '20240108'
GROUP BY SCT
ORDER BY REG_DT DESC
;
* GROUP BY와 ORDER BY 사용시 유의사항
- GROUP BY와 ORDER BY는 일반적으로 같은 열(컬럼)을 지칭하지 않아도 됩니다. 그러나 몇 가지 사항을 고려해야 합니다.
- 1. 집계 함수 사용 시: GROUP BY를 사용할 때 집계 함수(예: COUNT, SUM, AVG 등)를 사용하면 해당 집계 함수가 적용된 열을 기준으로 그룹화됩니다. 이때 ORDER BY에서도 동일한 집계 함수를 사용해야 합니다.
SELECT department, COUNT(*) as employee_count
FROM employees
GROUP BY department
ORDER BY employee_count DESC;
- 2. Alias 사용 시: GROUP BY 또는 ORDER BY에서 열에 별칭(Alias)을 사용하면, 이 별칭을 그대로 사용할 수 있습니다.
- 위 예제에서 employee_count는 GROUP BY와 ORDER BY에서 모두 사용됩니다.
SELECT department, COUNT(*) as employee_count
FROM employees
GROUP BY department
ORDER BY employee_count DESC;
- 3. 순서 지정: 결과를 정렬하는 경우 ORDER BY에 지정한 열의 순서는 GROUP BY와 일치하지 않아도 됩니다.
- 위 예제에서는 employee_count를 내림차순으로 정렬하고, 동일한 employee_count일 경우 department를 오름차순으로 정렬합니다.
SELECT department, COUNT(*) as employee_count
FROM employees
GROUP BY department
ORDER BY employee_count DESC, department ASC;


