select BOOK_ID, AUTHOR_NAME, date_format(PUBLISHED_DATE,"%Y-%m-%d") as PUBLISHED_DATE
from BOOK as b, AUTHOR as a
where CATEGORY = "경제" and b.AUTHOR_ID = a.AUTHOR_ID
order by PUBLISHED_DATE;
그런데 문제 조건에 총주문량이 작은 순서대로 조회하는 SQL 문이라고 적혀있는데 해당 조건을 안 써도 통과가 된다.
그래도 정렬을 추가해서 다시 제출했다.
코드
select INGREDIENT_TYPE, SUM(TOTAL_ORDER) as TOTAL_ORDER
from FIRST_HALF as f join ICECREAM_INFO as i
on f.FLAVOR = i.FLAVOR
group by INGREDIENT_TYPE
order by TOTAL_ORDER;
조인의 경우는 where절에서 필터링을 걸기 때문에 조인을 수행하고 난 뒤면 데이터의 크기가 너무 커지지 않는지 궁금하다.
그리고 두번째 방법을 쓰는 경우 where에서 board_id가 같은 것만 선택하는 것 깜빡하지 않기!!
코드
# 조인
select
TITLE,
b.BOARD_ID,
REPLY_ID,
r.WRITER_ID,
r.CONTENTS,
DATE_FORMAT(r.CREATED_DATE, "%Y-%m-%d") as CREATED_DATE
from USED_GOODS_BOARD as b join USED_GOODS_REPLY as r
on b.BOARD_ID = r.BOARD_ID
where YEAR(b.CREATED_DATE) = 2022 and MONTH(b.CREATED_DATE) = 10
order by r.CREATED_DATE, TITLE;
# where
select
title,
b.board_id,
reply_id,
r.writer_id,
r.contents,
date_format(r.created_date, "%Y-%m-%d") as CREATED_DATE
from used_goods_board as b, used_goods_reply as r
where b.board_id = r.board_id
and date_format(b.created_date, "%Y-%m") = '2022-10'
order by r.created_date, title;
# 서브쿼리
select flavor
from first_half
where total_order > 3000 and flavor in (
select flavor
from icecream_info
where ingredient_type = 'fruit_based'
)
order by total_order desc;
# 조인
select first_half.flavor
from first_half join icecream_info
on first_half.flavor = icecream_info.flavor
where total_order > 3000 and ingredient_type = 'fruit_based'
order by total_order desc;
DATE 타입을 출력하면 1992-03-16 00:00:00으로 나오기 때문에 DATE_FORMAT(DATE_OF_BIRTH, "%Y-%m-%d") as DATE_OF_BIRTH를 사용했다.
%Y
4자리 연도
%y
2자리 연도
%M
영어 월
%m
2자리 월
%D
일+th
%d
2자리 일
DATE 타입에서 월만 가져오려면 MONTH(컬럼명)을 사용한다. 이외에 YEAR(대상), MONTH(대상), DAY() 아니면 DAYOFMONTH()가 있다.
코드
SELECT MEMBER_ID, MEMBER_NAME, GENDER, DATE_FORMAT(DATE_OF_BIRTH, "%Y-%m-%d") as DATE_OF_BIRTH
FROM MEMBER_PROFILE
WHERE GENDER = 'W'
and MONTH(DATE_OF_BIRTH) = 3
and TLNO is not null
ORDER BY MEMBER_ID;
자물쇠는 N의 크기를 가지고 있다. 열쇠가 배열의 범위를 벗어나 확인이 가능하기 때문에 맵을 N + (M*2) - 2 만큼 확장해 준다.
자물쇠의 크기 + 열쇠 2개 - 겹치는 부분
- 배열 중심에 자물쇠 위치 시키기
맵의 중심에 자물쇠를 위치시킨다. 확장된 맵에서의 자물쇠의 위치는 열쇠길이-1 부터 시작위치에서 자물쇠의 길이만큼 더해준 값이다.
자물쇠를 확장맵에 위치시키고 나면 다음과 같이 맵이 나타난다.
열쇠 위치
2중 반복문을 사용한다. 인덱스의 범위는 (0,0) 부터 자물쇠의 마지막 위치인 (열쇠의 길이+자물쇠의 길이)-1 만큼이다.
확장맵 + 열쇠
확장된 맵에 현재 열쇠의 인덱스 (i, j) 부터 열쇠의 크기까지 맵에 더한다
이 결과로 맵에 저장되는 값은 0, 1, 2인데 문제에서 구하고자 하는 값은 1이 된다.
0 : 열쇠와 자물쇠의 홈끼리 만난 경우
1 : 열쇠의 돌기와 자물쇠의 홈이 만난 경우 → 정상
2 : 열쇠의 돌기와 자물쇠의 돌기가 만난 경우
자물쇠가 열리는지 확인
전체 맵을 확인 할 필요 없이 자물쇠가 있는 위치만 확인한다. 이 문제의 답은 자물쇠의 홈이 모두 채워지는 경우여야 하기 때문이다.
자물쇠의 범위는 (열쇠의 길이 - 1) ~ (열쇠의 길이 + 자물쇠의 길이 - 1) 이 된다.
해당 범위를 확인하는 check 메서드를 만들어 범위가 전부 1인지 확인한다. check 메서드가 true를 반환한다면 현재 열쇠는 맞는 열쇠가 되기 때문에 true를 return 하고 종료한다. false를 반환한다면 현재 열쇠가 맞지 않기 때문에 방향을 바꿔준다.
방향을 모두 바꿔도 맞지 않는다면 다음 위치로 넘어간다.
열쇠 회전
한번에 90도씩 회전시킨다. 90도를 회전시키면 배열의 크기가 3인 인덱스의 매칭은 다음과 같다.
[행][열]
rotate[0][0] = origin[2][0]
rotate[0][1] = origin[1][0]
rotate[0][2] = origin[0][0]
rotate[1][0] = origin[2][1]
rotate[1][1] = origin[1][1]
rotate[1][2] = origin[0][1]
rotate[2][0] = origin[2][2]
rotate[2][1] = origin[1][2]
rotate[2][2] = origin[0][2]
행과 열을 읽을 때 행을 아래에서부터 위로 읽은 것을 열에 저장한다. 복잡하게 설명하지만 직접 써보면서 풀면 이해가 쉬워진다.
전체 코드
public class Solution_자물쇠와열쇠 {
static int M, N;
public static boolean solution(int[][] key, int[][] lock) {
N = lock.length; //자물쇠의 크기
M = key.length; //열쇠의 크기
//맵을 자물쇠의 크기에서 열쇠의 크기만큼 확장해줌
int[][] map = new int[N + (M * 2) - 2][N + (M * 2) - 2];
//중심에 자물쇠 위치시키기. i/j -> map에 대한 인덱스. k/l -> 자물쇠에 대한 인덱스
for (int i = M - 1, k = 0; i < M - 1 + N; i++, k++) {
for (int j = M - 1, l = 0; j < M - 1 + N; j++, l++) {
map[i][j] = lock[k][l];
}
}
//임시 복사 배열
int[][] copyMap = new int[map.length][map.length];
//0,0부터 N-1+M까지 열쇠 두기
for (int i = 0; i < M + N - 1; i++) {
for (int j = 0; j < M + N - 1; j++) {
for (int d = 0; d < 4; d++) {
//맵 복사
MapCopy(copyMap, map);
//열쇠를 복사맵에 더함
for (int k = 0; k < M; k++) {
for (int l = 0; l < M; l++) {
copyMap[i + k][j + l] += key[k][l];
}
}
//자물쇠가 열리는지 확인
if (check(copyMap)) { //맞는다면 트루
return true;
}
//방향이 아니라면 돌려줌
key = rotate(key);
}
}//end j
}//end i for check all index
return false;
}
private static void MapCopy(int[][] copyMap, int[][] map) {
//맵 복사함
for (int k = 0; k < map.length; k++) {
System.arraycopy(map[k], 0, copyMap[k], 0, map[k].length);
}
}
private static int[][] rotate(int[][] key) {
int[][] copyKey = new int[M][M];
for (int i = 0; i < M; i++) {
for (int j = 0; j < M; j++) {
copyKey[i][j] = key[M - 1 - j][i];
}
}
return copyKey;
}
private static boolean check(int[][] copyMap) {
//자물쇠 영역이 전체가 1인지 확인함
for (int k = M - 1; k < M - 1 + N; k++) {
for (int l = M - 1; l < M - 1 + N; l++) {
if (copyMap[k][l] != 1) { //1이 아닌 값이 들어갔다면 돌기끼리 만났거나 홈이 안채워짐
return false;
}
}
}
return true;
}
}