카테고리 없음

[ DBMS - 7일차 ]

pulttaegi 2026. 5. 23. 13:08
반응형

1. 예시 문제

문제 정답 및 실행순서
1)
EMPLOYEE테이블에서 JOB_ID별 기준으로 평균연봉이 1억 미만인 직급과 평균 연봉을 조회하여라. 단, 조회 시 평균연봉을 기준으로 오름차순 정렬한다. (EMPLOYEES테이블)

④ SELECT
JOB_ID, AVG(SALARY

① FROM EMPLOYEES         
➁ GROUP BY JOB_ID         
③ HAVING AVG(SALARY) < 10000
⑤ ORDER BY AVG(SALARY) ASC;
2)
PLAYER ID가 2007로 시작하는 선수들 중 POSITION별 평균 키를 조회하여라.
(PLAYER테이블)


④ SELECT
"POSITION" 포지션, ROUND(AVG(HEIGHT),2) "평균 키"

① FROM PLAYER
➁ WHERE PLAYER_ID LIKE '2007%'
③ GROUP BY "POSITION";
3)
PLAYER테이블에서 포지션이 DF인 선수들 중 TEAM_ID를 기준으(별)로 평균 키를 조회하고, 오름차순을 적용하시오.

④ SELECT
TEAM_ID, AVG(HEIGHT) AS "평균키"

① FROM PLAYER
➁ WHERE "POSITION" = 'DF'
③ GROUP BY TEAM_ID
⑤ ORDER BY "평균 키";
4)
EMPLOYEES테이블에서 평균연봉이 가장 높은 순서대로 조회한다. 단, 수수료 (COMMISSION_PCT)별로 평균 연봉을 조회하고, 수수료 (COMMISSION_PCT)가 없는 직원은 제외한다. (즉, 수수료가 없는 직원은 제외하고 평균연봉을 조회)

④ SELECT
COMMISSION_PCT, AVG(SALARY)

① FROM EMPLOYEES
➁ GROUP BY COMMISSION_PCT
③ HAVING COMMISSION_PCT IS NOT NULL
⑤ ORDER BY AVG(SALARY) DESC;

~별로 : 그룹으로 묶는다

2. 서브쿼리(Sub Query) ★

- 하나의 쿼리 내에 작성하는 또 다른 쿼리문

- 또 다른 쿼리는 별도로 정상 실행 가능

- 서브 쿼리는 크게 3가지 종류가 존재함 

종류 설명 및 예시
1. FROM 절 IN LINE VIEW 

[ 문제 ] PLAYER테이블에서 TEAM_ID가 'K04'인 선수 중 POSITION이 'GK'인 선수를 조회하기. (서브쿼리 사용)

방법 1
SELECT
*

FROM PLAYER
WHERE TEAM_ID = 'K04' AND "POSITION" = 'GK';

방법 2
SELECT *
FROM (SELECT * FROM PLAYER WHERE TEAM_ID = 'K04')
WHERE "POSITION" = 'GK';


소괄호 부분이 먼저 실행되고, 이 부분만 단독으로 실행하는 것도 가능함
SELECT * FROM PLAYER WHERE TEAM_ID = 'K04'
2. SELECT 절 SCALA
- 리턴(결과 값)무조건 단일 값이어야함.

SELECT EMPLOYEE_ID, FIRST_NAME, SALARY,
(SELECT AVG(SALARY) FROM EMPLOYEES) AS AVG
FROM EMPLOYEES;


마찬가지로 소괄호 부분만 단독 실행하는 것도 가능함
SELECT AVG(SALARY) FROM EMPLOYEES;
3. WHERE 절 SUB QUERY

SELECT *
FROM PLAYER
WHERE WEIGHT > (SELECT AVG(WEIGHT) FROM PLAYER);

 

[ 추가 서브쿼리 방법 ]

- INSERT문의 컬럼 수와 SELECT문의 컬럼 수는 반드시 동일해야함

