Today's Codekata
class Solution {
public int solution(int[] numbers) {
int total = 0;
for (int i = 0; i <= 9; i++) {
total += i;
}
int result = 0;
for (int num : numbers) {
result += num;
}
return total - result;
}
}
처음엔 return 45 - result; 이렇게 답만 찾았다가 개발자는 코드를 그런 식으로 짜면 안 될 것 같다는 생각에 합계를 구하는 for문을 추가했다. 같은 기능을 하는 코드를 여러 방식으로 만들어보는게 공부가 되는 것 같다.
public class Solution {
public int[] solution(int[] arr) {
if (arr.length <= 1) return new int[]{-1};
int minIndex = 0;
for (int i = 1; i < arr.length; i++) {
if (arr[i] < arr[minIndex]) {
minIndex = i;
}
}
int[] answer = new int[arr.length - 1];
for (int i = 0, index = 0; i < arr.length; i++) {
if (i != minIndex) {
answer[index++] = arr[i];
}
}
return answer;
}
}
int min = Arrays.stream(arr).min().getAsInt();
return Arrays.stream(arr).filter(i -> i != min).toArray();
if문 뒤에 실행문이 한 줄뿐이면 중괄호를 생략할 수 있다는 걸 알게 되었다. 그런데 코드 자체는 간결해보이지만 이게 좋은 방식인지는 아직 잘 모르겠다. 최소값이나 최소값이 있는 배열의 인덱스를 어떻게 구해서 제외할지 답을 찾는데 오래 걸렸다. 다른 사람들의 풀이를 보면서 어떤 식으로 stream을 활용하면 좋을지 또 배운 것 같다.
SELECT PRODUCT_ID, PRODUCT_NAME, PRODUCT_CD, CATEGORY, PRICE
FROM FOOD_PRODUCT
ORDER BY PRICE DESC
LIMIT 1;
SELECT ANIMAL_ID
FROM ANIMAL_INS
WHERE NAME IS NULL
ORDER BY ANIMAL_ID;
처음에 최고 가격을 조회할 때 max(price) 라고 작성했더니, 그 값에 해당하는 다른 컬럼 정보는 함께 조회되지 않았다. 그래서 최고값부터 내림차순으로 정렬하고 LIMIT를 활용해 한 줄만 조회되도록 만들었다.
Today I Learned
SQL 기본 문법 SUBQUERY
하나의 쿼리문 안에 포함된 또 다른 쿼리문이다.
복잡한 조건이나 계산을 한 번에 처리할 수 있게 해주는 아주 강력한 도구이다.
-- 가장 높은 급여를 받는 직원 조회
SELECT EMP_ID, NAME, SALARY
FROM EMPLOYEES
WHERE SALARY = (SELECT MAX(SALARY) FROM EMPLOYEES);
-- 서브쿼리: 전체 직원 중 최대 급여 계산
-- 메인쿼리: 그 급여를 받는 직원 정보 조회
-- 서울에 위치한 부서에 속한 직원 조회
SELECT NAME, DEPT_ID
FROM EMPLOYEES
WHERE DEPT_ID IN (
SELECT DEPT_ID
FROM DEPARTMENTS
WHERE LOCATION = 'SEOUL'
);
-- 서브쿼리: 서울에 있는 부서 ID 목록 추출
-- 메인쿼리: 해당 부서에 속한 직원 조회
-- 각 직원의 평균 급여와 비교
SELECT NAME, SALARY,
(SELECT AVG(SALARY) FROM EMPLOYEES) AS AVG_SALARY
FROM EMPLOYEES;
-- 서브쿼리: 전체 평균 급여 계산
-- 메인쿼리: 각 직원 정보와 함께 평균 급여도 출력
여러 예시들을 만들어봤다. FROM절에서 사용하는 방식만 배웠는데, WHERE절에서도 SELECT절에서도 활용이 가능하다.
SQL 기본 문법 JOIN
| 종류 | 설명 | 예시 상황 |
| INNER JOIN | 두 테이블 모두에 일치하는 값이 있을 때만 | 직원과 부서 모두 존재 |
| LEFT JOIN | 왼쪽 모든 행 + 오른쪽 일치값 (없으면 NULL) | 모든 직원 + 부서X 직원 포함 |
| RIGHT JOIN | 오른쪽 모든 행 + 왼쪽 일치값 (없으면 NULL | 모든 부서 + 직원X 부서 포함 |
| FULL OUTER JOIN | 양쪽 모든행 + 일치하지 않는 값 NULL | 모든 직원과 모든 부서 |
| CROSS JOIN | 두 테이블 모든행을 조합 | 모든 상품 * 모든 고객 |
| SELF JOIN | 하나의 테이블을 자기 자신과 조인 | 직원 간 상사-부하 관계 |
SELECT e.EMP_ID, e.NAME, d.DEPT_NAME
FROM EMPLOYEES e
INNER JOIN DEPARTMENTS d ON e.DEPT_ID = d.DEPT_ID;
DEPT_ID가 양쪽 테이블에 모두 존재하는 경우들만 출력된다.
SELECT e.EMP_ID, e.NAME, d.DEPT_NAME
FROM EMPLOYEES e
LEFT JOIN DEPARTMENTS d ON e.DEPT_ID = d.DEPT_ID;
EMPLOYEES 테이블의 모든 행이 출력되고, DEPT_ID가 없는 경우는 DEPT_NAME이 NULL로 표시된다.
select restaurant_name,
case when price <= 5000 then '5000원 이하'
when price <= 10000 then '10000원 이하'
when price <= 30000 then '30000원 이하'
when price > 30000 then '30000원 초과' end price_group,
case when age < 30 then '20대'
when age between 30 and 39 then '30대'
when age between 40 and 49 then '40대'
else '50대 이상' end age_group
from
(
select f.restaurant_name,
avg(f.price) price,
avg(c.age) age
from food_orders f
inner join customers c on f.customer_id = c.customer_id
group by 1
) a
order by 1
식당별 평균 음식 주문 금액과 주문자의 평균 연령을 기반으로 Segmentation 하기 미션 클리어!
COALESCE
여러 값 중 첫 번째로 NULL이 아닌 값 반환하는 함수이다.
coalesce(컬럼명 또는 값, 대체값)
SELECT name, COALESCE(email, 'noemail@example.com') AS contact_email
FROM employees;
위 예시를 보면 이메일이 없을 경우 이렇게 기본값처럼 설정해줄 수 있다.
마치며
오늘은 키오스크 프로젝트를 마무리하고 전에 마무리 못한 SQL 관련해서 공부하는 시간을 가졌다. 아직 문법도 낯설고 실수도 많이 하지만, 데이터를 정확히 가져오고 정리하는 흐름을 익히면 백엔드 코드를 이해하는 데에도 도움이 될 거라는 생각이 든다. 앞으로 백엔드 개발자가 되기 위해서는 SQL의 기초도 확실히 다져야겠다는 다짐을 해본다.