NULL 집계
t.v가 10, NULL, 10, 20일 때 결과는?
SELECT COUNT(*), COUNT(v), COUNT(DISTINCT v) FROM t;정답과 풀이 확인
정답 4 3 2
전체 4행, NULL 아닌 값 3개, 서로 다른 NULL 아닌 값 10·20의 2개.
이 브라우저에서 다음 학습에도 적용됩니다.
정보처리 실무 · 학습 노트
눈으로 실행 계획 대신 결과 행을 추적하기
CRUD 경험을 점수로 바꾸기 좋은 영역이다. NULL, 외부 조인, 집계, 서브쿼리에서 실제로 남는 행을 직접 적어보자. 문법은 표준 중심이며 DBMS별 차이를 표시했다.
기호와 용어가 낯설면 기초·상세 보강을 먼저 읽고, 기존 핵심 정리로 연결하세요. 예제의 값을 손으로 계산한 뒤 확인 질문을 답하고 마지막에 문제를 풉니다.
핵심 규칙을 설명하고, 연습문제의 답과 이유를 해설 없이 적을 수 있으면 체크하세요. 이해 체크와 정답 기록은 별도로 저장됩니다.
DDL은 CREATE·ALTER·DROP, DML은 INSERT·UPDATE·DELETE와 조회 SELECT, DCL은 GRANT·REVOKE, TCL은 COMMIT·ROLLBACK·SAVEPOINT다. SELECT를 DQL로 별도 분류하는 교재도 있다.
“문장 종류와 기본 틀”의 핵심 규칙과 헷갈리는 지점을 설명해 보세요.
UPDATE t SET col=값 WHERE 조건; DELETE FROM t WHERE 조건; INSERT INTO t(col) VALUES(값); DROP은 객체 제거, DELETE는 행 삭제, TRUNCATE는 전체 행 제거. 롤백 가능 여부는 DBMS·트랜잭션 조건에 따라 달라 일반화 금지.
UPDATE t SET col=값 WHERE 조건; DELETE FROM t WHERE 조건; INSERT INTO t(col) VALUES(값);
헷갈리는 지점 DROP은 객체 제거, DELETE는 행 삭제, TRUNCATE는 전체 행 제거. 롤백 가능 여부는 DBMS·트랜잭션 조건에 따라 달라 일반화 금지.
개념적으로 FROM·JOIN → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY 순으로 결과를 구성한다. 실제 엔진의 물리 실행 순서와는 다르다.
“SELECT 논리 처리 순서”의 핵심 규칙과 헷갈리는 지점을 설명해 보세요.
WHERE는 개별 행을, HAVING은 그룹을 거른다. ORDER BY 없이는 출력 순서를 보장하지 않는다. 집계한 COUNT(*) 조건을 WHERE에 직접 쓰지 않는다. SELECT 별칭의 사용 가능 위치는 DBMS에 따라 차이가 있다.
WHERE는 개별 행을, HAVING은 그룹을 거른다. ORDER BY 없이는 출력 순서를 보장하지 않는다.
헷갈리는 지점 집계한 COUNT(*) 조건을 WHERE에 직접 쓰지 않는다. SELECT 별칭의 사용 가능 위치는 DBMS에 따라 차이가 있다.
NULL은 값이 없거나 알려지지 않은 상태다. = NULL 대신 IS NULL을 쓴다. COUNT(*)는 행 수, COUNT(col)는 NULL이 아닌 값 수, COUNT(DISTINCT col)는 중복·NULL을 제외한 수다.
“NULL과 집계”의 핵심 규칙과 헷갈리는 지점을 설명해 보세요.
SUM·AVG는 NULL을 제외한다. 값 10,NULL,20의 AVG는 15이다. NOT IN의 비교 대상에 NULL이 있으면 UNKNOWN 때문에 기대한 행이 사라질 수 있다. NOT EXISTS와 구별한다.
SUM·AVG는 NULL을 제외한다. 값 10,NULL,20의 AVG는 15이다.
헷갈리는 지점 NOT IN의 비교 대상에 NULL이 있으면 UNKNOWN 때문에 기대한 행이 사라질 수 있다. NOT EXISTS와 구별한다.
INNER JOIN은 매칭된 행만, LEFT JOIN은 왼쪽 전체와 매칭된 오른쪽, RIGHT JOIN은 오른쪽 전체와 매칭된 왼쪽을 남긴다. 매칭되지 않은 쪽은 NULL이다.
“조인과 행 개수”의 핵심 규칙과 헷갈리는 지점을 설명해 보세요.
같은 키가 왼쪽 2행·오른쪽 3행이면 해당 키의 조인 결과는 6행. LEFT JOIN 뒤 WHERE b.col=값을 쓰면 NULL로 채워진 행이 제거된다. ON에 조건을 넣는 것과 결과가 다르다.
같은 키가 왼쪽 2행·오른쪽 3행이면 해당 키의 조인 결과는 6행.
헷갈리는 지점 LEFT JOIN 뒤 WHERE b.col=값을 쓰면 NULL로 채워진 행이 제거된다. ON에 조건을 넣는 것과 결과가 다르다.
IN은 결과 집합 포함 여부, EXISTS는 조건에 맞는 행의 존재 여부다. 상관 서브쿼리는 바깥 행의 값을 참조한다. UNION은 중복 제거, UNION ALL은 중복 유지다.
“서브쿼리와 집합 연산”의 핵심 규칙과 헷갈리는 지점을 설명해 보세요.
부서별 평균보다 큰 급여: e.salary > (SELECT AVG(x.salary) FROM emp x WHERE x.dept=e.dept). 스칼라 서브쿼리가 여러 행을 반환하면 오류가 날 수 있다. ANY·ALL과 단순 =를 구별한다.
부서별 평균보다 큰 급여: e.salary > (SELECT AVG(x.salary) FROM emp x WHERE x.dept=e.dept).
헷갈리는 지점 스칼라 서브쿼리가 여러 행을 반환하면 오류가 날 수 있다. ANY·ALL과 단순 =를 구별한다.
PRIMARY KEY는 행 식별, FOREIGN KEY는 참조 일관성, UNIQUE는 유일성, NOT NULL은 값 필수, CHECK는 조건 제약이다. CREATE DOMAIN은 재사용할 값의 타입과 조건을 정의한다.
“제약조건과 도메인”의 핵심 규칙과 헷갈리는 지점을 설명해 보세요.
CREATE DOMAIN score_t AS INTEGER CHECK (VALUE BETWEEN 0 AND 100); PostgreSQL에서 지원하는 예다. CHECK만으로 NULL을 항상 차단하지 않는다. 필수값에는 NOT NULL을 함께 둔다. CREATE DOMAIN은 모든 DBMS가 지원하지 않는다.
CREATE DOMAIN score_t AS INTEGER CHECK (VALUE BETWEEN 0 AND 100); PostgreSQL에서 지원하는 예다.
헷갈리는 지점 CHECK만으로 NULL을 항상 차단하지 않는다. 필수값에는 NOT NULL을 함께 둔다. CREATE DOMAIN은 모든 DBMS가 지원하지 않는다.
LIKE의 %는 0개 이상 문자, _는 정확히 한 문자다. 뷰는 조회문으로 정의한 논리적 테이블이다. 인덱스는 검색을 돕는 별도 구조로 저장 공간과 쓰기 비용을 사용한다.
“패턴과 뷰·인덱스”의 핵심 규칙과 헷갈리는 지점을 설명해 보세요.
LIKE '김%' / ORDER BY score DESC, id ASC / CREATE VIEW v AS SELECT ... 일반 뷰가 항상 결과를 물리적으로 저장하는 것은 아니다. 물리화 뷰와 구별한다.
LIKE '김%' / ORDER BY score DESC, id ASC / CREATE VIEW v AS SELECT ...
헷갈리는 지점 일반 뷰가 항상 결과를 물리적으로 저장하는 것은 아니다. 물리화 뷰와 구별한다.
CASE WHEN 조건1 THEN 값1 WHEN 조건2 THEN 값2 ELSE 기본값 END은 조건별로 다른 값을 계산하는 조건식이며, 여러 WHEN은 위에서부터 순서대로 검사해 처음 참인 조건의 값을 사용한다. COALESCE(a,b)는 a가 NULL이면 b를, 아니면 a를 반환해 NULL을 기본값으로 대체할 때 쓴다.
“CASE 조건식과 NULL 대체”의 핵심 규칙과 헷갈리는 지점을 설명해 보세요.
ELSE를 생략하면 어떤 WHEN도 참이 아닌 행은 NULL이 된다. WHEN 조건이 겹치면 먼저 나온 조건이 우선한다. 아래쪽이 더 구체적이어도 위쪽에서 이미 참이면 아래는 검사하지 않는다.
ELSE를 생략하면 어떤 WHEN도 참이 아닌 행은 NULL이 된다.
헷갈리는 지점 WHEN 조건이 겹치면 먼저 나온 조건이 우선한다. 아래쪽이 더 구체적이어도 위쪽에서 이미 참이면 아래는 검사하지 않는다.
테이블은 행과 열로 구성되며 SELECT는 필요한 열을 고른다. FROM은 대상 테이블, WHERE는 행 조건이다. *는 모든 열이며 AS는 결과 열의 별칭이다. DISTINCT는 선택된 열 조합의 중복을 제거한다.
조건은 AND·OR·NOT으로 결합하며 AND가 OR보다 우선한다. BETWEEN a AND b는 양 끝을 포함한다. IN(값목록)은 그중 하나인지 검사한다. 문자열은 작은따옴표로 표시한다.
SELECT name, score AS 점수
FROM student
WHERE score BETWEEN 60 AND 100
ORDER BY score DESC, name ASC;BETWEEN 60 AND 100은 60과 100을 포함하는가?
둘 다 포함한다.
SELECT 열 FROM 테이블 WHERE 조건 ORDER BY 열 ASC/DESC;
헷갈리는 지점 DISTINCT 한 열의 중복과 두 열 조합의 중복은 다르다. 정렬은 ORDER BY가 있어야 보장된다.
INSERT는 행을 넣고 UPDATE는 기존 행의 열값을 바꾸며 DELETE는 행을 지운다. WHERE가 없으면 UPDATE와 DELETE가 모든 행에 적용된다. CREATE TABLE은 구조를 만들고 ALTER TABLE은 구조를 바꾸며 DROP TABLE은 객체를 제거한다.
GRANT는 권한 부여, REVOKE는 권한 회수다. COMMIT은 트랜잭션 확정, ROLLBACK은 취소, SAVEPOINT는 부분 취소 기준을 만든다. DDL 자동 커밋과 TRUNCATE의 롤백 가능 여부는 DBMS마다 다르다.
CREATE TABLE student (
id INTEGER PRIMARY KEY,
name VARCHAR(20) NOT NULL,
score INTEGER CHECK (score BETWEEN 0 AND 100)
);
INSERT INTO student(id,name,score) VALUES(1,'민수',70);
UPDATE student SET score=80 WHERE id=1;
DELETE FROM student WHERE id=1;특정 사용자에게 조회 권한을 주는 키워드는?
GRANT. 예: GRANT SELECT ON student TO 사용자;
INSERT INTO t(열목록) VALUES(값목록); UPDATE t SET 열=값 WHERE 조건; DELETE FROM t WHERE 조건;
헷갈리는 지점 UPDATE와 DELETE는 객체 구조를 없애는 DROP과 다르다.
GROUP BY는 지정한 값이 같은 행들을 묶는다. COUNT·SUM·AVG·MIN·MAX는 그룹별로 계산한다. WHERE는 그룹 만들기 전 행 필터, HAVING은 그룹 계산 후 필터다. 집계하지 않은 SELECT 열은 원칙적으로 그룹 기준과 일치해야 한다.
부서 A에 급여 10,30, 부서 B에 20인 세 행이라면 A 평균 20, B 평균 20이다. WHERE salary>=20을 먼저 적용하면 A에는 30만 남아 평균 30이 된다. 이처럼 행 필터와 그룹 필터는 결과가 다르다.
SELECT dept, COUNT(*) AS n, AVG(salary) AS avg_salary
FROM emp
GROUP BY dept
HAVING COUNT(*) >= 2
ORDER BY dept;| 부서 | 급여 목록 | COUNT(*) | AVG |
|---|---|---|---|
| A | 10,30 | 2 | 20 |
| B | 20 | 1 | 20 |
집계 결과가 3 이상인 그룹을 남기는 절은?
HAVING. WHERE에 COUNT(*)>=3을 직접 쓰지 않는다.
행 나열 → WHERE 제거 → 그룹 묶기 → 집계 → HAVING → 출력·정렬.
헷갈리는 지점 COUNT(*)는 모든 행, COUNT(col)는 NULL 제외. AVG 분모도 NULL 아닌 값 개수.
SQL 조건은 TRUE·FALSE 외에 UNKNOWN을 가질 수 있다. NULL=값과 NULL<>값은 UNKNOWN이고 WHERE는 TRUE인 행만 통과시킨다. IS NULL·IS NOT NULL은 NULL 여부를 검사한다. COALESCE(a,0)는 첫 NULL 아닌 값을 선택한다.
2 NOT IN (1,NULL)은 2<>1 AND 2<>NULL이어서 TRUE AND UNKNOWN → UNKNOWN이다. 따라서 통과하지 않는다. NULL이 섞인 부정 포함 조건은 상관 NOT EXISTS로 의도를 표현할 수 있다.
SELECT id FROM A
WHERE NOT EXISTS (
SELECT 1 FROM B WHERE B.aid=A.id
)
ORDER BY id;10,NULL,20의 SUM·AVG·COUNT(col)는?
30,15,2. NULL은 집계 대상에서 제외된다.
NULL은 0도 빈 문자열도 아니다. UNKNOWN은 WHERE에서 남지 않는다.
헷갈리는 지점 NOT UNKNOWN도 UNKNOWN이다. NULL이 있으면 모든 행이 무조건 사라진다는 식의 설명도 피한다.
조인은 두 테이블 행을 조건으로 연결한다. 같은 키가 A에 2행, B에 3행이면 각각 모두 매칭되어 6행이다. CROSS JOIN은 모든 조합이며 A m행, B n행이면 m×n행이다. SELF JOIN은 같은 테이블에 서로 다른 별칭을 붙여 자기 자신과 연결한다.
LEFT JOIN의 ON은 매칭 조건이고 WHERE는 만들어진 결과 필터다. ON에 오른쪽 조건을 붙이면 매칭 실패한 왼쪽 행도 NULL로 남지만 WHERE의 오른쪽 열 조건은 그 행을 제거할 수 있다.
SELECT a.id, b.status
FROM A a LEFT JOIN B b
ON a.id=b.aid AND b.status='Y'
ORDER BY a.id;CROSS JOIN의 두 입력이 3행·4행이면?
12행.
조인은 키별로 매칭 행들을 나열하고 미매칭 행을 따로 추가한다.
헷갈리는 지점 외래키 관계라고 결과가 항상 한 행씩인 것은 아니다. 일대다·중복 키를 확인한다.
x > ANY(집합)는 하나 이상의 값보다 크면 참이고 x > ALL(집합)는 모든 값보다 커야 참이다. NULL 없는 비어 있지 않은 집합 10,20,30에서는 >ANY는 최솟값 10보다 큰지, >ALL은 최댓값 30보다 큰지로 확인할 수 있다.
EXISTS는 서브쿼리 결과 행의 존재를 검사한다. UNION은 합친 뒤 중복 제거, UNION ALL은 중복 유지, INTERSECT는 공통 행, EXCEPT는 왼쪽에만 있는 행이다. Oracle 전통 문법은 차집합에 MINUS를 사용한다. 입력 열 수와 대응 자료형의 호환성이 필요하다.
UNION과 UNION ALL에서 중복 행을 유지하는 것은?
UNION ALL.
>ANY: 하나만 만족 / >ALL: 모두 만족. NULL·빈 집합은 별도로 해석한다.
헷갈리는 지점 빈 집합에 대한 ALL은 참, ANY는 거짓. MIN/MAX 치환을 무조건 적용하지 않는다.
윈도 함수는 행을 유지하면서 그룹별 계산을 덧붙인다. OVER(PARTITION BY dept ORDER BY score DESC)는 부서별로 나눠 점수 순서로 계산한다. ROW_NUMBER는 행별 번호, RANK는 동점 같은 순위와 다음 순위 건너뜀, DENSE_RANK는 동점 뒤 순위를 이어간다.
일반 뷰는 SELECT 정의를 저장하는 논리적 테이블이며 복잡한 질의를 단순화하고 노출 열을 제한한다. 인덱스는 검색 경로를 돕지만 저장 공간·쓰기 비용이 추가된다. 뷰의 갱신 가능 여부는 정의와 DBMS에 따라 다르다.
SELECT id, score,
RANK() OVER (ORDER BY score DESC) AS r,
DENSE_RANK() OVER (ORDER BY score DESC) AS dr
FROM student
ORDER BY score DESC, id;| 점수 | ROW_NUMBER(동점 순서 지정) | RANK | DENSE_RANK |
|---|---|---|---|
| 90 | 1 | 1 | 1 |
| 90 | 2 | 1 | 1 |
| 80 | 3 | 3 | 2 |
검색용 인덱스가 많을 때 INSERT 비용은 어떻게 될 수 있는가?
인덱스도 갱신해야 하므로 증가할 수 있다.
점수 90,90,80: RANK 1,1,3 / DENSE_RANK 1,1,2.
헷갈리는 지점 ROW_NUMBER의 동점 순서를 고정하려면 ORDER BY에 고유한 보조 기준을 넣는다.
NOT IN 목록에 NULL이 있고 일치값이 없으면 조건은 UNKNOWN이 되어 WHERE를 통과하지 못한다. 빈 집합에 대한 ALL은 참, ANY는 거짓이다. COUNT(*)는 행을 세고 COUNT(열)은 NULL을 제외한다. 비어 있는 집합의 COUNT는 0이며 SUM은 NULL이다.
3 NOT IN (1,NULL)은 TRUE인가?
UNKNOWN이다. 3<>1 AND 3<>NULL에서 두 번째가 UNKNOWN이므로 WHERE에서 제외된다.
2026.10.14 재확인: PostgreSQL 18 비교와 NULL
WHERE는 TRUE만 남긴다. FALSE와 UNKNOWN은 모두 제외한다.
헷갈리는 지점 ANY·ALL은 문제의 DBMS 문법을 따른다. PostgreSQL 배열용 ANY와 표준 서브쿼리 표기를 혼동하지 않는다.
모두 유형 연습을 위해 직접 만든 문제입니다. C 예제의 printf·strlen은 필요한 표준 헤더가 포함된 상황을 가정합니다. Java는 표시된 클래스·main 위치에서 실행합니다. 단답은 동의어가 있을 수 있어 자동 판정 대신 자기 채점을 사용합니다.
t.v가 10, NULL, 10, 20일 때 결과는?
SELECT COUNT(*), COUNT(v), COUNT(DISTINCT v) FROM t;정답 4 3 2
전체 4행, NULL 아닌 값 3개, 서로 다른 NULL 아닌 값 10·20의 2개.
부서별 3명 이상인 부서만 출력하려 한다. 빈칸은?
SELECT dept,COUNT(*) FROM emp
GROUP BY dept
_____ COUNT(*) >= 3;정답 HAVING
그룹의 집계값을 검사하므로 HAVING이다.
A.id는 1,2,3 각 1행이고 B.aid는 1,1,3 각 1행이다. 결과 행 수는?
SELECT * FROM A LEFT JOIN B ON A.id=B.aid;정답 4
id=1은 두 번 매칭되어 2행, id=2는 미매칭 1행, id=3은 1행. 합 4.
위와 같은 A,B에서 다음 결과 행 수는?
SELECT * FROM A LEFT JOIN B ON A.id=B.aid
WHERE B.aid IS NOT NULL;정답 3
NULL로 채워진 id=2 행은 WHERE에서 제거된다. id=1 두 행과 id=3 한 행이 남는다.
emp(id,dept,salary)가 (1,A,10),(2,A,30),(3,B,20)일 때 출력 id는?
SELECT e.id FROM emp e
WHERE e.salary > (SELECT AVG(x.salary)
FROM emp x WHERE x.dept=e.dept)
ORDER BY e.id;정답 2
A 평균 20보다 큰 id=2만 남는다. B는 평균 20과 같아서 제외된다.
값이 없는 email을 고르는 조건은?
SELECT * FROM users WHERE email _____;정답 IS NULL
NULL과의 동등 비교는 UNKNOWN이다. IS NULL을 사용한다.
A가 1,1,2이고 B가 2,3일 때 UNION ALL 결과 행 수는?
정답 5
중복 제거 없이 3행+2행=5행이다. UNION이면 서로 다른 1,2,3으로 3행.
성이 이씨인 사람의 점수를 높은 순서로 조회하는 두 빈칸은?
SELECT name,score FROM student
WHERE name LIKE '_____'
ORDER BY score _____;정답 이% / DESC
LIKE 이%는 이로 시작하는 모든 문자열을 찾고 DESC는 내림차순이다.
PostgreSQL에서 score_t 값이 0~100인지 제한할 키워드는?
CREATE DOMAIN score_t AS INTEGER
_____ (VALUE BETWEEN 0 AND 100);정답 CHECK
도메인 값 조건은 CHECK이며 VALUE는 해당 도메인 값을 뜻한다.
A.id가 1,2이고 B.id가 2,3이다. A RIGHT JOIN B ON A.id=B.id의 A.id, B.id 결과는?
SELECT A.id,B.id FROM A RIGHT JOIN B ON A.id=B.id
ORDER BY B.id;정답 2 2 / NULL 3
오른쪽 B의 2와 3은 모두 남는다. 3에 대응하는 A가 없으므로 A.id는 NULL이다. 순서는 ORDER BY B.id로 고정한다.
score가 75일 때 다음 CASE 식의 결과는?
SELECT CASE WHEN score>=90 THEN 'A'
WHEN score>=80 THEN 'B'
WHEN score>=70 THEN 'C'
ELSE 'F' END
FROM t WHERE score=75;정답 C
90 이상 A, 80 이상 B, 70 이상 C 순서로 검사한다. 75는 70 이상 조건에서 처음 참이 되어 C다.
COALESCE(email, '미등록')에서 email이 NULL일 때 결과는?
정답 미등록
COALESCE는 인자를 앞에서부터 검사해 처음 NULL이 아닌 값을 반환한다. email이 NULL이므로 다음 값을 사용한다.
emp의 (dept,salary)가 (A,10),(A,30),(B,20)이다. 다음 결과는?
SELECT dept,AVG(salary) FROM emp
WHERE salary>=20 GROUP BY dept
HAVING AVG(salary)>25 ORDER BY dept;정답 A 30
WHERE로 A10을 제거한 뒤 A30,B20을 묶는다. HAVING으로 평균 25 초과인 A만 남긴다.
90,90,80점 내림차순의 RANK와 DENSE_RANK를 각각 쓰시오.
정답 1,1,3 / 1,1,2
RANK는 공동 1위 두 행 뒤 3위, DENSE_RANK는 다음 2위.
A.id는 1,2,3이며 B.id는 1,NULL이다. 결과 행 수는?
SELECT id FROM A WHERE id NOT IN (SELECT id FROM B);정답 0
1은 NOT IN이 FALSE, 2·3은 UNKNOWN이어서 WHERE에 남지 않는다.
집합 10,20,30에 대해 25>ANY와 25>ALL의 참·거짓은?
정답 참 / 거짓
하나보다 크면 ANY 참, 모두보다 커야 ALL 참. NULL 없는 집합이다.
x가 1,2,3인 테이블에서 WHERE x NOT IN (1,NULL)이 남기는 행 수는?
정답 0
1은 FALSE, 2·3은 UNKNOWN이므로 TRUE가 없다.
빈 테이블 t(v)에서 SELECT COUNT(*), SUM(v) FROM t 결과는?
정답 0, NULL
GROUP BY 없는 전체 집계는 한 행을 반환한다. COUNT는 0, SUM은 NULL이다.
2024년 2회 · Java 참조 비교·반정규화·DML·릴레이션 크기
2025년 3회 · 패키지 다이어그램·조건 커버리지·C/Java·SQL
2026년 2회 · 구조체·상속·딕셔너리·외부 조인·상관 서브쿼리·SRT·서브넷