ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • (2주차 8일) SQL 함수, 조인, 서브쿼리
    수업 내용 정리 2024. 5. 20. 17:30

    MariaDB

    > 함수 실습(2)

    • 문자열 함수
    /*
    * 문자열 함수
    */
    -- ASCII(), CHAR()
    SELECT ASCII('a'), CHAR(97);
    
    -- BIT_LENGTH(), CHAR_LENGTH(), LENGTH() 함수
    -- MariaDB는 기본적으로 UTF-8 코드를 사용하므로 영문은 1Byte, 한글은 3Byte를 할당함
    SELECT BIT_LENGTH('abc'), CHAR_LENGTH('abc'), LENGTH('abc');
    SELECT BIT_LENGTH('가나다'), CHAR_LENGTH('가나다'), LENGTH('가나다');
    
    -- CONCAT(), CONCAT_WS()
    SELECT CONCAT('2024', '05', '20');
    SELECT CONCAT_WS('/', '2024', '05', '20');
    
    -- usertbl 테이블에서 아이디, 이름, 전화번호를 조회
    SELECT userID, NAME, 
    --		 CONCAT(mobile1, mobile2) AS mobile FROM usertbl;
    		 CONCAT_WS(')',mobile1, mobile2) AS mobile FROM usertbl;
    		 
    SELECT CONCAT(emp_name, '님의 급여는 ', salary, '입니다.') FROM employee;
    
    -- 문자열 위치 반환: ELT(), FIELD(), FIND_IN_SET, INSTR(), LOCATE()
    SELECT ELT(2, '하나', '둘', '셋'), -- 첫 인자의 위치값 리턴
    		 FIELD('둘', '하나', '둘', '셋'), -- 첫 인자의 문자열 인자 위치 반환
    		 FIND_IN_SET('둘', '하나,둘,셋'), -- 문자열을 콤마로 구분된 리스트에서 찾아 위치 반환
    		 INSTR('하나둘셋', '둘'), -- 문자열에서 부분 문자열 시작 위치 반환
    		 LOCATE('둘', '하나둘셋'); -- INSTR과 반대
    		 
    -- employee 테이블에서 이메일의 '@' 위치값 리턴
    SELECT INSTR(email, '@') FROM employee;
    
    -- INSERT(): 기준 문자열 위치부터 길이만큼 삭제하고 문자열 추가
    SELECT INSERT('ABCDEFGHI', 3, 4, '@@@@'),
    		 INSERT('ABCDEFGHI', 2, 3, '@@@@');
    		 
    SELECT emp_name, 
    		 INSERT(emp_no, 8, 7, '*******') FROM employee;
    		 
    -- LEFT(), RIGHT()
    SELECT LEFT('ABCDEFGHI', 3), RIGHT('ABCDEFGHI', 3);
    
    SELECT emp_name, email, LEFT(email, INSTR(email, '@') - 1) AS id FROM employee;
    
    -- UPPER(), LOWER()
    SELECT UPPER('abcDEF'), LOWER('abcDEF');
    
    -- LPAD(), RPAD(): 문자열을 길이만큼 늘린 후, 빈 곳에 문자열 추가
    SELECT LPAD('HELLO', 4), LPAD('HELLO', 10, '#');
    
    -- employee 테이블에서 사원명, 주민등록번호 출력
    SELECT emp_name, RPAD(LPAD(emp_no, 8), 14, '*') FROM employee;
    
    -- LTRIM(), RTRIM(), TRIM()
    SELECT LTRIM('     HELLO     '),
    		 RTRIM('     HELLO     '),
    		 TRIM('     HELLO     ');
    		 
    SELECT TRIM(BOTH ' ' FROM '     HELLO     '),
    		 TRIM(BOTH 'Z' FROM 'ZZZZZHEZLLO  ZZ'),
    		 TRIM(LEADING 'Z' FROM 'ZZZZZHEZLLO  ZZ'),
    		 TRIM(TRAILING 'Z' FROM 'ZZZZZHEZLLO  ZZ');
    		 
    -- REPEAT(), SPACE()
    SELECT REPEAT('HELLO', 3),
    		 SPACE(10),
    		 CONCAT('Maria', SPACE(5), 'DB'),
    		 REVERSE('HELLO');
    
    -- REPLACE()
    SELECT REPLACE('hong123@naver.com', 'naver.com', 'gmail.com');
    
    SELECT emp_name, 
    		 REPLACE(email, '@kh.or.kr', '') AS id,
    		 REPLACE(email, 'kh.or.kr', 'naver.com') AS email FROM employee;
    		 
    -- SUBSTRING()
    SELECT SUBSTRING('대한민국만세', 3), SUBSTRING('대한민국만세', 3, 2);
    
    SELECT emp_name, 
    		 SUBSTRING(email, 1, INSTR(email, '@') - 1) AS 'id',
    		 IF(SUBSTRING(emp_no, 8, 1) = 1, '남자', '여자') AS 'gender' FROM employee;
    		 
    SELECT SUBSTRING_INDEX('cafe.naver.com', '.', 2),
    		 SUBSTRING_INDEX('cafe.naver.com', '.', -2);
    		 
    SELECT SUBSTRING_INDEX(email, '@', 1) FROM employee;

     

    • 수학 함수
    /*
    * 수학 함수
    */
    -- ABS()
    SELECT ABS(100), ABS(-100), ABS(10.9), ABS(-10.9);
    
    -- CEILING(), FLOOR(), ROUND(), TRUNCATE()
    SELECT CEILING(4.3), FLOOR(4.7), ROUND(4.53, 1), TRUNCATE(16.13, -1);
    
    -- MOD()
    SELECT MOD(10, 3), 7 % 8, 157 MOD 14;
    
    -- RAND()
    SELECT RAND();
    
    -- POW(), SQRT(), SIGN()
    SELECT POW(2, 3), SQRT(9), SIGN(15), SIGN(0), SIGN(-33);
    • 날짜 및 시간 함수
    /*
    * 날짜 및 시간 함수
    */
    -- ADDDATE(), SUBDATE(), ADDTIME(), SUBTIME()
    SELECT ADDDATE('2024-05-20', INTERVAL 31 DAY),
    		 ADDDATE('2024-05-20', INTERVAL 31 MONTH),
    		 ADDDATE('2024-05-20', INTERVAL 31 YEAR);
    		 
    SELECT SUBDATE('2024-05-20', INTERVAL 31 DAY);
    
    SELECT ADDTIME('2024-05-10 09:00:00', '01:10:30'),
    		 ADDTIME('09:00:00', '02:20:50');
    		 
    SELECT SUBTIME('2024-05-10 09:00:00', '01:10:30'),
    		 SUBTIME('09:00:00', '02:20:50');
    		 
    SELECT emp_name, hire_date,
    		 ADDDATE(hire_date, INTERVAL 3 MONTH) FROM employee;
    		 
    -- CURDATE(), CURTIME(), NOW(), SYSDATE(): 현재 날짜 및 시간 출력
    SELECT CURDATE(), CURTIME(), NOW(), SYSDATE();
    
    -- YEAR(), MONTH(), DAY(), HOUR(), MINUTE(), SECOND(), MICROSECOND(): 특정 정보만 출력
    SELECT YEAR(NOW()), MONTH(NOW()), DAY(NOW()), HOUR(NOW()),
    		 MINUTE(NOW()), SECOND(NOW()), MICROSECOND(NOW());
    		 
    -- DAYDIFF(), TIMEDIFF(): 날짜 및 시간 인자간의 차이 반환
    SELECT DATEDIFF(CURDATE(), '2022-05-20'),
    		 TIMEDIFF(CURTIME(), '09:00:00');
    		 
    SELECT emp_name, hire_date, 
    		 DATEDIFF(IF(ent_date IS NULL, CURDATE(), ent_date), hire_date) FROM employee;
    
    -- DAYOFWEEK(), MONTHNAME(), DAYOFYEAR(), LAST_DAY()		 
    SELECT DAYOFWEEK(CURDATE()),
    		 MONTHNAME('2024-04-20'),
    		 DAYOFYEAR(CURDATE()),
    		 LAST_DAY(CURDATE());
    		 
    SELECT emp_name, hire_date, LAST_DAY(CURDATE()) FROM employee;
    
    -- MAKEDATE(), MAKETIME(), PERIOD_ADD(), PERIOD_DIFF(), QUARTER(), TIME_TO_SEC()
    SELECT MAKEDATE(2024, 100), MAKETIME(22, 58, 25);
    
    SELECT PERIOD_ADD(202403, 11), PERIOD_DIFF(202408, 202305);
    
    SELECT QUARTER(CURDATE());
    
    SELECT TIME_TO_SEC(CURTIME());
    • 윈도우 함수
    /*
    * 윈도우 함수
    */
    -- #순위 함수 ROW_NUMBER(), RANK(), DENSE_RANK(), NTILE()
    -- ROW_NUMBER: uesrtbl 테이블에서 키가 큰 순으로 행넘버 부여
    SELECT ROW_NUMBER() OVER(ORDER BY height DESC, NAME ASC) AS 'num',
    		 NAME, addr, height FROM usertbl;
    		 
    -- 지역별로 키를 기준으로 행넘버 부여하여 주소, 순위, 이름, 키를 조회
    SELECT ROW_NUMBER() OVER(PARTITION BY addr ORDER BY height DESC) AS num,
    		 addr, NAME, height FROM usertbl ORDER BY addr;
    		 
    -- RANK: 동순위 이후 rank를 동순위만큼 증가
    SELECT RANK() OVER(ORDER BY height DESC) AS rank,
    		 addr, NAME, height FROM usertbl ORDER BY addr;
    		 
    SELECT RANK() OVER(PARTITION BY addr ORDER BY height DESC) AS num,
    		 addr, NAME, height FROM usertbl ORDER BY addr;
    		 
    -- DENSE_RANK: 동순위 이후 rank를 1 증가
    SELECT DENSE_RANK() OVER(ORDER BY height DESC) AS rank,
    		 addr, NAME, height FROM usertbl ORDER BY addr;
    		 
    -- NTILE: 정렬 후 데이터를 n분할
    SELECT NTILE(2) OVER(ORDER BY height DESC) AS 'group',
    		 addr, NAME, height FROM usertbl ORDER BY addr;
    		 
    -- employee 테이블에서 급여가 높은 순서대로 rank 부여하고 순위, 직원명, 급여 조회
    SELECT RANK() OVER(ORDER BY salary DESC) AS 'rank',
    		 emp_name, salary FROM employee ORDER BY salary DESC;
    		 
    SELECT RANK() OVER(PARTITION BY job_code ORDER BY salary DESC) AS 'rank',
    		 emp_name, job_code, salary FROM employee ORDER BY salary DESC;
    		 
    -- #분석 함수 LEAD(), LAG(), FIRST_VALUE(), LAST_VALUE(), CUME_DIST()
    -- 키 순서대로 내림차순 정렬 후 다음 사람과 키 차이를 조회
    SELECT NAME, addr, height,
    		 height - LEAD(height, 1) OVER(ORDER BY height DESC) FROM usertbl;
    		 
    -- 키 순서대로 내림차순 정렬 후 이전 사람과 키 차이를 조회
    SELECT NAME, addr, height,
    		 height - LAG(height, 1) OVER(ORDER BY height DESC) FROM usertbl;
    		 
    -- 지역별로 가장 키가 큰 사람과의 키 차이를 조회
    SELECT addr, NAME, height,
    		 FIRST_VALUE(height) OVER(PARTITION BY addr ORDER BY height DESC) - height AS 'diff' 
             FROM usertbl;

     

    > 조인(JOIN)과 UNION 연산자(1)

    /*
    * 조인(JOIN)
    */
    -- #내부 조인(INNER JOIN)
    -- 각 사원들의 사번, 직원명, 부서 코드, 부서명을 조회
    SELECT emp_id, emp_name, dept_code, b.dept_title
    FROM employee a INNER JOIN department b ON a.dept_code = b.dept_id;
    
    -- 각 사원들의 사번, 직원명, 직급 코드, 직급명을 조회
    SELECT emp_id, emp_name, a.job_code, b.job_name
    FROM employee a INNER JOIN job b ON a.job_code = b.job_code
    WHERE b.job_name = '대리';
    
    -- #자연 조인(NATURAL JOIN) - 참고!
    
    SELECT emp_id, emp_name, job_code, job_name
    FROM employee NATURAL JOIN job;
    
    /*
    * 연습문제
    */
    -- usertbl 테이블과 buytbl 테이블을 조인하여
    -- JPY라는 아이디를 가진 회원의 이름, 주소, 연락처, 주문 상품 이름을 조회
    SELECT NAME, addr, CONCAT(mobile1, mobile2) AS mobile, b.prodName
    FROM usertbl a INNER JOIN buytbl b ON a.userID = b.userID
    WHERE a.userID = 'JYP';
    
    -- employee 테이블과 department 테이블을 조인하여
    -- 보너스를 받는 사원들의 사번, 직원명, 보너스, 부서명을 조회
    SELECT emp_id, emp_name, bonus, b.dept_title
    FROM employee a LEFT OUTER JOIN department b ON a.dept_code = b.dept_id
    WHERE bonus IS NOT NULL;
    
    -- employee 테이블과 department 테이블을 조인하여
    -- 인사관리부가 아닌 사원들의 직원명, 부서명, 급여를 조회
    SELECT emp_name, b.dept_title, salary
    FROM employee a LEFT OUTER JOIN department b ON a.dept_code = b.dept_id
    WHERE dept_code != 'D1' OR dept_code IS NULL;
    -- where문에서는 NULL <> 1이 true로 평가되지 않으므로 where문의 결과값에서 필터링됨
    
    -- employee 테이블과 department 테이블, job 테이블을 조인하여
    -- 사번, 직원명, 부서명, 직급명 조회
    SELECT emp_id, emp_name, b.dept_title, c.job_name
    FROM employee a LEFT OUTER JOIN department b ON a.dept_code = b.dept_id
    					 LEFT OUTER JOIN job c ON a.job_code = c.job_code;