일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 혼자공부하는sql
- 날솟샘
- 화학
- 데이터베이스
- SQLD
- 일반화학
- 설교
- 글로벌리더십학부
- 한동대학교
- 찬양
- 묵상
- 웹개발
- FE
- 전산전자공학부
- CHEMISTRY
- 날마다 솟는 샘물
- csee
- 예배
- 유태준교수님
- CCM
- GLS
- dbms
- 프론트엔드
- Database
- Software Engineering
- 남재창교수님
- 어노인팅
- typeScript
- QT
- SQL
- Today
- Total
멈추지 않는 기록
[혼자공부하는SQL] 11강 본문
04-3. SQL 프로그래밍
0. 시작하기 전에
1) 스토어드 프로시저는
: MySQL에서 프로그래밍 기능이 필요할 때 사용하는 데이터베이스 개체이다.
: SQL 프로그래밍은 기본적으로 스토어드 프로시저 안에 만들어야 한다.
2) 구조
DELIMITER $$ -- 스토어드 프로시저의 코딩 부분
CREATE PROCEDURE 스토어드_프로시저_이름()
BEGIN
-- 이 부분에 SQL 프로그래밍 코딩
END $$ -- 스토어드 프로시저 종료
DELIMITER; -- 종료 문자를 다시 세미콜론(;)으로 변경
CALL 스토어드_프로시저_이름(); -- 스토어드 프로시저 실행
(1) 일반적으로 구분문자(DELIMITER)는 $$를 많이 사용하지만, 원한다면 /, &, Q 등을 사용해도 상관없다. 다른 기호와 중복될 수 있으므로, 기호 2개를 연속해서 사용하는 것이 좋다.
(2) 즉, 스토어드 프로시저는 DEIMITER $$ ~ END $$ 안에 작성하고 CALL로 호출한다.
1. IF문
: 조건문으로 가장 많이 사용되는 프로그래밍 문법 중 하나이다.
1) IF 문의 기본 형식
: IF문은 조건식이 참이라면 ‘SQL문장들’을 실행하고, 그렇지 않으면 그냥 넘어간다.
(1) 형식
IF <조건식> THEN
SQL문장들
END IF;
: ‘SQL문장들’이 한 문장이라면, 그 문장만 써도 되지만, 두 문장 이상이 처리되어야 할 때는 BEGIN ~ END로 묶어줘야 한다.
(2) 예시
USE market_db;
DROP PROCEDURE IF EXISTS ifProc1; -- 기존에 ifProc1()을 만든 적이 있다면 삭제한다.
DELIMITER $$ -- 세미콜론(;)으로는 SQL 끝인지, 스토어드 프로시저의 끝인지 구별할 수 없어 $를 사용한다.
CREATE PROCEDURE ifProc1() -- 스토어드 프로시저의 이름을 ifProc1()로 지정했다.
BEGIN
IF 100 = 100 THEN -- 조건식으로 100과 100이 같은지 비교했다.
SELECT '100은 100과 같습니다.';
END IF;
END $$
DELIMITER ;
CALL ifProc1(); -- CALL로 호출하면 ifProc1()이 실행된다.
: 다른 프로그래밍언어에서는 같다는 의미로 ==를 사용하지만, SQL은 =를 사용한다.
: 그리고 SELECT 뒤에 문자가 나오면, 그냥 화면에 출력해준다. (print()와 같은 기능)
2) IF ~ ELSE문
: 조건에 따라 다른 부분을 수행한다. 조건식이 참이라면 ‘SQL문장1’을 실행하고, 그렇지 않으면 ‘SQL문장2’를 실행한다.
(1) 예시
DROP PROCEDURE IF EXISTS ifProc2;
DELIMITER $$
CREATE PROCEDURE ifProc2()
BEGIN
DECLARE myNum INT; -- myNum 변수 '선언'
SET myNum = 200; -- 변수에 값 '대입'
IF myNum = 100 THEN
SELECT '100입니다.';
ELSE
SELECT '100이 아닙니다.';
END IF;
END $$
DELIMITER ;
CALL ifProc2();
3) 응용
DROP PROCEDURE IF EXISTS ifProc3;
DELIMITER $$
CREATE PROCEDURE ifProc3()
BEGIN
DECLARE debutDate DATE; -- 데뷰일
DECLARE curDate DATE; -- 오늘
DECLARE days INT; -- 활동한 일수
SELECT debut_date INTO debutDate -- debut_date 결과를 '변수 hireDATE'에 대입
FROM market_db.member
WHERE mem_id = 'APN';
SET curDATE = CURRENT_DATE(); -- 현재 날짜
SET days = DATEDIFF(curDATE, debutDate); -- 날짜의 차이, 일 단위
IF (days/365) >= 5 THEN -- 5년이 지났다면
SELECT CONCAT('데뷔한지 ', days, '일이나 지났습니다. 핑순이들 축하합니다!');
ELSE
SELECT '데뷔한지 ' + days + '일밖에 안되었네요. 핑순이들 화이팅~' ;
END IF;
END $$
DELIMITER ;
CALL ifProc3();
(1) 변수 선언
DECLARE 변수명 변수타입;
(2) 검색 결과를 변수에 저장
SELECT 열_이름 INTO 저장할 변수
FROM 테이블
WHERE 조건
(3) 현재 날짜 구하는 함수 : CURRENT_DATE();
-- 예시
SET curDATE = CURRENT_DATE()
(4) 날짜의 차이 (일 단위)를 구하는 함수 : DATEDIFF(최근 날짜, 데뷔 날짜)
-- 특징 : 결과가 양수면 날짜1이 더 미래, 음수면 날짜2가 더 미래이다.
SELECT DATEDIFF('2025-12-31', '2025-01-01') AS result; -- 결과: 364 (날짜 차이)
SELECT DATEDIFF('2025-01-01', '2025-12-31') AS result; -- 결과: -364
SELECT DATEDIFF(NOW(), '2024-01-01') AS result; -- 현재 날짜와 비교 가능
-- 예시 : 오늘 날짜와 데뷔 날짜의 차이
SET dyas = DATEDIFF(curDATE, debutDate);
2. CASE문
: 조건을 설정하여 여러 가지 조건 중 선택할 수 있다.
1) CASE문의 기본 형식
: IF문은 참 아니면 거짓 두 가지만 있기 때문에, 2중 분기라는 용어를 사용한다.
: 반면, CASE문은 2가지 이상의 여러 가지 경우일 때 처리가 가능하므로 다중 분기라고 부른다.
: SWITCH ~ CASE문과 비슷한 기능을 한다.
(1) 형식
CASE
WHEN 조건1 THEN
SQL문장들1
WHEN 조건2 THEN
SQL문장들2
WHEN 조건3 THEN
SQL문장들3
ELSE
SQL문장들4
END CASE;
: 조건이 여러개라면 WHEN을 여러 번 반복하고, 모든 조건에 해당하지 않으면 마지막 ESLE 부분을 수행한다.
(2) 예시
DROP PROCEDURE IF EXISTS caseProc;
DELIMITER $$
CREATE PROCEDURE caseProc()
BEGIN
-- 변수 선언
DECLARE point INT ;
DECLARE credit CHAR(1);
-- 점수 가정 (대입)
SET point = 88 ;
CASE
WHEN point >= 90 THEN
SET credit = 'A';
WHEN point >= 80 THEN
SET credit = 'B';
WHEN point >= 70 THEN
SET credit = 'C';
WHEN point >= 60 THEN
SET credit = 'D';
ELSE
SET credit = 'F';
END CASE;
SELECT CONCAT('취득점수==>', point), CONCAT('학점==>', credit);
END $$
DELIMITER ;
CALL caseProc();
2) CASE 문의 활용
(1) 예시의 상황
: 회원의 등급을 4단계로 나누려고 한다.
총 구매액 | 회원등급 |
1500 이상 | 최우수고객 |
1000 ~ 1499 | 우수 고객 |
1~999 | 일반고객 |
0 이하 (구매한 적 없음) | 유령 고객 |
(2) 코드
USE market_db;
-- 그룹 별 총 구매액
SELECT mem_id, SUM(price * amount)
FROM buy
GROUP BY mem_id;
-- 그룹 별 총 구매액 (내림차순)
SELECT mem_id, SUM(price * amount)
FROM buy
GROUP BY mem_id
ORDER BY SUM(price * amount) DESC;
-- 그룹 별 총 구매액 (내림차순) - 아이디, 이름, 구매액
SELECT B.mem_id, M.mem_name, SUM(price * amount)
FROM buy B
INNER JOIN member M
ON B.mem_id = M.mem_id
GROUP BY B.mem_id
ORDER BY SUM(B.price * B.amount) DESC;
-- 그룹 별 총 구매액 (내림차순) - 유령 고객까지 반영 (mem_id를 신경 쓰기)
SELECT M.mem_id, M.mem_name, SUM(price * amount)
FROM buy B
RIGHT OUTER JOIN member M
ON B.mem_id = M.mem_id
GROUP BY M.mem_id
ORDER BY SUM(B.price * B.amount) DESC;
-- 그룹 별 총 구매액 (내림차순) - CASE 적용
SELECT M.mem_id, M.mem_name, SUM(price * amount),
CASE
WHEN (SUM(price * amount) >= 1500) THEN '최우수고객'
WHEN (SUM(price * amount) >= 1000) THEN '우수고객'
WHEN (SUM(price * amount) >= 1) THEN '일반고객'
ELSE '유령고객'
END "회원등급"
FROM buy B
RIGHT OUTER JOIN member M
ON B.mem_id = M.mem_id
GROUP BY M.mem_id
ORDER BY SUM(B.price * B.amount) DESC;
(3) 궁금증
Q. 예시 1에서는 CASE 뒤에 END 하고 CASE 라고 적었는데, 예시 2에서는 END 하고 "회원등급"이라고 했어. 무슨 차이고 왜 그런거야?
A. CASE 문은 프로시저 내부에서 변수에 값을 할당할 때와 SELECT 문에서 컬럼 값을 결정할 때 사용하는 방식이 다르다.
구분사용 위치END 뒤 표현설명
예시 1 | 프로시저 내부 (SET 사용) | END CASE; | CASE 문이 단독으로 사용되며, SET을 통해 변수에 값을 할당하기 때문에 END CASE;로 종료해야 한다. |
예시 2 | SELECT 문 내부 (컬럼 값 결정) | "회원등급" | CASE 문이 SELECT 문의 컬럼 값으로 사용되므로, END 뒤에 컬럼명을 지정하여 결과 테이블에 해당 값이 포함되도록 해야 한다. |
즉, 예시 1에서는 프로시저 내부에서 값 할당을 위해 END CASE;로 종료하고, 예시 2에서는 SELECT 문에서 컬럼 값을 결정하므로 END 뒤에 컬럼명을 명시한 것이다.
3. WHILE문
1) WHILE문의 기본 형식
: WHILE문은 조건식이 참인 동안에 SQL문장들을 계속 반복한다.
(1) 형식
WHILE <조건식> DO
SQL 문장들
END WHILE;
(2) 예시
: 1부터 100까지 더하는 함수 whileProc
DROP PROCEDURE IF EXISTS whileProc;
DELIMITER $$
CREATE PROCEDURE whileProc()
BEGIN
-- 변수 선언
DECLARE i INT;
DECLARE hap INT;
-- 변수 대입
SET i = 1;
SET hap = 0;
-- 반복 진행
WHILE (i < 100) DO
SET hap = hap + i;
SET i = i + 1;
END WHILE;
-- 결과 출력
SELECT '1부터 100까지의 합 ==> ', hap;
END $$
DELIMITER ;
CALL whileProc();
2) WHILE문의 응용
(1) 종류
- ITERATE [레이블] : 지정한 레이블로 가서 계속 진행한다.
- LEAVE [레이블] : 지정한 레이블을 빠져나간다. 즉 WHILE문이 종료된다.
(2) 예시
DROP PROCEDURE IF EXISTS whileProc2;
DELIMITER $$
CREATE PROCEDURE whileProc2()
BEGIN
-- 변수 선언
DECLARE i INT; -- 1에서 100까지 증가할 변수
DECLARE hap INT; -- 더한 값을 누적할 변수
-- 변수 대입
SET i = 1;
SET hap = 0;
myWhile: -- While문에 label을 지정
WHILE (i <= 100) DO
IF (i%4 = 0) THEN -- 생략 조건
SET i = i + 1;
ITERATE myWhile; -- 지정한 label문으로 가서 계속 진행
END IF;
SET hap = hap + i;
IF (hap > 1000) THEN -- 종료 조건
LEAVE myWhile; -- 지정한 label문을 떠남. 즉, While 종료.
END IF;
SET i = i + 1;
END WHILE;
SELECT '1부터 100까지의 합(4의 배수 제외), 1000 넘으면 종료 ==>', hap;
END $$
DELIMITER ;
CALL whileProc2();
4. 동적 SQL
: SQL문은 내용이 고정되어 있는 경우가 대부분이다. 하지만 상황에 따라 내용 변경이 필요할 때, 동적 SQL을 사용하면 변경되는 내용을 실시간으로 적용시켜 사용할 수 있다.
1) PREPARE와 EXECUTE
(1) 의미
- PREPRAE : SQL 문을 실행하지는 않고, 미리 준비만 해놓는다.
- ESECUTE : 준비한 SQL문을 실행한다.
- DEALLOCATE PREPARE : 실행한 후에는 문장을 해제해주는 것이 바람직하다.
(2) 예시
: mem_id가 ‘BLK”인 멤버의 정보를 보여준다.
USE market_db;
PREPARE myQuery FROM 'SELECT * FROM member WHERE mem_id = "BLK"';
EXECUTE myQuery;
DEALLOCATE PREPARE myQuery;
2) 동적 SQL의 활용
(1) 물음표(?)의 사용
: PREPARE 문에서는 ?로 향후에 입력될 값을 비워놓고, EXECUTE에서 USING으로 ?에 값을 전달할 수 있다.
: 이를 통해 실시간으로 필요한 값을 전ㄷ라해서 동적으로 SQL이 실행된다.
(2) 예시
DROP TABLE IF EXISTS gate_table;
-- 테이블 생성
CREATE TABLE gate_table (
id INT AUTO_INCREMENT PRIMARY KEY,
entry_time DATETIME
);
-- 현재 날짜와 시간 대입
SET @curDate = CURRENT_TIMESTAMP();
-- SQL문 준비 및 실행
PREPARE myQuery FROM 'INSERT INTO gate_table VALUES (NULL, ?)';
EXECUTE myQuery USING @curDate;
-- SQL문 해제
DEALLOCATE PREPARE myQuery;
-- 테이블 검색
SELECT * FROM gate_table;
'웹 개발 > MySQL' 카테고리의 다른 글
[혼자공부하는SQL] 13강 (1) | 2025.02.19 |
---|---|
[혼자공부하는SQL] 12강 (0) | 2025.02.19 |
[혼자공부하는SQL] 10강 (0) | 2025.02.13 |
[혼자공부하는SQL] 9강 (1) | 2025.02.13 |
[혼자공부하는SQL] 8강 (0) | 2025.02.13 |