- INSERT문의 컬럼과 SELECT절의 컬럼의 데이터 TYPE이 동일해야함

- SELECT절에 기술된 컬럼이 INSERT문에 기술된 컬럼의 순서대로 입력됨

구분 예시 및 설명
방법 1
CREATE TABLE TBL_SUB_TEST AS
SELECT * FROM EMPLOYEES WHERE SALARY > 20000;


SELECT * FROM TBL_SUB_TEST;
방법 2
CREATE TABLE TBL_MEMBER100(
                MEMBER_AGE NUMBER,
                MEMBER_NAME VARCHAR2(100),
                MEMBER_PRICE NUMBER);
INSERT INTO TBL_MEMBER100(MEMBER_AGE, MEMBER_NAME, MEMBER_PRICE)
SELECT EMPLOYEE_ID, LAST_NAME, SALARY, FROM EMPLOYEES
WHERE SALARY > 15000;

 

[ 서브 쿼리 예시 문제 ]

문제 정답 및 설명
사전 작업
CREATE TABLE TBL_MEMBER3(
                MEMBER_NUMBER NUMBER,
                 MEMBER_DPT VARCHAR2(1000),
                 MEMBER_NAME VARCHAR2(1000),
                 MEMBER_AGE NUMBER,
                 MEMBER_GENDER char(2),
                 MEMBER_SALARY NUMBER );

INSERT INTO TBL_MEMBER3(
                        MEMBER_NUMBER,
                        MEMBER_DPT,
                        MEMBER_NAME,
                        MEMBER_AGE,
                        MEMBER_GENDER,
                        MEMBER_SALARY)
VALUES(1, 'IT', '홍길동', 20, 'M',5000);
VALUES(2, '인사팀', '둘리', 30, 'M',6000);
VALUES(3, '안전팀', '또치', 40, 'W',7000);

SELECT * FROM TBL_MEMBER3;
문제#1).  [ PLAYER 테이블에서 박상수 선수가 소속된 팀 선수들 조회 ]

SELECT PLAYER FROM PLAYER
WHERE TEAM_ID = (SELECT TEAM_ID FROM PLAYER WHERE PLAYER_NAME = '박상수');

SELECT TEAM_ID FROM PLAYER WHERE PLAYER_NAME = '박상수';
문제#2).  [ PLAYER테이블에서 NICKNAME이 NULL인 선수들을 박상수 선수의 닉네임으로 변경하기 ]

UPDATE PLAYER
SET NICKNAME = (SELECT NICKNAME FROM PLAYER WHERE PLAYER_NAME = '박상수')
WHERE NICKNAME IS NULL;
문제#3).  [ SCHEDULE 테이블에서 경기 일정이 20120501 ~ 20120502 사이에 있는 경기장(STADIUM)의 정보를 모두 조회 ]
SELECT * FROM STADIUM
WHERE STADIUM_ID IN(SELECT STADIUM_ID FROM SCHEDULE
                                           WHERE SCHE_DATE BETWEEN '20120501' AND '20120502');

SELECT STADIUM_ID FROM SCHEDULE
                                      WHERE SCHE_DATE BETWEEN '20120501' AND '20120502';

SELECT * FROM SCHEDULE;
문제#4). 조건#1). TBL_MEMBER3 테이블에서 ‘둘리’ 직원이 사고를 쳐서 연봉 조건을 수정
조건#2). ‘둘리’의 연봉은 수수료(commisstion_pct) 없는 대신에 “최저연봉”에 따른 지급 조건으로 재계약을 체결
기타 조건 사항
  - ‘둘리’의 연봉이 삭감.
  - ‘둘리’는 수수료(가) 없는 상태. (IS NULL)
  - 최저연봉은 EMPLOYEES테이블에서 가장 낮은 직원의 연봉으로 반영.

UPDATE TBL_MEMBER3
SET MEMBER_SALARY = (2100)
WHERE MEMBER_NAME = '둘리';

