Humility

아무리 노력해도 최고가 되지 못할 수 있다⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀그럼에도 노력하는자가 가장 겸손한 것 아닌가

공부하는 블로그

자격증/SQL

오답노트 ( SQL 활용_1 )

새벽_글쓴이 2025. 5. 20. 00:00
반응형

1️⃣집합 연산자에 대한 설명으로 가장 적절하지 않은 것은?

  1. UNION 연산자는 합집합 결과에서 중복된 행을 하나의 행으로 만든다
  2. UNION ALL 연산자는 집합 간의 결과가 중복되지 않는 경우, UNION과 결과가 동일하다
  3. UNION 연산자를 사용한 SQL은 각각의 집합에 GROUP BY절을 사용할 수 있다
  4. UNION 연산자를 사용한 SQL은 각각의 집합에 ORDER BY절을 사용할 수 있다
더보기

4

해설

집합 연산자를 사용한 SQL의 ORDER BY 절은 최종 결과를 정렬하며, 가장 마지막 줄에 한번만 사용할 수 있다


2️⃣ 아래를 참고할 때 SQL 실행 결과로 가장 적절한 것은?

[TBL1]

COL1 COL2
AA A1
AB A2

 

[TBL2]

COL1 COL2
AA A1
AB A2
AC A3
AD A4
SELECT COL1, COL2, COUNT(*) AS CNT
FROM (SELECT COL1, COL2
			FROM TBL1
			UNION ALL
			SELECT COL1, COL2
			FROM TBL2
			UNION
			SELECT COL1, COL2
			FROM TBL1)
GROUP BY COL1, COL2;

 

1.

 

COL1 COL2 CNT
AA A1 1
AB A2 1
AC A3 1
AD A4 1

 

2.

COL1 COL2 CNT
AA A1 2
AB A2 2
AC A3 1
AD A4 1

 

3.

COL1 COL2 CNT
AA A1 3
AB A2 3
AC A3 1
AD A4 1

 

4.

COL1 COL2 CNT
AA A1 3
AB A2 3
AC A3 2
AD A4 2
더보기

정답

1

 

해설

  • 만약 UNION과 UNION ALL의 순서를 바꾼다면 2번과 같은 형태로 나타난다
  • SQL에서 위에 정의된 연산자가 먼저 수행된다. UNION 연산자가 실행되면 중복된 행을 하나로 만들기 때문에 1번으로 나타난다

4️⃣ 💡아래의 SQL과 실행 결과가 다른 하나는?

[테이블 생성]
CREATE TABLE T1 (NO NUMBER, COLA VARCHAR2(10));

INSERT INTO T1 VALUES (1,'AAA');

CREATE TABLE T2 (NO NUMBER, COLB VARCHAR2(10));

INSERT INTO T2 VALUES (1, 'BBB');
INSERT INTO T2 VALUES (3, 'CCC');

COMMIT;

[SQL]
SELECT A.NO, A.COLA, B.COLB
FROM T1 A, T2 B
WHERE B.NO = A.NO;
  1. SELECT A.NO, A.COLA, B.COLB FROM T1 A INNER JOIN T2 B ON B.NO = A.NO;
  2. SELECT NO, A.COLA, B.COLB FROM T1 A JOIN T2 B USING (NO);
  3. SELECT A.NO, A.COLA, B.COLB FROM T1 A CROSS JOIN T2 B;
  4. SELECT NO, A.COLA, B.COLB FROM T1 A NATURAL JOIN T2 B;
더보기

3

해설

USING과 NATURAL JOIN은 기본적으로 INNER JOIN 이기 때문이다

INNER JOIN은 조인 조건이 일치하는 행만 결과에 포함하고,

조건이 성립되지 않거나 NULL이 관련된 행은 포함되지 않습니다.

5️⃣💡 WINDOW FUNCTION을 사용하지 않고 아래의 실행 결과를 출력하는 SQL로 가장 적절한 것은?

[일자별매출] [실행결과]

