-
2024-01-11스파르타/TIL(Today I Learned) 2024. 1. 11. 22:41더보기
SQL 코드카타
584. Find Customer Referee(SQL)
https://leetcode.com/problems/find-customer-referee/
id=2인 유저에게 초대받지 않은 사람의 이름을 출력하는 문제이다.
SELECT c.name FROM Customer c WHERE c.referee_id !=2 or c.referee_id is null
customer테이블로 부터 referee_id가 2가 아니거나 null인 이름을 모두 출력해주었다
595. Big Countries(SQL)
https://leetcode.com/problems/big-countries/description/
큰 나라(면적이 3000000이상이거나 인구가 25000000이상인 나라)의 이름, 인구, 면적을 출력하는 문제이다.
SELECT w.name, w.population, w.area FROM World w WHERE w.area >= 3000000 or w.population >=25000000
말 그대로 해주는 간단한 문제이다.
1148. Article Views I(SQL)
https://leetcode.com/problems/article-views-i/description/
자신이 쓴 기사를 1번 이상 본 작성자의 id를 오름차순으로 출력하는 문제이다
SELECT distinct v.author_id id FROM Views v WHERE v.author_id = v.viewer_id ORDER BY v.author_id
2번이상 본 이라면 조금 더 조건을 달아야 했겠지만 지금은 한번이라도 본 적이 있으면 되므로 기록에서 작성자와 본 사람이 동일한 경우에 대해서만 조회해준 뒤 id를 중복없이 출력한 뒤 오름차순으로 정렬해주었다.
더보기파이썬 코드카타
피로도(python) (itertools의 permutations, 나중에 다시 다른 방법으로도 풀어보기)
https://school.programmers.co.kr/learn/courses/30/lessons/87946
여러 던전을 하루에 한 번씩만 갈 수있는데 주어진 피로도라는 값이 있고, 각 던전에는 입장시 만족해야하는 최소 피로도와 갔다올 시 소모되는 소비 피로도가 정해져 있다 최소 피로도와 소비 피로도가 저장된 던전 리스트와 현재 피로도가 주어질 때 가장 많이 돌 수 있는 던전의 수를 구하는 문제이다.
from itertools import permutations def posible_num(k,dungeons): count=0 for dungeon in dungeons: if dungeon[0]>k: continue else: k-=dungeon[1] count+=1 return count def solution(k, dungeons): all_number_of_cases=[] count_list=[] for case in permutations(dungeons,len(dungeons)): all_number_of_cases.append(case) for case in all_number_of_cases: count=posible_num(k,case) count_list.append(count) answer=max(count_list) return answer
처음에는 다른 모듈 안 찾아보고 머리 써서 경우의 수를 최대한 줄여서 체크해볼려고 하였다
그런 아이디어에서 떠올린 방법이 최소 피로도가 큰 순으로 먼저 정렬하여 그 순서대로 입장하거나 소모 피로도가 작은 순으로 먼저 정렬하여 입장하는 방법 각각의 두 방식을 (만약 최소 피로도가 같은 경우는 소모 피로도 작은순으로, 소모피로도가 같은 경우 최소 피로도가 큰 순으로 추가해주었다) 하여 둘 중 갈 수 있는 던전 수가 많은 값을 채택하여 리턴하도록 하였는데 꽤 많은 시간과 정신력을 쓰면서 완성했는데 처음 주어진 테스트 케이스부터 실패하였다.. 점검해보니 저 방식대로 해도 최대 던전 수를 세지 못하는 경우가 존재할 수 밖에 없다는 것을 알고 좌절했다. 시간도 늦고 다른 할 일도 많아 결국 포기하고 다음날 다른 것 다하고 잠깐 쉬는 시간에 기존에 방식은 포기하고 직접 순열로 가능한 경우의 수를 직접 만들까하다가 질문하기에서 itertools에 permutations라는 순열을 만들어주는 모듈이 있다는 것을 확인하고는 그 방식을 사용하여 해결하였다(매우 간단히 끝났다)
애초에 완전탐색 문제라 효율성은 따지지 않고 정확도만 체크하는 문제인지라 확인만 되면 되는듯 하였다.
우선 코드에 대해 간단히 설명하면 우선 사용할 모듈 import해주었고, posible_num이라는 함수를 정의하여 주어진 던전 순서에 따라 현재 피로도가 최소 피로도 보다 높아던전을 들어갈 수 있으면 +1해서 세어주고 현재 피로도에서 소모 피로도 만큼 빼주는 방식으로 던전리스트를 받으면 담겨있는 순서대로 갔을 경우 갈 수 있는 총 던전수를 세어주는 함수이다.
그리고 solution함수로는 우선 모든 경우를 담을 리스트 all_number_of_cases를 만들어주고, 세어서 나온 모든 count값들을 담을 count_list도 만들어준 뒤 모듈을 사용하여 반복문을 통해 모든 케이스를 리스트에 담아주고 그 리스트에 대해 반복문을 다시 돌려 각 경우의 총 던전수를 count_list에 담고 그중 가장 큰 값을 answer로 하여 리턴하였다.
바빠서 시간이 부족한 관계로 한 문제에 더 이상 시간을 쓸 수 없어서 모듈을 사용해서 간단히 넘어갔지만 나중에 시간이 날 때 다시 다른 방식으로도 풀어보고 싶다.
그리고 permutations는 쓰는 방식이 permutations(리스트, 몇개) 이런식으로 쓸 수 있을듯하다 리스트 자리에는 반복가능한 객체인 리스트,튜플,문자열이 가능하다고 한다 저런색으로 쓰면 리스트안의 요소에서(다른 것도 같은 방식) 몇개를 뽑아 순서 있게 조합해주는 순열 nPr의 경우의 수를 가지는 쌍에 대한 튜플 형식으로 반환된다.
아래는 시도해봤으나 잘못된 아이디어로 설계한 바람에 작동은 올바르게 문제없이 되나 정답을 리턴해주지 못하는 코드이다
def posible_num(k,dungeons): count=0 for dungeon in dungeons: if dungeon[0]>k: continue else: k-=dungeon[1] count+=1 return count def solution(k, dungeons): limit_value=[] #최소 필요 피로도 종류 담을 리스트 consum_value=[]#소모 피로도 종류 담을 리스트 method1=[] #소모 피로도가 작은 것부터 method2=[] #최소 필요 피로도가 큰 것부터 #indexing_dungeons=[] count_list=[] for i in range(len(dungeons)): limit_value.append(dungeons[i][0]) consum_value.append(dungeons[i][1]) #indexing_dungeons.append([i,dungeons[i][0],dungeons[i][1]]) limit_value.sort(reverse=True) #큰순서부터 consum_value.sort() #소비 작은것부터 한것이랑 최소 큰것부터 한거랑 비교해서 값 큰것 선택 #순서 정렬기준 소비작은것, 최소 큰것 순으로 for con in range(len(consum_value)): if consum_value[con-1] == consum_value[con]: if consum_value[con] != consum_value[con+1]: sort_lim=sorted(method1[-1*consum_value.count(consum_value[con]):][1],reverse=True) for lim2 in sort_lim: for j in range(len(dungeons)): if lim2 == dungeons[j][0] and consum_value[con] == dungeons[j][1]: method1.append(dungeons[j]) continue for i in range(len(dungeons)): if consum_value[con] == dungeons[i][1]: method1.append(dungeons[i]) count_list.append(posible_num(k,method1)) #순서 정렬 기준 최소 큰것, 소비작은것 순으로 for lim in range(len(limit_value)): if limit_value[lim-1] == limit_value[lim]: if limit_value[lim] != limit_value[lim+1]: sort_con=sorted(method2[-1*limit_value.count(limit_value[lim]):][0]) for con2 in sort_con: for j2 in range(len(dungeons)): if con2 == dungeons[j2][1] and limit_value[lim] == dungeons[j2][0]: method2.append(dungeons[j2]) continue for i2 in range(len(dungeons)): if limit_value[lim] == dungeons[i2][0]: method2.append(dungeons[i2]) count_list.append(posible_num(k,method2)) answer=max(count_list) return answer
더보기SQL 관련 질문한 것들
우선 좀 애매해서 크게 의미가 없었던 질문은 노션에만 기록으로 남겨두고 나머지 부분에 대해서만 블로그에 기록으로 남기겠다
- 가끔 구문이라고 부르는 부분들이 있는데 보통 메인쿼리 밖에서 따로 구동되는 쿼리들을 구문이라고 주로 표현하는 듯하다고 말씀해주셨다(정확하지는 않다고... 사실 엄밀히 구별해서 말하는 경우도 잘없는 듯하다 표현이 계속 나오는데 명확히 알 수 있다면 좋을 듯하여 한 번 여쭤보았다)
- 대소문자 구별해서 적는 것 확실히 추천! -> 기준 어떻게해서 어떤 것을 대문자, 어떤 것을 소문자로?
->시스템 자체적으로 주어지는 함수 등은 모두 대문자로 그외 나머지는 컬럼명, 테이블명, 값, 내용 등은 소문자로
- round가 계산 시 무시가 되는 듯하다 버그인가?
https://school.programmers.co.kr/learn/courses/30/lessons/157339
해당 문제에서 나왔던 쿼리이고
이렇게 하면 정상적으로 나왔는데SELECT disc.CAR_TYPE,DURATION_TYPE, disc.DISCOUNT_RATE, 30*rental.DAILY_FEE month_FEE, round(30*rental.DAILY_FEE*(1-disc.DISCOUNT_RATE/100)) FEE FROM CAR_RENTAL_COMPANY_DISCOUNT_PLAN disc join CAR_RENTAL_COMPANY_CAR rental on disc.CAR_TYPE = rental.CAR_TYPE where disc.DURATION_TYPE = '30일 이상'# and disc.CAR_TYPE = rental.CAR_TYPE
이렇게 하면 round 부분이 1로 계산 되듯이 무시가 되었다SELECT disc.CAR_TYPE,DURATION_TYPE, disc.DISCOUNT_RATE, 30*rental.DAILY_FEE month_FEE, 30*rental.DAILY_FEE*round((1-disc.DISCOUNT_RATE/100)) FEE FROM CAR_RENTAL_COMPANY_DISCOUNT_PLAN disc join CAR_RENTAL_COMPANY_CAR rental on disc.CAR_TYPE = rental.CAR_TYPE where disc.DURATION_TYPE = '30일 이상'# and disc.CAR_TYPE = rental.CAR_TYPE
1로 계산 되듯이 무시되었다!!! 쿼리 작성하여 문제 풀 때는 전혀 인지 못했으나 질문할 때 어렴풋 눈치가 살짝 챘다... 튜터님이 그거 반올림되서 1되서 1로 곱해진 것 아니에요? 라고 답해주시는 순간 살짝 멍해졌었다 왜 이 쉽고 간단한 사실을 눈치 못챘는지.. 째든 다음 질문 내용으로 넘어가도록 하겠다
- 앞 부분에서 미리 order해두고 그 테이블에 따로 조작안해주고 그대로 가져온다면 order된 채로 남아있기 때문에 따로 order안해줘도 order 남아있다(어차피 order 한번 더해줘도 상관 없다는 것 봐서는 order는 연산에 크게 영향 끼치지는 않는 듯하다)
- 프로그래머스에서 %서울%하면 오답 처리 되고 서울%로 해야만 정답 처리 되는 문제가 있었는데 주어진 문제의 데이터가 아니라 다른 상황에서도 문제에서 의도한 대로 풀려면 서울로 시작하는 조건이여야 한다고 출제자가 의도해서 정답 판정내릴때 서울%로 해야만 정답되게 설정해둬서 그런듯 하다
- explain 따로 시간을 보기는 따로 프로그램에서 설정을 해줘야 하는 듯하고 프로그래머스에서 참고하는 방법은 대강 말로만 설명을 간략히 적어본다면 id가 서브쿼리를 사용한 경우 3번 연산을 해줬고 서브쿼리 없이 join한 경우는 2번 연산해줬다(id가 3개, 2개로 표시 됬음) 그리고 rows랑 filtered를 보고 대략적으로나마 얼만큼 많은 양의 데이터를 가져와서 연산에 사용하였는지 볼 수 있는데 이는 비율이라 정확하지는 않고 대략적으로나마 대강 이렇구나 알 수 있다고 하셨다(결론적으로 직접 시간 비교하고 싶으면 따로 더 서칭해서 설정하는 법을 알아와야함)
- 날짜를 조건으로 필터링 할때 표시 방식들과 관련 내용
WHERE date_format(PRODUCE_DATE,'%Y')=2022 and date_format(PRODUCE_DATE,'%m')=5 WHERE date_format(PRODUCE_DATE,'%Y-%m')='2022-05' WHERE year(PRODUCE_DATE)='2022' and month(PRODUCE_DATE)='5' WHERE year(PRODUCE_DATE)=2022 and month(PRODUCE_DATE)=5 WHERE date_format(hst.START_DATE,'%Y-%m-%d') BETWEEN '2022-09-01' and '2022-09-31'
보통 date_format을 편해서 많이 사용하며 다른것과 성능차이는 그렇게 차이 나지 않는다고 한다 그리고 =뒤에는 보통 문자열로 하면 맞는 경우가 많다고 하니 참고하면 좋을 듯하다#에러는 아닌데 값이 정상적으로 안나옴 WHERE date_format(PRODUCE_DATE,'%Y')='2022' and date_format(PRODUCE_DATE,'%m')='5' WHERE date(hst.START_DATE) BETWEEN '2022-09-01' and '2022-09-31' WHERE hst.START_DATE BETWEEN '2022-09-01' and '2022-09-31' WHERE hst.START_DATE BETWEEN 2022-09-01 and 2022-09-31 WHERE date_format(PRODUCE_DATE,'%Y-%m')=2022-5 WHERE date_format(PRODUCE_DATE,'%Y-%m')=2022-05 #이의 경우는 에러남 WHERE date_format(PRODUCE_DATE,'%Y-%m')=2022,5 #SQL 실행 중 오류가 발생하였습니다. #You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ',5 #GROUP BY 1 #ORDER BY 3 desc,1' at line 5
- full outer join은 어떻게 하는지? ->mysql은 full join없다고 함! (튜터님도 잘 몰랐던 사실이라 검색을 좀 많이 해보시고 알려주셨는데 없어서 대체하기 위해서 Left join과 right join이 있는 것이라고 함)
- 서브 쿼리 부분 작동하는 방식->뭐라고 적어야 할지 모르겠으나 순서 맞춰서 하고 행별로 판단해서 데이터 불러오는게 맞으나, 첫행 할때만 서브커리 연산해서 결과값 저장해두고 그다음 행부터는 결과값으로 비교함
쿼리 작동 순서가 FROM-WHERE-GROUP-HAVING-SELECT-ORDER-LIMIT순으로 기본적으로 작동한다고 생각하면 된다(서브쿼리부터 하는 게 아닌!) 그리고 예외적으로 가끔 상황따라 순서가 조금 바뀔 수 있다고 하셨는데 group, having쪽이 바뀔수도 있다고 하셨는데 잘 이해가 안되고 떠오르는 상황이 없어 나중에 그런 상황을 만나면 다시 여쭤보거나 해야할듯하다
- join한 테이블도 Alias할 수 있는가? ->튜터님도 잘 모르시는데 아마 되지 않을까 싶어서 같이 튜터님이 보시는 중에 테스트 해봤는데 안되는 것같다 ->일단 안 된다고 생각하면 될듯함!(사실 쓸일은 사실상 없을 것 같은데 혹시나 할 수 있나 궁금해서 했음)
- 위에 것에 관련해서 서브쿼리 where절 등에 써줄 때 연결할 테이블이 조인하여서 가져오는 테이블이라면 어떻게 해줘야 하는지 궁금해서 방법 이리 저리 궁리하다가 떠오른 궁금증이였다
(제대로 이해는 못하였으나 들은 바로는)무조건 서브쿼리는 따로 돌기 때문에 join하기전 테이블 개별중 하나와 연결을 따로 해야 한다고 하심(적으면서 좀 이해 된듯 함 join은 메인쿼리에서 수행하는 것이기 때문에 서브쿼리는 그래도 따로 돌기 때문에 join한 테이블에 대해 알 수 없으므로) 그리고 깜빡하고 못물어보았으나SELECT concat('/home/grep/src/',brd.BOARD_ID,'/',file.FILE_ID,file.FILE_NAME,file.FILE_EXT) FILE_PATH, file.BOARD_ID FROM USED_GOODS_FILE file join USED_GOODS_BOARD brd on file.BOARD_ID = brd.BOARD_ID WHERE brd.VIEWS = (select max(brd_sub.VIEWS) from USED_GOODS_BOARD brd_sub where brd_sub.BOARD_ID=brd.BOARD_ID) ORDER BY file.FILE_ID desc
이것 처럼 연결할 쪽을 한쪽은 테이블명.연결할 컬럼으로 해주지 않아도 되었던 것 같았는데 이부분은 차후에 질문할 때 다시 물어보기로 하겠다SELECT concat('/home/grep/src/',brd.BOARD_ID,'/',file.FILE_ID,file.FILE_NAME,file.FILE_EXT) FILE_PATH FROM USED_GOODS_FILE file join USED_GOODS_BOARD brd on file.BOARD_ID = brd.BOARD_ID WHERE brd.VIEWS = (select max(brd_sub.VIEWS) from USED_GOODS_BOARD brd_sub where brd_sub.VIEWS=VIEWS) ORDER BY file.FILE_ID desc
오늘은 프로젝트 발제를 하였고 프로젝트 기간이 시작되었다 그에따라 개인 공부할 시간이 거의 없이 계속 회의와 자료찾기로 이어졌었다. 잠깐 쉴 때 다행히 SQL코드카타가 쉬운 부분이였어서 금방 해결하였고, 파이썬은 계속 손도 못댈듯하여 저번에 모듈 등을 쓰지않고 독창적인 풀어볼려고 했던 문제를 그 방식으로 푸는 것을 포기하고 질문하기를 잠깐 참조하여 새로운 모듈을 알고 적용하여 간단히 풀어 제출하였다. 그리고 저녁시간에 저녁 먹고와서 튜터님께 질문할려고 했던 부분중 정리되어있는 내용들(그래도 거의 다 정리해 두었었다) 쭉 물어보는 시간을 가질 수 있었다 오늘 개인 공부한 것이 없어서 적을 내용이 딱히 없을 듯 하였는데 질문한 내용이 많다보니 그 부분을 적으니 생각보다 양이 많았다 프로젝트 기간 동안은 사용하기 위해 새로 공부한 내용 정도만 정리가 된다면 블로그에 올리는 것 외에는 거의 적을 내용이 없을 듯하다.
'스파르타 > TIL(Today I Learned)' 카테고리의 다른 글
2024-01-13~2024-01-14 (1) 2024.01.15 2024-01-1 (2) 2024.01.12 2024-01-10 (0) 2024.01.10 2024-01-09 (2) 2024.01.09 2024-01-08 (0) 2024.01.08