-- 아래처럼 가장 낮은 연봉 값을 조회하고 서브쿼리에 넣음
-- 2,100만원이 나옴
SELECT MIN(SALARY)
FROM EMPLOYEES
WHERE COMMISSION_PCT IS NULL;
문제#5).  [ TBL_MEMBER3에 입사한 또치의 이름이 잘못 입력되었다. (서브쿼리 이용)
확인을 해보니, EMPLOYEES테이블에 존재하는 직원 중 Lex라는 성을 가진 이름과 동일한 이름인 것으로 확인됨
Lex성을 가진 직원의 이름으로 변경해라 ]
- 데이터 값의 대소문자 명확하게 구분 해줘야함
      
UPDATE TBL_MEMBER3
SET MEMBER_NAME = (SELECT LAST_NAME FROM EMPLOYEES WHERE FIRST_NAME = 'Lex')
WHERE MEMBER_NAME = '또치';

혹은

UPDATE TBL_MEMBER3
SET MEMBER_NAME = ('De Haan')
WHERE MEMBER_NAME = '또치';

SELECT LAST_NAME FROM EMPLOYEES WHERE FIRST_NAME = 'Lex';
문제#6).  [ EMPLOYEES테이블에서 연봉 1 ~ 5위까지 조회 ]

방법 1: 원하는 데이터 값이 안나옴)
-- 전체 데이터를 구할때 전체 컬럼은 오류가 발생함. 테이블을 명시해줘야함
SELECT ROWNUM, E.* --> 핵심
FROM EMPLOYEES E
ORDER BY SALARY DESC; --> 핵심
⇒ FROM EMPLOYEES: 일단 직원 테이블에서 데이터를 마구잡이(가장 먼저 찾아지는 순서)로 가져옵니다.
  SELECT ROWNUM, E.*: 정렬도 안 된 무작위 데이터 상태에서 위에서부터 차례대로 ROWNUM 번호(1, 2, 3...)를 임의로 쾅쾅 찍어버립니다.
  ORDER BY SALARY DESC: ROWNUM 번호가 이미 다 매겨진 결과물을 가지고, 그제서야 연봉(SALARY) 높은 순으로 뒤섞어서 정렬합니다.

======================================================================================

방법 2: 원하는 데이터 값 출력

-- 서브쿼리를 이용해 선작업을 하고 메인작업을 해주면 효율적으로 문제 해결이 가능함
SELECT ROWNUM, E.* --> 핵심
FROM EMPLOYEES E

SELECT ROWNUM, E.*
FROM (SELECT * FROM EMPLOYEES ORDER BY SALARY DESC) E
WHERE ROWNUM <= 5;

======================================================================================

[ 서브쿼리는 메인쿼리에 접근 불가능 ]

-------------------------------------------------------------------------------------------------------------------------------------------------------
[ 메인쿼리는 서브쿼리에 접근이 가능 ]

3. 뷰(VIEW) = 가상 테이블

- 기본 테이블을 보존한 상태로 필요한 컬럼 및 새로운 컬럼을 만든 가상테이블

- 실제 데이터가 저장되는 공간은 아님

- VIEW를 통해 데이터만을 조 가능

( 필요 정보를 별도로 조회할때 사용)

특징 설명
A 독립성: 다른 곳에서 원본 테이블에 접근하지 못하도록 하는 성질
B 편리성: 긴 쿼리문을 짧게 만드는 성질
C 보안성: 기존 쿼리문이 보여지지 않음
예시
SELECT P.*, ROUND((SYSDATE-BIRTH_DATE)/365) AS "나이"
FROM PLAYER P;

CREATE VIEW VIEW_PLAYER AS
SELECT P.*, ROUND((SYSDATE-BIRTH_DATE)/365) AS "나이"
FROM PLAYER P;

SELECT * FROM VIEW_PLAYER;