일자 매출액
2015.11.01 1000
2015.11.02 1000
2015.11.03 1000
2015.11.04 1000
2015.11.05 1000
2015.11.06 1000
2015.11.07 1000
2015.11.08 1000
2015.11.09 1000
2015.11.10 1000

 

[실행결과]

일자 누적매출액
2015.11.01 1000
2015.11.02 2000
2015.11.03 3000
2015.11.04 4000
2015.11.05 5000
2015.11.06 6000
2015.11.07 7000
2015.11.08 8000
2015.11.09 9000
2015.11.10 10000
  1. SELECT A.일자, SUM(A.매출액) AS 누적매출액 FROM 일자별매출 A GROUP BY A.일자 ORDER BY A.일자;
  2. SELECT B.일자, SUM(B.매출액) AS 누적매출액 FROM 일자별매출 A JOIN 일자별매출 B ON (A.일자 ≥ B.일자) GROUP BY B.일자 ORDER BY B.일자;
  3. SELECT A.일자, SUM(B.매출액) AS 누적매출액 FROM 일자별매출 A JOIN 일자별매출 B ON (A.일자 ≥ B.일자) GROUP BY A.일자 ORDER BY A.일자;
  4. SELECT A.일자, (SELECT SUM(B.매출액) FROM 일자별매출 B WHERE B.일자 ≥ A.일자) AS 누적매출액 FROM 일자별매출 A GROUP BY A.일자 ORDER BY A.일자;
더보기

3

해설

1번: 일자별매출이랑 똑같이 출력됨 2번,4번: 작은날짜에 높은금액으로 출력됨

SELECT B.일자, SUM(B.매출액)
FROM A JOIN B ON A.일자 ≥ B.일자
GROUP BY B.일자

6️⃣ 아래의 SQL의 실행 결과로 가장 적절한 것은?

[사원]

사원번호 사원명 입사일자 매니저사원번호
001 홍길동 2012-01-01 NULL
002 강감찬 2012-0101 001
003 이순신 2013-01-01 001
004 이민정 2013-01-01 001
005 이병헌 2013-01-01 NULL
006 안성기 2014-01-01 005
007 이수근 2014-01-01 005
008 김병만 2014-01-01 005
SELECT 사원번호, 사원명, 입사일자, 매니저사원번호
FROM 사원
START WITH 매니저사원번호 IS NULL
CONNECT BY PRIOR 사원번호 = 매니저사원번호
AND 입사일자 BETWEEN '2013-01-01' AND '2013-12-31'
ORDER SIBLINGS BY 사원번호;

 

1.

 

사원번호 사원명 입사일자 매니저사원번호
001 홍길동 2012-01-01 NULL
003 이순신 2013-01-01 001
004 이민정 2013-01-01 001
005 이병헌 2013-01-01 NULL

 

2.

사원번호 사원명 입사일자 매니저사원번호
003 이순신 2013-01-01 001
004 이민정 2013-01-01 001
005 이병헌 2013-01-01 NULL

 

3.

사원번호 사원명 입사일자 매니저사원번호
001 홍길동 2012-01-01 NULL

 

4.

사원번호 사원명 입사일자 매니저사원번호
001 홍길동 2012-01-01 NULL
005 이병헌 2013-01-01 NULL
006 안성기 2014-01-01 005
007 이수근 2014-01-01 005
008 김병만 2014-01-01 005
더보기

1

해설

왜 홍길동(001)이 포함되는가?

