SQL 코드카타 121번
DIAB1로 시작하거나,
앞에 어떤 단어가 있고(% 띄어쓰기) + DIAB1로 시작하는 conditions를 조건으로 걸면 됨.
SELECT *
FROM patients
WHERE conditions LIKE 'DIAB1%'
OR conditions LIKE '% DIAB1%'
SQL 코드카타 122번
처음으로 select가 아니라 delete를 묻는 문제.
중복되는 email이 있을 경우 작은 id쪽의 데이터만 살리고 큰 쪽의 데이터는 지워야 한다.
DELETE p1 FROM Person p1,
Person p2
WHERE
p1.Email = p2.Email AND p1.Id > p2.Id
SQL 코드카타 123번
간단하게 풀 수 있는 문제인데 너무 어렵게 돌아갔다.
SELECT DISTINCT secondhighestsalary
FROM (SELECT CASE
WHEN (SELECT Count(DISTINCT salary)
FROM employee) >= 2 THEN (SELECT salary
FROM (SELECT salary,
Dense_rank()
OVER (
ORDER BY
salary
DESC) AS
ranking
FROM employee
GROUP BY 1) b
WHERE ranking = '2')
ELSE NULL
END AS SecondHighestSalary
FROM (SELECT salary,
Dense_rank()
OVER (
ORDER BY salary DESC) AS ranking
FROM employee) a) b
내가 짠 쿼리는 저거였는데, 저렇게 복잡하게 생각할 필요가 전혀 없었다. 완전 간단한 버전의 쿼리로도 해결 가능.
SELECT Max(salary) AS SecondHighestSalary
FROM employee
WHERE salary <> (SELECT Max(salary)
FROM employee);
답은 맞게 나왔지만 또 생각을 너무 복잡하게 했던 문제.
그저께 dense_rank를 썼던 기억이 살아있어서였는지 자연스럽게 그거부터 쓸 생각을 했는데, 망치 든 사람에게는 못밖에 안 보인다는 말의 전형적인 예.
아무리 medium난이도여도 나처럼 극단적으로 복잡하게 생각을 해야만 풀 문제가 나오지는 않는다는 사실을 자꾸 잊어버리는 것 같다. 한 번 생각에 잠겨서 몰입하기 시작하면 도중에 끊고 빠져나오는 게 어려운 스타일인 것도 한몫하는 듯.
최대한 단순하게 생각할 수 있게 머릿속 컨디션 조절을 잘 하자.
어떤 문장의 각 알파벳을 일정한 거리만큼 밀어서 다른 알파벳으로 바꾸는 암호화 방식을 시저 암호라고 합니다. 예를 들어 "AB"는 1만큼 밀면 "BC"가 되고, 3만큼 밀면 "DE"가 됩니다. "z"는 1만큼 밀면 "a"가 됩니다. 문자열 s와 거리 n을 입력받아 s를 n만큼 민 암호문을 만드는 함수, solution을 완성해 보세요.
이 문제는 지금까지 알던 기본 함수만 갖고는 해결할 수 없었다. 어떤 문자를 입력받아서 그 문자로부터 n번째 뒤의 문자를 출력하려면 그 문자를 순번이 있는 숫자로 나타낼 수 있어야 하는데, 그런 역할을 하는 함수를 배운 바가 없었기 때문.
구글링을 해 보니 chr과 ord라는 함수가 있어서 이번 문제를 푸는 데 적용해 보기로 했다.
- chr : 어떤 유니코드 숫자를 입력하면 그에 해당하는 문자를 반환함
- ord : 어떤 문자를 입력하면 그에 해당하는 유니코드를 정수로 반환함
- 예시 : ord(a) = 97, chr(97) = a
- ord와 chr은 서로 역의 관계
ord('A') = 65,
ord('B') = 66,
...
ord('Z') = 90,
ord('a') = 97, ※91부터 96까지는 다른 문자가 들어감
ord('b') = 98,
...
ord('z') = 122
여기까지는 이해했는데 그럼 z를 한 칸 밀었을 때 다시 a, 즉 97번이 나오게 하려면 어떻게 해야할지 고민..
ord(z) = 122니까
ord('임의의 문자')+n > 122라면
(ord('임의의 문자'))+n-26 이렇게 해야 하나?
했는데 의외로 정답이었다...??
def solution(s, n):
x = list(s)
y = []
for i in x:
if i.isupper() and ord(i)+n > 90:
y.append(chr(ord(i)+n-26))
if i.isupper() and ord(i)+n <= 90:
y.append(chr(ord(i)+n))
if i.islower() and ord(i)+n > 122:
y.append(chr(ord(i)+n-26))
if i.islower() and ord(i)+n <= 122:
y.append(chr(ord(i)+n))
if i == ' ':
y.append(i)
answer = ''.join(y)
return answer
s를 리스트x로 바꿔주고 x에 담긴 값들을 하나씩 확인한다.
만약 i가 대문자고 ord(i)+n이 90보다 크다면, (즉, Z를 넘어서 다시 대문자 A로 돌아가야 하는 상황이라면) ord(i)+n-26을 문자로 바꿔서(chr) 빈 리스트 y에 추가해 준다. 그게 아니라면 그냥 ord(i)+n에 해당하는 문자를 y에 추가해 준다.
이런 식으로 대문자/소문자, z(혹은 Z)를 넘을 때/안 넘을 때로 경우의 수를 4가지로 나눠 y에 담고, 마지막으로 공백일 경우에는 그냥 y에 담아주면 된다. 리스트 y를 합쳐서 출력하면 정답.
다 풀고 나서 추가로 검색해 보니 ascii_offset을 알고 있으면 코드를 더 간단하게 만들 수 있겠다. 하지만 지금은 문제에서 요구한 사항들을 정답에 맞도록 직관적으로 구현해 내는 것이 목표이므로, 좀 더 진일보한 코드는 나중에 복습할 때 만들어 보기로.