지정된 쿼리문을 실행하며 가상의 테이블을 만듬
⇨ 정의한 SELECT ... FROM PLAYER P라는 쿼리문(정의) 자체만 데이터베이스에 저장해 두는 것
사용자가 이 뷰를 호출할 때마다, 데이터베이스 엔진이 내부적으로 원본 테이블(PLAYER)에 접근해 실시간으로 데이터를 가져오는 가상의 창문(Window) 역할을 함 

방대한 양의 쿼리문을 짧게 만듬 (편리성)
⇨ 복잡한 로직을 VIEW_PLAYER라는 이름 하나로 꽁꽁 캡슐화해 두었기 때문에, 개발자는 복잡한 내부 구현을 몰라도 단 한 줄(SELECT * FROM VIEW_PLAYER;)로 아주 편리하게 데이터를 조회할 수 있음

지정된 것만 조회하게 만들 수 있음 (보안성)
⇨ 보여줘도 괜찮은 컬럼(이름, 포지션, 계산된 나이 등)만 쏙 골라서 정의해 두면, 외부 사용자에게 원본 테이블에 대한 직접적인 접근 권한을 주지 않고도 필요한 데이터만 안전하게 제공 가능함

 

[ 뷰 예시 문제 ]

MF인 포지션 중 키가 180인 이상인 선수에 대하여, 이름과 키를 조회하는 뷰를 생성해라

구분 정답 및 설명
예시
CREATE VIEW VIEW_PLAYER_HEIGHT AS
SELECT PLAYER_NAME, HEIGHT
FROM PLAYER
WHERE "POSITION" = 'MF' AND HEIGHT >=180;


SELECT * FROM VIEW_PLAYER_HEIGHT;

4. EXISTS 연산자

- 서브쿼리의 결과 값에 적어도 하나 이상의 행이 존재하는지 확인함

- 서브쿼리의 결과가 존재하면 TRUE, 아니면 FALSE

- 서브쿼리의 결과 집합에 단 하나의 행만 존재해도 TRUE

- 서브쿼리의 SELECT 절에 어떤 열을 지정하는지는 중요하지 않음

보통 SELECT * 또는 SELECT 1 사용


5. DECODE 함수

- 특정 값을 다른 값으로 변환하는데 사용함

- DECODE(원본 데이터, 검색 데이터, 변환 데이터1, 검색 데이터2, 변환데이터2..., [default])

구분 설명
예시
SELECT EMPLOYEE_ID, FIRST_NAME,
               DECODE(JOB_ID, 'IT_PROG', '프로그래머',
                                'SA_REP', '영업사원'
                                'FI_ACCOUNT', '회계사',
                                '기타') AS JOB_TITLE
FROM EMPLOYEES;

 

[ DECODE 예시 문제 ]

구분 정답 및 설명
문제#1). `employees` 테이블에서 `salary` 값에 따라 다음과 같이 직원 등급을 변환하여 출력하는 쿼리를 작성.
- 20000  : '고급'
- 10000 : '중급'
- 나머지 : ‘추가 확인 필요'

SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, SALARY,
               DECODE(SALARY, 20000, '고급CASE',
                                               10000, '중급'
                                                '추가 확인 필요') AS EMPLOYEE_LEVEL
FROM EMPLOYEES;
문제#2). DEPARTMENTS 테이블에서 `LOCATION_ID` 값을 다음과 같이 도시이름으로 변환하여 출력하는 쿼리를 작성하세요.
- 1000: 'Seattle'
- 1700: 'Chicago'
- 2400: 'London'
- 나머지: 'Other'

-- 데이터 값은 대소문자 구별함
SELECT DEPARTMENT_ID, DEPARTMENT_NAME, LOCATION_ID,
               DECODE(LOCATION_ID,1000,'Seattle',
                                                         1700, 'Chicago',
                                                         2400, 'London',
                                                         'Other') AS LOCATION_NAME
FROM DEPARTMENTS;

컬럼의 개수와 데이터 타입은 반드시 동일해야함

 

반응형