START WITH 매니저사원번호 IS NULL
CONNECT BY PRIOR 사원번호 = 매니저사원번호
AND 입사일자 BETWEEN '2013-01-01' AND '2013-12-31'
  • 이 구조에서 `입사일자 조건은 자식 노드에게만 적용됩니다.
  • 즉, 자식 노드가 이 조건을 만족해야 연결이 이루어짐
  • 하지만 루트 노드(홍길동, 사원번호 001)는 탐색의 출발점이기 때문에 이 조건에 영향받지 않습니다

홍길동(001)이 제외되지 않은 이유는 CONNECT BY 조건은 "연결 여부"만 통제하고,

출력 대상 필터링WHERE 절에서만 가능합니다.


7️⃣아래에서 서브쿼리에 대한 설명으로 적절한 것을 모두 고른 것은?

(가) 서브쿼리는 단일 행 또는 복수 행 비교 연산자와 함께 사용할 수 있다

(나) 서브쿼리는 SELSECT 절, FROM 절 HAVING 절, ORDER BY 절 등에서 사용이 가능ㅎ다

(다) 서브쿼리의 결과가 복수 행 결과를 반환하는 경우에는 =,≤,≥ 등의 연산자와 함께 사용할 수 있다

(라) 연관 서브쿼리는 서브쿼리가 메인쿼리 칼럼을 포함하고 있는 형태의 서브쿼리이다

(마) 다중 칼럼 서브쿼리는 서브쿼리의 결과로 여러 개의 칼럼이 반환되어 메인쿼리의 조건과 동시에 비교되는 것을 의미하며 오라클 및 SQL 및 SQL Server 등의 DBMS에서 사용할 수 있다.

  1. 나,라,마
  2. 가,나,라
  3. 나,다,라
  4. 가,나,마
더보기

2

해설

(마) 다중 칼럼 서브쿼리는 서브쿼리의 결과로 여러 개의 칼럼이 반환되어 메인 쿼리의 조건과 비교되는데, SQL Server에서는 현재 지원하지 않는 기능이다

🔹 "다중 칼럼 서브쿼리"란?

  • 보통 튜플(tuple) 형태로 여러 칼럼을 한 번에 비교하는 (a, b) IN (SELECT x, y FROM ...) 같은 구문 자체를 말합니다.
  • 즉, 문법적으로 (컬럼1, 컬럼2) 형태로 동시에 비교하는 방식이 다중 칼럼 서브쿼리입니다.

예시

Oracle

SELECT *
FROM 사원
WHERE (부서ID, 직급) IN (
  SELECT 부서ID, 직급
  FROM 부서직급
);
  • Oracle에서는 (a, b) IN (SELECT x, y FROM ...) 구문이 자연스럽게 동작합니다.

SQL Server

-- EXISTS 예시
SELECT *
FROM 사원 A
WHERE EXISTS (
  SELECT 1
  FROM 부서직급 B
  WHERE A.부서ID = B.부서ID AND A.직급 = B.직급
);

-- JOIN 예시
SELECT A.*
FROM 사원 A
JOIN 부서직급 B
  ON A.부서ID = B.부서ID AND A.직급 = B.직급;

 

이런 방식은 "다중 칼럼을 동시에 비교하는 효과"는 있지만, 형식상 다중 칼럼 서브쿼리라고 부르지는 않는다


8️⃣ 아래 SQL에 대한 설명으로 가장 적절한 것은?

SELECT A.회원ID, A.회원명, A.이메일
FROM 회원 A
(ㄱ) WHERE EXISTS (SELECT 'X'
		FROM 이벤트 B, 메일발송 C
		WHERE B.시작일자 >= '2014.10.01'
		AND B.이벤트ID = C.이벤트ID
(ㄴ)	   AND A. 회원ID = C.회원ID
(ㄷ)	   HAVING COUNT(*) < (SELECT COUNT(*)
		FROM 이벤트
		WHERE 시작일자
		>= '2014.10.01'));
  1. 이벤트 시작일자가 ‘2014.10.01’과 같거나 큰 이벤트를 대상으로 이메일ㅇ리 발송된 기록이 있는 모든 회원을 추출하는 SQL이다
  2. (ㄴ)을 제거하고 (ㄱ)의 EXISTS 연사자를 IN 연산자로 변경해도 결과는 동일하다
  3. (ㄷ)은 이벤트 시작일자가 ‘2014.10.01’과 같거나 큰 이벤트건수와 그 이벤트드을 기준으로 회원별 이메일 발송건수를 비교하는 것이다
  4. GROUP BY 및 집계 함수를 사용하지 않고 HAVING절을 사용하였으므로 SQL이 실행되지 못하고 오류가 발생한다
더보기

3

① 이벤트 시작일자가 ‘2014.10.01’과 같거나 큰 이벤트를 대상으로 이메일이 발송된 기록이 있는 모든 회원을 추출하는 SQL이다.

→ ❌ 틀림

  • 이 SQL은 단순히 "발송 기록이 있는" 회원이 아니라,
  • "메일이 발송되지 않은 이벤트가 하나라도 있는 회원"을 찾는 쿼리입니다.

② (ㄴ)을 제거하고 (ㄱ)의 EXISTS 연산자를 IN 연산자로 변경해도 결과는 동일하다.

→ ❌ 틀림

  • (ㄴ)의 A.회원ID = C.회원ID 조건이 빠지면, 회원 개별 조건이 사라지기 때문에
  • 전혀 엉뚱한 결과가 나옵니다.
  • EXISTS → IN으로 바꾸면 회원별 비교가 불가능해집니다.

③ (ㄷ)은 이벤트 시작일자가 ‘2014.10.01’과 같거나 큰 이벤트 건수와 그 이벤트들을 기준으로 회원별 이메일 발송 건수를 비교하는 것이다.

→ ⭕

  • 정확한 설명입니다.
  • HAVING COUNT(*) < (SELECT COUNT(*)) 구문은
  • 전체 이벤트 수와 현재 회원이 받은 이벤트 메일 수를 비교하고 있습니다.

④ GROUP BY 및 집계 함수를 사용하지 않고 HAVING절을 사용하였으므로 SQL이 실행되지 못하고 오류가 발생한다.

→ ❌ 틀림

  • HAVING은 GROUP BY가 없어도 전체 결과를 하나의 그룹으로 보고 사용할 수 있습니다.
  • 따라서 이 SQL은 오류 없이 실행됩니다.

9️⃣ 서브쿼리에 대한 설명으로 가장 적절한 것은?

  1. 단일 행 서브쿼리는 서브쿼리의 실행 결과가 항상 한 건 이하인 서브쿼리로 IN, ALL 등의 비교 연산자를 사용하여야 한다
  2. 다중 행 서브쿼리 비교 연산자는 단일 행 서브쿼리의 비교 연산자로도 사용할 수 있다
  3. 연관 서브쿼리는 주로 메인쿼리에 값을 제공하기 위한 목적으로 사용 한다
  4. 서브 쿼리는 하앙 메인쿼리에서 읽힌 데이터에 대해 서브쿼리에서 해당 조건이 만족하는지를 확인하는 방식으로 수행된다
더보기

2

 

해설

2번

IN, ALL, ANY는 단일 행 서브쿼리에서도 사용할 수는 있지만

서브쿼리 결과가 2건 이상 나오면 오류가 날 수도 있으니, 단일 행이면 = 같은 연산자를 쓰는 게 안전함

  1. 비 연관 서브쿼리가 주로 메인쿼리에 값을 제공하기 위한 목적으로 사용된다
  2. 메인쿼리의 결과가 서브쿼리로 제공될 수도 있고, 서브쿼리의 결과가 메인쿼리로 제공될 수도 있으므로 실행 순서는 상황에 따라 달라진다

1️⃣0️⃣아래를 참고할 때 평가대상상품에 대한 품질평가항복별 최종 평가결과를 출력하는 SQL로 가장 적절한 것은? ( 단, 평가항목에 대한 평가등급이 기대수준에 미치지 못할 경우 해당 평가항목에 대해서만 재평가를 수행한다.)

1.

SELECT B.상품ID, B.상품명, C.평가항목ID, C.평가항목명, A.평가회차, A.평가등급, A.평가일자
FROM 평가결과 A, 평가대상상품 B, 품질평가항목 C, 
		 (SELECT MAX(평가회차) AS 평가회차 FROM 평가결과) D
WHERE A.상품ID = B.상품ID
AND A.평가항목ID = C.평가항목ID
AND A.평가회차 = D.평가회차;

 

2.

SELECT B.상품ID, B.상품명, C.평가항목ID, C.평가항목명, A.평가회차, A.평가등급, A.평가일자
FROM 평가결과 A, 평가대상상품 B, 품질평가항목 C
WHERE A.상품ID = B.상품ID
AND A.평가항목ID = C.평가항목ID
AND A.평가회차 = (SELECT MAX(X.평가회차)
									FROM 평가결과 X
									WHERE X.상품ID = B.상품ID
									AND X.평가항목ID = C.평가항목ID);

 

3.

SELECT B.상품ID, B.상품명, C.평가항목ID, C.평가항목명
			 ,MAX(A.평가회차) AS 평가회차
				 ,MAX(A.평가등급) AS 평가등급
			 ,MAX(A.평가일자) AS 평가일자
FROM 평가결과 A, 평가대상상품 B, 품질평가항목 C
WHERE A.상품ID = B.상품ID
AND A.평가항목ID = C.평가항목ID
GROUP BY B.상품ID, B.상품명, C.평가항목ID, C.평가항목명;

 

4.

SELECT B.상품ID, B.상품명, C.평가항목ID, C.평가항목명, A.평가회차, A.평가등급, A.평가일자
FROM (SELECT 상품ID, 평가항목ID
						 ,MAX(평가회차) AS 평가회차
								,MAX(평가등급) AS 평가등급
								,MAX(평가일자) AS 평가일자
			FROM 평가결과
			GROUP BY 상품ID, 평가항목ID) A, 평가대상상품 B,
						 품질평가항목 C
WHERE A.상품ID = B.상품ID
AND A.평가항목ID = C.평가항목ID;
더보기

2

해설

“재평가는 합격할 때까지 반복한 게 아니라는 가정 때문에 마지막 평가등급이 최고라는 보장이 없다”

✅ ①번

(SELECT MAX(평가회차) FROM 평가결과) D
  • 이건 전체 테이블 중 가장 큰 회차 1개만 가져옴
  • → 모든 상품/항목에 대해 똑같은 회차만 비교함 ❌

오답: 항목별로 평가회차를 비교하지 않음


✅ ②번 (정답)

AND A.평가회차 = (
  SELECT MAX(X.평가회차)
  FROM 평가결과 X
  WHERE X.상품ID = B.상품ID
  AND X.평가항목ID = C.평가항목ID
)
  • 각 상품 + 평가항목별로 가장 큰 평가회차 1건만 선택
  • 원하는 조건에 딱 부합

정답: 항목별 최신 평가회차만 가져옴


✅ ③번

GROUP BY B.상품ID, B.상품명, C.평가항목ID, C.평가항목명
  • MAX(평가회차), MAX(평가등급) 등의 집계함수를 쓰면
  • → 서로 다른 평가회차의 데이터들이 섞일 수 있음 (비정합 발생)

오답: 평가회차는 가장 큰 걸 가져왔어도 등급과 일자가 같은 행의 것일지 보장 안 됨


✅ ④번

SELECT 상품ID, 평가항목ID, MAX(평가회차), MAX(평가등급) ...
  • ③번과 같은 문제
  • MAX(평가회차)는 최신 회차지만, 그 회차에 해당하는 등급/일자와 일치한다는 보장이 없음

오답: 컬럼 간 정합성 보장되지 않음

 

반응형

'자격증 > SQL' 카테고리의 다른 글

오답노트 ( SQL 활용_2 )  (1) 2025.05.21
SQL) 데이터 모델과 SQL  (0) 2025.05.20
오답노트 ( SQL_2 )  (0) 2025.05.19
오답노트 ( SQL 기본_1 )  (0) 2025.05.19
오답노트 ( 데이터 모델링 )  (2) 2025.05.15