MySQL 고급 기능 - GROUP BY, Window Function, Stored Procedure
GROUP BY
GROUP BY 기본 개념
GROUP BY로 그룹화할 때 특정 행을 뽑고 싶다면, 단순히 컬럼을 출력하면 각 컬럼별로 다른 행의 값이 나올 수 있습니다.
동일한 레코드의 값을 정확히 뽑으려면:
- 조인을 사용하거나
- Window Function을 사용합니다.
GROUP BY 관련 설정
sql_mode 확인 및 설정
-- 현재 설정 확인
SELECT @@sql_mode;
-- 전역 설정 변경
SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
-- 세션 설정 변경
SET sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
이 설정에서 ONLY_FULL_GROUP_BY를 제외하면 GROUP BY 관련 제약이 완화됩니다.
GROUP_CONCAT 함수
같은 그룹의 여러 행 값을 하나의 문자열로 합칠 때 사용합니다.
기본 사용법
SELECT k.id, GROUP_CONCAT(d.value)
FROM keywords AS k
INNER JOIN data AS d ON k.id = d.id
GROUP BY k.id;
정렬 및 구분자 지정
SELECT k.id, GROUP_CONCAT(d.value ORDER BY d.name SEPARATOR ' ')
FROM keywords AS k
INNER JOIN data AS d ON k.id = d.id
GROUP BY k.id;
Window Function (OVER 절)
Window Function은 행 그룹에 대해 계산을 수행하면서도 개별 행을 유지합니다.
누적 합계
SELECT
farmer,
crop_year,
kilos_produced,
SUM(kilos_produced) OVER(
PARTITION BY orange_variety
ORDER BY crop_year
) AS cumulative_previous_years
FROM orange_production
WHERE farmer = 'Pierre';
그룹별 순번 매기기 (ROW_NUMBER)
SELECT
id,
ROW_NUMBER() OVER (PARTITION BY code) AS row_num
FROM company;
그룹별 카운트
SELECT
*,
COUNT(*) OVER (PARTITION BY company_id) AS company_count
FROM employees;
주요 Window Function
| 함수 | 설명 |
|---|---|
ROW_NUMBER() |
각 행에 순번 부여 |
RANK() |
동일 값에 같은 순위, 다음 순위 건너뜀 |
DENSE_RANK() |
동일 값에 같은 순위, 다음 순위 연속 |
SUM(), AVG(), COUNT() |
집계 함수의 윈도우 버전 |
LAG(), LEAD() |
이전/다음 행 값 참조 |
Stored Procedure
기본 구조
DELIMITER //
CREATE PROCEDURE GetOfficeByCountry(IN countryName VARCHAR(255))
BEGIN
SELECT *
FROM offices
WHERE country = countryName;
END //
DELIMITER ;
변수 선언 및 사용
-- 변수 선언
DECLARE variable_name dataType(size) DEFAULT default_value;
-- 값 할당
SET variable_name = value;
-- 예시
DECLARE total_sale INT DEFAULT 0;
DECLARE x, y INT DEFAULT 0;
SET total_count = 10;
SELECT 결과를 변수에 저장
DECLARE total_products INT DEFAULT 0;
SELECT COUNT(*) INTO total_products
FROM products;
파라미터 종류
| 타입 | 설명 |
|---|---|
| IN | 입력 파라미터 (기본값) |
| OUT | 출력 파라미터 |
| INOUT | 입출력 파라미터 |
OUT 파라미터 예제
-- 프로시저 호출
CALL CountOrderByStatus('Shipped', @total);
-- 결과 확인
SELECT @total;
INOUT 파라미터 예제
DELIMITER $$
CREATE PROCEDURE set_counter(INOUT count INT(4), IN inc INT(4))
BEGIN
SET count = count + inc;
END$$
DELIMITER ;
WHILE 반복문
저장 프로시저 내에서 반복 처리가 필요할 때 사용합니다.
SET @myArrayOfValue = '2,5,2,23,6,';
WHILE (LOCATE(',', @myArrayOfValue) > 0)
DO
SET @value = ELT(1, @myArrayOfValue);
SET @myArrayOfValue = SUBSTRING(@myArrayOfValue, LOCATE(',', @myArrayOfValue) + 1);
INSERT INTO EXAMPLE VALUES(@value, 'hello');
END WHILE;
MySQL 버전별 이슈
MySQL 5.6 이하 TIMESTAMP 제약
MySQL 5.6 이하에서는 하나의 테이블에 CURRENT_TIMESTAMP를 사용하는 TIMESTAMP 컬럼이 2개 이상 있으면 오류가 발생합니다:
Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause
MySQL 5.6.5 이상에서는 이 제약이 해제되었습니다.
Comments