Table: Employee
+-------------+------+
| Column Name | Type |
+-------------+------+
| id | int |
| salary | int |
+-------------+------+
id is the primary key (column with unique values) for this table.
Each row of this table contains information about the salary of an employee.
Write a solution to find the second highest distinct salary from the Employee table. If there is no second highest salary, return null (return None in Pandas).
The result format is in the following example.
Example 1:
Input:
Employee table:
+----+--------+
| id | salary |
+----+--------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
+----+--------+
Output:
+---------------------+
| SecondHighestSalary |
+---------------------+
| 200 |
+---------------------+
Example 2:
Input:
Employee table:
+----+--------+
| id | salary |
+----+--------+
| 1 | 100 |
+----+--------+
Output:
+---------------------+
| SecondHighestSalary |
+---------------------+
| null |
+---------------------+
[1번 방법]
SELECT
CASE
WHEN (SELECT COUNT(DISTINCT salary) FROM Employee) >= 2
THEN (
SELECT DISTINCT salary
FROM Employee
ORDER BY salary DESC
OFFSET 1
LIMIT 1
)
ELSE NULL
END AS SecondHighestSalary
* WHEN 절의 2개 행이상일떄 THEN문이 실행됨.
CASE
WHEN 조건
THEN 조건이 참일떄 실행
ELSE 조건이 False일때 실행
END AS 이름
* OFFSET은 전체 데이터에서 건너뛰는 행 수를 정함.
> OFFSET(1)이면 맨 위에서 다음칸으로 건너뜀.
> OFFSET은 LIMIT 전에 실행 됨. 단 작성시 LIMIT 상단에 적어야 함.
> OFFSET에 정해진 개수만큼의 레코드를 먼저 검새한 후 버리고 그 다음 레코드를 반환하므로, 불필요한 데이터 처리량이 많아진다. 데이터가 커지면 해당 옵션은 좋은 옵션은 아니다.
* 이경우 결과가 단일 스칼라 (변수이름은 있지만 값이 몇개냐 기준)이므로
FROM 없이 출력이 가능하다.
1. 결과가 단일 스칼라인 걸 확인. 또한 salary가 두번째 큰 값을 구해야됨을 인지함.
> SELECT 문의 subquery로 진행 시도
2. 1번 작성시 값이 있으면 salary값을, 없으면 Null을 해야함. 즉 처음 행이 2개가 아니면 Null을 출력하게 할 수 있음.
> 1번 subquery문 안에 case, when 문이 있어야 함.
[2번 방법]
더 단순한 코드
* OFFSET을 보완하고 다른 방법을 사용해본다.
* 단, MySQL에서 WHERE 조건문을 만족하지 않으면 NULL이 아니라 빈 결과(0 rows)를 반환한다.
이경우 ISNULL()문을 이용해서 강제로 값이 없으면 NULL을 반환하게 만들 수도 있다.
SELECT IFNULL(
(SELECT, FROM~), NULL
) AS SecondHighestSalary;
* 여기서는 WHERE조건문이 빈결과(0 row)를 내뱉는 결과를 SELECT문의 MAX()함수가 받아서 NULL로 출력한다.
1. WHERE절에서 subquery를 작성한다.
1) 이때 salary 최고값이 있다면 스칼라 값을, 없다면 0행을 반환되도록한다.
2)이 반환된 값을 다시 salary와 비교한다. 스칼라 값이 있다면 그것보다 작은 salary값들이 반환되고 비교대상이 없다면 0행이 주어진다.
2. SELECT절에서 WHERE에서 반환한 값의 최댓값을 구한다.(MAX()) 이 때 값이 없다면 MAX()함수 특성상 NULL을 반환하고, 값이 있다면 그 값을 반환한다. 이떄 중복되는 행출력을 박고자 DISTINCT를 명시해준다.
SELECT DISTINCT MAX(salary) AS SecondHighestSalary
FROM Employee
WHERE salary < (
SELECT MAX(salary)
FROM Employee
)
ORDER BY salary DESC
LIMIT 1 ;
이번 문제로 알게 된 것
번호주제설명예제 / 추가 정보
1 | CASE WHEN | 특정 조건이 만족될 때만 실행되며, 그렇지 않으면 NULL을 반환할 수 있음. | sql SELECT CASE WHEN (조건) THEN (값) ELSE NULL END AS SecondHighestSalary; |
2 | OFFSET의 역할 | OFFSET n은 처음 n개의 행을 건너뛰고 그다음 행부터 가져옴. | OFFSET 1 LIMIT 1 → 두 번째 값 가져옴 |
3 | OFFSET의 성능 문제 | OFFSET이 클수록 불필요한 데이터 스캔이 많아져 비효율적 | 해결 방법: 커서 기반 페이징 사용 (WHERE salary < ? 방식) |
4 | ORDER BY의 올바른 사용법 | ORDER BY salary DESC로 내림차순 정렬 후 두 번째 값 선택 | DEC는 DESC의 오타이며, SQL에서 문법 오류 발생! |
5 | FROM 없는 SELECT | 단일 스칼라 값을 반환하는 서브쿼리는 FROM 없이도 실행 가능 | sql SELECT (SELECT MAX(salary) FROM Employee) AS MaxSalary; |
6 | WHERE 조건이 빈 결과(0 rows)를 반환하는 이유 | MySQL에서 WHERE 조건을 만족하는 데이터가 없으면 NULL이 아니라 **"빈 결과(0 rows)"**를 반환함 | 예: SELECT salary FROM Employee WHERE salary < 100; (해당 값이 없으면 0 rows) |
7 | MAX()가 NULL을 반환하는 이유 | MAX() 함수는 입력 값이 없을 때 NULL을 반환 | sql SELECT MAX(salary) FROM Employee WHERE salary < 50; -- 값이 없으면 NULL 반환 |
8 | IFNULL()를 이용한 NULL 방지 | IFNULL(쿼리, 기본값)을 사용하면 빈 결과(0 rows)를 NULL 또는 다른 값으로 변경 가능 | sql SELECT IFNULL((SELECT salary FROM Employee WHERE salary < 100 LIMIT 1), NULL) AS SecondHighestSalary; |
9 | COALESCE()를 이용한 NULL 방지 | COALESCE()는 여러 개의 값을 검사하면서 첫 번째 NULL이 아닌 값을 반환 | sql SELECT COALESCE((SELECT salary FROM Employee WHERE salary < 100), 0) AS SecondHighestSalary; |
10 | DISTINCT MAX(salary)의 의미 | MAX(salary)는 하나의 값만 반환하므로 DISTINCT는 불필요하지만, 불필요한 중복 행 방지를 위해 사용 가능 | sql SELECT DISTINCT MAX(salary) AS SecondHighestSalary FROM Employee WHERE salary < (SELECT MAX(salary) FROM Employee); |
11 | NULL이 반환되는 이유 | ① WHERE 조건이 만족하는 값이 없으면 NULL 대신 빈 결과(0 rows) 반환 → MAX()가 이를 받아서 NULL 반환 ② WHERE salary < NULL이 항상 FALSE가 되기 때문 | NULL을 반환하는 코드: sql SELECT MAX(salary) FROM Employee WHERE salary < (SELECT MAX(salary) FROM Employee); |
'SQL > 코딩테스트' 카테고리의 다른 글
Rising Temperature (0) | 2025.03.14 |
---|---|
[MySQL] SubQuery 활용법 (0) | 2024.11.11 |
[MySQL] SUB쿼리를 굳이 쓰지 않아도 되는 경우 (0) | 2024.11.10 |
[MySQL] 하나의 테이블에 두개의 키 변수를 이용해 Join 하기 (0) | 2024.11.09 |
[MySQL] SQL 문제에서 문제정의방법 (1) | 2024.11.08 |