Dandy Now!
  • [MySQL] ONLY_FULL_GROUP_BY 오류: 개념과 해결 방법
    2025년 06월 18일 09시 48분 12초에 업로드 된 글입니다.
    작성자: DandyNow
    728x90
    반응형

    MySQL ONLY_FULL_GROUP_BY 오류: 개념과 해결 방법


    MySQL을 사용하면서 GROUP BY 쿼리 작성 시 In aggregated query without GROUP BY, expression #N of SELECT list contains nonaggregated column ... this is incompatible with sql_mode=only_full_group_by와 같은 오류 메시지를 만나는 경우가 많다. 이 오류는 ONLY_FULL_GROUP_BY라는 MySQL SQL 모드 때문에 발생한다. 이 블로그 포스팅에서는 ONLY_FULL_GROUP_BY가 무엇인지, 왜 이런 오류가 발생하는지, 그리고 효과적인 해결 방법은 무엇인지 상세히 알아보도록 하겠다.

    1. ONLY_FULL_GROUP_BY란?


    ONLY_FULL_GROUP_BY는 MySQL의 엄격한 SQL 모드 중 하나이다. 이 모드가 활성화되어 있으면, GROUP BY 절을 사용하는 쿼리에서 SELECT 리스트에 포함된 모든 컬럼은 다음 중 하나여야 한다.

    • 집계 함수(Aggregate Function)에 포함되어 있는 컬럼: SUM(), COUNT(), AVG(), MIN(), MAX()와 같은 함수 내부에 사용된 컬럼이다.
    • GROUP BY 절에 명시적으로 포함되어 있는 컬럼: GROUP BY 뒤에 나열된 컬럼이다.
    • GROUP BY 절에 포함된 컬럼의 함수 종속성(Functional Dependency)이 있는 컬럼: 예를 들어, id가 기본 키이고 nameid에 종속적이라면, id로 그룹화할 때 nameSELECT 절에 포함할 수 있다. 하지만 MySQL은 이를 자동으로 파악하지 못할 때가 많으므로 명시적으로 GROUP BY에 포함하는 것이 안전하다.

    이 모드는 SQL 표준(SQL92 및 이후 버전)을 준수하도록 강제하여, GROUP BY 쿼리의 결과가 예측 가능하고 논리적으로 명확하도록 돕는다. 만약 GROUP BY에 없는 컬럼을 SELECT하면, 해당 그룹 내에서 여러 값이 존재할 수 있는데 MySQL이 어떤 값을 반환해야 할지 알 수 없기 때문에 오류를 발생시키는 것이다.

    2. ONLY_FULL_GROUP_BY 오류가 발생하는 이유


    가장 흔한 오류 발생 시나리오는 다음과 같다.

    • SELECT 절에 비집계 컬럼이 있지만 GROUP BY에 없는 경우:
      예를 들어, 어떤 테이블에서 사용자의 나이를 합산하면서 사용자의 이름을 함께 가져오려 할 때, GROUP BY 절에 이름이 없으면 오류가 발생한다. 한 그룹(예: 특정 나이대) 내에 여러 이름이 있을 수 있기 때문이다.

      -- 오류를 발생시킬 수 있는 쿼리 예시
      SELECT category_id, item_name, SUM(price)
      FROM products
      GROUP BY category_id;
      -- 이 쿼리에서 item_name은 GROUP BY에 없으며, SUM()으로 묶이지도 않았다.

      위 쿼리에서 category_id로 그룹화할 때, 한 category_id에 여러 item_name이 있을 수 있으므로 item_name에 어떤 값을 가져와야 할지 MySQL은 판단할 수 없어 오류가 발생한다.

    3. ONLY_FULL_GROUP_BY 오류 해결 방법


    ONLY_FULL_GROUP_BY 오류를 해결하는 방법은 크게 두 가지로 나뉜다.

    3.1. SQL 쿼리 자체를 수정하는 방법 (권장)

    이 방법은 SQL 표준에 부합하며 데이터의 논리적 일관성을 유지하는 가장 바람직한 해결책이다. 쿼리의 목적에 따라 다음과 같이 수정할 수 있다.

    • SELECT 절의 모든 비집계 컬럼을 GROUP BY 절에 추가한다.
      이는 가장 직관적인 해결 방법이다. SELECT 절에서 가져오고 싶은 모든 개별 컬럼을 GROUP BY 절에 명시적으로 추가한다.

      -- 해결 방법 1: GROUP BY 절에 item_name 추가
      SELECT category_id, item_name, SUM(price)
      FROM products
      GROUP BY category_id, item_name;

      이 쿼리는 category_iditem_name의 조합별로 price의 합계를 계산한다.

    • 비집계 컬럼에 적절한 집계 함수를 적용한다.
      만약 SELECT 절의 비집계 컬럼이 각 그룹 내에서 단일한 대표 값을 가지도록 하고 싶다면, MIN(), MAX(), ANY_VALUE() (MySQL 8.0 이상)와 같은 집계 함수를 사용할 수 있다.

      -- 해결 방법 2: 비집계 컬럼에 집계 함수 적용 (가장 오래된/가장 작은 값을 가져옴)
      SELECT category_id, MIN(item_name) AS first_item_name, SUM(price)
      FROM products
      GROUP BY category_id;

      이 쿼리는 각 category_id 그룹에서 가장 사전적으로 앞서는 item_nameprice의 합계를 가져온다. ANY_VALUE(item_name)를 사용하면 임의의 item_name을 가져온다.

    3.2. MySQL SQL 모드를 변경하는 방법 (비권장)

    이 방법은 근본적인 해결책이 아니며, 데이터의 일관성을 해칠 수 있기 때문에 일반적으로 권장하지 않는다. 하지만 특정 레거시 시스템과의 호환성 등의 이유로 불가피하게 사용해야 할 때가 있을 수 있다.

    • 세션(Session) 단위로 변경하기:
      현재 MySQL 연결 세션에 대해서만 ONLY_FULL_GROUP_BY 모드를 비활성화한다. 애플리케이션에서 데이터베이스 연결 후 이 쿼리를 실행할 수 있다.

      SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));

      이 설정은 해당 세션이 종료되면 초기화된다.

    • 전역(Global) 단위로 변경하기:
      MySQL 서버 전체에 대해 ONLY_FULL_GROUP_BY 모드를 비활성화한다. 이는 MySQL 설정 파일(my.cnf 또는 my.ini)을 수정하여 적용하며, MySQL 서버 재시작이 필요하다.

      [mysqld]
      sql_mode=STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
      -- 기존 sql_mode 값에서 ONLY_FULL_GROUP_BY만 제거하고 나머지는 유지하는 것이 안전하다.

      주의: 이 변경은 서버의 모든 데이터베이스와 애플리케이션에 영향을 미치므로 신중하게 적용해야 한다.

    4. 결론


    ONLY_FULL_GROUP_BY 오류는 MySQL이 SQL 표준을 엄격하게 적용하여 발생하는 문제이다. 이 오류는 쿼리의 논리적 모호성을 방지하려는 의도에서 비롯된다. 가장 좋은 해결 방법은 SQL 쿼리 자체를 수정하여 GROUP BY 절과 SELECT 절의 일관성을 맞추는 것이다. 비집계 컬럼들을 GROUP BY 절에 추가하거나, 적절한 집계 함수를 사용하여 쿼리의 의도를 명확히 하는 것이 중요하다. SQL 모드를 변경하는 것은 임시 방편이거나 특정 상황에서만 고려해야 할 보조적인 방법이다. 쿼리 작성 시 ONLY_FULL_GROUP_BY 원칙을 이해하고 적용한다면, 더욱 견고하고 예측 가능한 데이터베이스 애플리케이션을 구축할 수 있을 것이다.

    728x90
    반응형
    댓글