
SQLD 벼락치기 기억이 새록새록..^^.. 게시판 베스트 게시글 조건 변경해본다고 Raw data 백엔드에서 받아서 MySQL로 점수 계산해보던 기억도 새록새록..^^.. 서브쿼리 문제 풀 때 도대체 먼소리? 했었는데 과정 보니까 복잡할 수밖에.. 낼 바로 시험인디 언제 다시 보지 ㅎ
CREATE TABLE TIME_TEST(
NO NUMBER UNIQUE NOT NULL,
WHEN DATE NOT NULL
);
-- '시간 표시 방식이 맞으면' 문자열을 바로 추가할 수 있지만 비추천
INSERT INTO TIME_TEST(NO, WHEN) VALUES(1, '2022-08-23');
-- TO_DATE('문자열', '형식정보')를 통해 문자열을 날짜 데이터로 변환 가능
INSERT INTO TIME_TEST(NO, WHEN) VALUES(2, TO_DATE('2022-08-23', 'YYYY-MM-DD'));
-- TO_DATE('문자열', '형식정보')를 통해 문자열을 날짜 데이터로 변환 가능
INSERT INTO TIME_TEST(NO, WHEN) VALUES(2, TO_DATE('2022-08-23', 'YYYY-MM-DD'));
INSERT INTO TIME_TEST(NO, WHEN) VALUES(3, TO_DATE('2022-08-23', 'yyyy-mm-dd'));
-- 현재 시각은 SYSDATE로 확인
INSERT INTO TIME_TEST(NO, WHEN) VALUES(4, SYSDATE);
INSERT INTO TIME_TEST(NO, WHEN) VALUES(5, SYSDATE + 365); -- 1년 뒤
SELECT * FROM TIME_TEST;
SELECT NO, TO_CHAR(WHEN, 'YYYY-MM-DD HH24:MI:SS') FROM TIME_TEST;
-- 오라클 시간(분): MI
-- SYSDATE로 삽입한 데이터만 시/분/초 정보가 출력됨(기본값: 00:00:00)
NOT NULL + UNIQUE 포함)외래키 관련 개념)후보키 중 택1 → 나머지 후보키는 보조키(대체키)가 됨CREATE TABLE PLAYER(
PLAYER_ID VARCHAR2(30) PRIMARY KEY,
PLAYER_JOB VARCHAR2(12) NOT NULL,
PLAYER_LEVEL NUMBER DEFAULT 1 NOT NULL
);
CREATE TABLE EXAM(
YEAR NUMBER,
ROOM NUMBER,
NO NUMBER,
NAME VARCHAR2(21),
-- YEAR+ROOM+NO로 PK 설정(복합키)
PRIMARY KEY(YEAR, ROOM, NO)
);
SELECT 컬럼1, 컬럼2,... FROM 테이블 [WHERE 조건] -- 일부 항목 조회
SELECT * FROM 테이블 -- 전체 조회
결과 집합(RESULT SET)을 출력하는 것= 등호 하나만 사용-- Q. 2000원 이하의 상품만 조회
SELECT * FROM PRODUCT WHERE PRICE <= 2000;
-- Q. 1000원 이상 2000원 이하의 상품만 조회
SELECT * FROM PRODUCT WHERE PRICE BETWEEN 1000 AND 2000;
-- Q. 1000원인 상품만 조회
SELECT * FROM PRODUCT WHERE PRICE = 1000;
-- Q. 1000원이 아닌 상품만 조회
SELECT * FROM PRODUCT WHERE PRICE != 1000;
SELECT * FROM PRODUCT WHERE PRICE <> 1000;
-- Q. 과자만 조회
SELECT * FROM PRODUCT WHERE TYPE = '과자';
-- Q. 아이스크림과 과자만 조회
SELECT * FROM PRODUCT WHERE TYPE = '과자' OR TYPE = '아이스크림';
SELECT * FROM PRODUCT WHERE TYPE IN ('과자', '아이스크림');
문자열 유사검색 시, 시작 검사는 LIKE / 나머지는 INSTR() 사용 권장
LIKE : %를 '있어도 되고 없어도 되는 값'으로 인식
-- Q. '바'로 시작하는 상품 조회
SELECT * FROM PRODUCT WHERE NAME LIKE '바%';
-- Q. '바'가 포함된 상품 조회
SELECT * FROM PRODUCT WHERE NAME LIKE '%바%';
-- Q. '바'로 끝나는 상품 조회
SELECT * FROM PRODUCT WHERE NAME LIKE '%바';
INSTR : 지정한 글자가 항목의 몇 번째에 위치하는지 반환(1부터 시작)-- Q. '바'로 시작하는 상품 조회
SELECT * FROM PRODUCT WHERE INSTR(NAME, '바') = 1;
-- Q. '바'가 포함된 상품 조회
SELECT * FROM PRODUCT WHERE INSTR(NAME, '바') > 0;
-- Q. '바'로 끝나는 상품 조회
SELECT * FROM PRODUCT WHERE INSTR(NAME, '바') = LENGTH(NAME);
EXTRACT : 날짜에서만 사용 가능-- Q. 제조년도가 2020년이 상품 조회
SELECT * FROM PRODUCT WHERE EXTRACT(YEAR FROM MADE) = 2020;
-- Q. 여름에 생산한 제품 조회
-- [방법1] EXTRACT를 한 번만 사용하는 첫 번째 방법이 성능이 좋음
SELECT * FROM PRODUCT WHERE EXTRACT(MONTH FROM MADE) IN (6, 7, 8);
-- [방법2] OR
SELECT * FROM PRODUCT
WHERE EXTRACT(MONTH FROM MADE) = 6
OR EXTRACT(MONTH FROM MADE) = 7
OR EXTRACT(MONTH FROM MADE) = 8;
-- [방법3] BETWEEN
SELECT * FROM PRODUCT
WHERE EXTRACT(MONTH FROM MADE) BETWEEN 6 AND 8;
-- [방법4] 지정한 날짜 형식에 따라 다양하게 활용 가능
SELECT * FROM PRODUCT
WHERE TO_CHAR(MADE, 'MM') IN ('06', '07', '08');
-- [방법5] LIKE% 성능 저하 이슈
SELECT * FROM PRODUCT
WHERE MADE LIKE '%/06/%'
OR MADE LIKE '%/07/%'
OR MADE LIKE '%/08/%';
-- [방법6] REGEX 성능 저하 이슈
SELECT * FROM PRODUCT
WHERE REGEXP_LIKE(TO_CHAR(MADE, 'MM'), '(06|07|08');
-- 2019년 6월 1일부터 2019년 8월 31일까지 조회
-- [방법1] 비교연산자
SELECT * FROM PRODUCT
WHERE MADE >= TO_DATE('2019-06-01 00:00:00', 'YYYY-MM-DD HH24:MI:DD')
AND MADE <= TO_DATE('2019-08-31 23:59:59', 'YYYY-MM-DD HH24:MI:DD');
-- [방법2] BETWEEN
SELECT * FROM PRODUCT
WHERE MADE BETWEEN TO_DATE('2019-06-01 00:00:00', 'YYYY-MM-DD HH24:MI:DD')
AND TO_DATE('2019-08-31 23:59:59', 'YYYY-MM-DD HH24:MI:DD');
정렬: 원하는 기준에 맞게 재배치 하는 것
오름차순(ASCENDING, ASC) / 내림차순(DESCENDING, DSC)
키워드로 정렬 수행
정렬 기준 여러 개 설정 가능
ORDER BY 컬럼명(OR 별칭) ASC; -- 오름차순
ORDER BY 컬럼명(OR 별칭) DESC; -- 내림차순
SELECT * FROM PRODUCT
ORDER BY NO ASC;
-- Q. 가격이 저렴한 상품 순으로 출력
SELECT * FROM PRODUCT
ORDER BY PRICE ASC;
-- Q. 가격이 비싼 상품 순으로 출력
SELECT * FROM PRODUCT
ORDER BY PRICE DESC, NO ASC; -- 같은 가격이면 번호순(PK를 마지막에)
" "로 묶어줘야 함SELECT 테이블.*, 컬럼 별칭 FROM 테이블
-- Q. 유통기한이 짧은 순으로 출력
SELECT PRODUCT.*, EXPIRE-MADE "유통기한" FROM PRODUCT
ORDER BY "유통기한" ASC;
가장 마지막에 위치해야 함SELECT 1234+5678 FROM DUAL;
-- ASCII 코드를 문자로 변환
SELECT CHR(65) FROM DUAL;
-- ASCII 코드를 숫자로 변환
SELECT ASCII('A') FROM DUAL;
-- 문자열 소문자화
SELECT LOWER('HELLO') "결과" FROM DUAL;
SELECT PRODUCT.*, LOWER(NAME) "소문자" FROM PRODUCT;
-- 문자열 인덱스 기준으로 자르기
SELECT PRODUCT.*, SUBSTR(NAME, 1, 1) "첫글자" FROM PRODUCT;
-- SELECT PRODUCT.*, SUM(PRICE) FROM PRODUCT;
SELECT SUM(PRICE) "합계" FROM PRODUCT;
SELECT AVG(PRICE) "평균" FROM PRODUCT;
SELECT MAX(PRICE) "최대" FROM PRODUCT;
SELECT MIN(PRICE) "최소" FROM PRODUCT;
SELECT COUNT(PRICE) "개수" FROM PRODUCT;
-- Q. 가장 비싼 상품의 이름을 출력
-- SELECT NAME FROM PRODUCT WHERE PRICE = MAX(PRICE);
SELECT MAX(PRICE) FROM PRODUCT; -- 3000
SELECT NAME FROM PRODUCT WHERE PRICE = 3000; -- 초코파이
-- 서브쿼리로 구문 통합
SELECT NAME FROM PRODUCT WHERE PRICE = (
SELECT MAX(PRICE) FROM PRODUCT
);
-- [공식]
SELECT * FROM (
SELECT TMP.*, ROWNUM RN FROM(
원하는 데이터 조회, 필터 및 정렬 구문
)TMP
)WHERE RN BETWEEN 시작행번호 AND 종료행번호;
[문제점1] SQL문 실행 순서에 따라 조회 결과에서 ROWNUM이 1부터 시작하지 않을 수 있음
- 실행 순서: FROM - WHERE - SELECT - ORDER BY
- 원인: ROWNUM이 SELECT절에서 먼저 생성된 후에 정렬이 됨
- 해결: SELECT절을 ORDER BY절보다 나중에 실행하기 위해 구문을 의도적으로 분해
-- 문제1
SELECT PRODUCT.*, ROWNUM FROM PRODUCT WHERE ROWNUM <= 3 ORDER BY PRICE DESC;
-- 해결1
SELECT TMP.*, ROWNUM FROM(
SELECT * FROM PRODUCT ORDER BY PRICE DESC
)TMP WHERE ROWNUM <= 3;
[문제점2] ROWNUM 조건에 1이 포함되어 있지 않으면 데이터 조회 결과가 없음
원인: ROWNUM은 반드시 1부터 부여하도록 되어 있음. 번호를 부여하면서 조건을 처리하고 있기 때문에 조건에 해당하지 않는 결과는 바로바로 제거됨
해결: 번호 부여를 먼저하고 조건을 나중에 처리
-- 문제2
SELECT TMP.*, ROWNUM FROM(
SELECT * FROM PRODUCT ORDER BY PRICE DESC
)TMP WHERE ROWNUM BETWEEN 3 AND 5;
-- 해결
-- SELECT * FROM (1차 완성 구문) WHERE ROWNUM BETWEEN 3 AND 5;
SELECT * FROM (
SELECT TMP.*, ROWNUM FROM(
SELECT * FROM PRODUCT ORDER BY PRICE DESC
)TMP
)WHERE ROWNUM BETWEEN 3 AND 5;
원인: ROWNUM은 SELECT절 개수만큼 생성됨
해결: 어떤 ROWNUM에 대한 조건인지 지정해줘야 함 → 별칭 설정
SELECT * FROM (
SELECT TMP.*, ROWNUM RN FROM(
SELECT * FROM PRODUCT ORDER BY PRICE DESC
)TMP
)WHERE RN BETWEEN 3 AND 5;
최고👍