๐ฎRIOT API ๋ถ์ ํ๋ก์ ํธ(8) - GrandMaster ํฐ์ด์ DB๊ตฌ์ถ
โ ๋ฐฐ๊ฒฝ : API๋ฅผ ํ์ฉํด DB ๊ตฌ์ถ ๋ฐ ์๋น์ค ์ด์ ๊ฒฝํ
โ ๋ชฉ์ : RIOT LOL API๋ฅผ ํ์ฉํด '๊ทธ๋๋๋ง์คํฐ' ๊ตฌ๊ฐ์ ์ค์ ํฐ์ด๋ฅผ ํ์ธ ๊ฐ๋ฅํ ์น ์๋น์ค ๋ง๋ค๊ธฐ
โ ๊ธฐ๊ฐ : 2024.08.25 ~ 2024.09.22 (์์ )
โ ์ธ์ : 1๋ช (2๋ช ์ผ๋ก ์์ํ์ผ๋ ํ๋ก์ ํธ์์ ํ์ฐจํ์ฌ ํผ์ ๋ค ํ๊ฒ ๋์์ต๋๋ค)
โ ์ญํ : python์ ํ์ฉํด api ํธ์ถ ๋ฐ ์ ์ ๋ค์ ์ ๋ณด๊ฐ ๋ด๊ธด DB ์์ฑ,
SQL ์ฟผ๋ฆฌ๋ฌธ์ ํ์ฉํด ๋ฐ์ดํฐ ์ถ์ถ ๋ฐ ๊ฐ๊ณต,
Tableau๋ฅผ ํ์ฉํด DB ์งํ ๋์๋ณด๋ ์์ฑ,
html, flask๋ฅผ ํ์ฉํ์ฌ ์นํ์ด์ง ๊ตฌํ
LEAGUE - VR - GRANDMASTER - queue๋ฅผ ํตํด summonerID ์ถ์ถ
import requests
def get_grandmaster_summoner_ids(api_key):
request_header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0",
"Accept-Language": "ko,en;q=0.9,en-US;q=0.8",
"Accept-Charset": "application/x-www-form-urlencoded; charset=UTF-8",
"Origin": "https://developer.riotgames.com",
"X-Riot-Token": api_key # ํ๊ฒฝ ๋ณ์์ ์ ์ฅ๋ API ํค ์ฌ์ฉ
}
base_url = "https://kr.api.riotgames.com/lol/league/v4/grandmasterleagues/by-queue/RANKED_SOLO_5x5"
# ๊ทธ๋๋๋ง์คํฐ ํ๋ ์ด์ด ๋ฐ์ดํฐ๋ฅผ Riot API์์ ๊ฐ์ ธ์ด
response = requests.get(base_url, headers=request_header)
if response.status_code == 200:
data = response.json()
summoner_ids = [entry['summonerId'] for entry in data['entries']]
return summoner_ids
else:
return {"error": f"๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฐ ์คํจํ์ต๋๋ค. ์ํ ์ฝ๋: {response.status_code}"}
# API ํค ์ค์
api_key = "my_api"
# ํจ์ ํธ์ถ
grandmaster_summoners = get_grandmaster_summoner_ids(api_key)
# ๊ฒฐ๊ณผ ์ถ๋ ฅ
print(len(grandmaster_summoners))
๊ทธ๋๋๋ง์คํฐ ํฐ์ด๋ ๋ค๋ฅธ ํฐ์ด๋ค๊ณผ ๋ฌ๋ฆฌ tier, division ๊ฐ์ ์ ๋ณด๋ฅผ ํ์๋ก ํ์ง ์์ต๋๋ค.
๊ทธ ๋์ Riot API์์๋ ๊ทธ๋๋๋ง์คํฐ์ ๋ง์คํฐ ํฐ์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ฐ ์ ์ฉ ์๋ํฌ์ธํธ๋ฅผ ํตํด ์ ๊ณตํ๊ณ ์์ต๋๋ค.
์ด๋ฒ ์ฝ๋์์๋ ๊ทธ๋๋๋ง์คํฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด ์๋ ์๋ํฌ์ธํธ๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
๊ทธ๋๋๋ง์คํฐ๋ ๋ง์คํฐ ํฐ์ด์์๋ ์ผ๋ฐ์ ์ธ ํฐ์ด/๋๋น์ ์์คํ ๊ณผ ๋ค๋ฅด๊ฒ ํ์ด์ง๋ ํ์ํ์ง ์์ต๋๋ค.
SUMMONER - V4 ์์ PUUID ์ถ์ถ
import aiohttp
import asyncio
from asyncio_throttle import Throttler # Throttler๋ฅผ ์ฌ์ฉํ์ฌ API ์์ฒญ ์๋ฅผ ์ ์ด
# ๋น๋๊ธฐ์ ์ผ๋ก ์ํ์ฌ PUUID๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์
async def fetch_summoner_puuid(session, summoner_id, header, throttler):
url = f"https://kr.api.riotgames.com/lol/summoner/v4/summoners/{summoner_id}"
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0",
"Accept-Language": "ko,en;q=0.9,en-US;q=0.8",
"Accept-Charset": "application/x-www-form-urlencoded; charset=UTF-8",
"Origin": "https://developer.riotgames.com",
"X-Riot-Token": "my_api"
}
async with throttler: # Throttler๋ก ์์ฒญ ์๋๋ฅผ ์ ์ด
async with session.get(url, headers=header) as response:
if response.status == 429: # Rate limit ์ฒ๋ฆฌ
retry_after = int(response.headers.get('Retry-After', 60))
print(f"Rate limit exceeded. Sleeping for {retry_after} seconds for {summoner_id}.")
await asyncio.sleep(retry_after)
return await fetch_summoner_puuid(session, summoner_id, header, throttler) # ์ฌ๊ท ํธ์ถ๋ก ์ฌ์๋
elif response.status == 200:
summoner_data = await response.json()
return summoner_data.get('puuid')
else:
print(f"Error: {response.status} for summoner ID {summoner_id}")
return None
# ๋น๋๊ธฐ์ ์ผ๋ก ์ฌ๋ฌ ์ํ์ฌ์ PUUID๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์
async def fetch_all_summoner_puuids(api_key, grandmaster_summoners):
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0",
"Accept-Language": "ko,en;q=0.9,en-US;q=0.8",
"Accept-Charset": "application/x-www-form-urlencoded; charset=UTF-8",
"Origin": "https://developer.riotgames.com",
"X-Riot-Token": "my_api"
}
summoner_puuid_list = []
throttler = Throttler(rate_limit=20, period=1) # ์ด๋น 20๊ฐ์ ์์ฒญ๋ง ํ์ฉ, riot api๊ฐ ์ด๋น 20๊ฐ๊ฐ ํ๊ณ์
async with aiohttp.ClientSession() as session:
tasks = []
for summoner_id in grandmaster_summoners:
task = fetch_summoner_puuid(session, summoner_id, header, throttler) # ๋น๋๊ธฐ ์์
์์ฑ
tasks.append(task)
# ๋ชจ๋ ๋น๋๊ธฐ ์์
์ ๋ณ๋ ฌ๋ก ์คํ
responses = await asyncio.gather(*tasks)
for puuid in responses:
if puuid:
summoner_puuid_list.append(puuid)
return summoner_puuid_list
# ๋น๋๊ธฐ ์คํ์ ์ํ ๋ฉ์ธ ํจ์
async def main():
api_key = "MY_API" # ํ๊ฒฝ ๋ณ์์์ API ํค ๊ฐ์ ธ์ค๊ธฐ
# ์ฌ๋ฌ ์ํ์ฌ์ PUUID๋ฅผ ๋น๋๊ธฐ๋ก ๊ฐ์ ธ์ค๊ธฐ
summoner_puuid_list = await fetch_all_summoner_puuids(api_key, grandmaster_summoners)
# ๊ฒฐ๊ณผ ๋ฐํ
return summoner_puuid_list
# ๋น๋๊ธฐ ํจ์ ์คํ
summoner_puuid_list = await main()
# ๊ฒฐ๊ณผ ์ถ๋ ฅ
print(f"Summoner PUUID List: {summoner_puuid_list}")
12๋ถ ์ ๋์ ์๊ฐ์ด ๊ฑธ๋ ค์ ํด๋น ๋ฐ์ดํฐ๊ฐ ์ถ์ถ ๋์์ต๋๋ค.
์ด์ SQL DB์ ์ ์ฅํ๊ฒ ์ต๋๋ค. ์ฌ์ค MATCHID ์ถ์ถํ ๋ ์ ์ฅํ๋ฉด ๋์ง๋ง ๋ฐ์ดํฐ ๋ ์๊ฐ๊น๋ด ๋ฏธ๋ฆฌ ์ ์ฅํฉ๋๋ค!
MYSQL DB์ PUUID ์ ์ฅ ๋ฐ ๋ถ๋ฌ์ค๊ธฐ
import aiomysql
import asyncio
# MySQL์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ํจ์
async def save_puuids_to_mysql(summoner_puuid_list, db_config):
# MySQL์ ์ฐ๊ฒฐ
conn = await aiomysql.connect(
host=db_config["host"],
port=db_config["port"],
user=db_config["user"],
password=db_config["password"],
db=db_config["db"],
charset='utf8mb4'
)
async with conn.cursor() as cursor:
for puuid in summoner_puuid_list:
# ๋ฐ์ดํฐ ์ฝ์
query = """
INSERT INTO summoner_puuid (puuid)
VALUES (%s)
ON DUPLICATE KEY UPDATE puuid=VALUES(puuid)
"""
await cursor.execute(query, (puuid,))
# ๋ณ๊ฒฝ ์ฌํญ ์ปค๋ฐ
await conn.commit()
# MySQL ์ฐ๊ฒฐ ์ข
๋ฃ
conn.close()
# ๋น๋๊ธฐ ์คํ์ ์ํ ๋ฉ์ธ ํจ์
async def main():
# MySQL ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๋ณด ์ค์
db_config = {
"host": "localhost", # MySQL ์๋ฒ ํธ์คํธ
"port": 3306, # MySQL ํฌํธ
"user": "root", # MySQL ์ฌ์ฉ์ ์ด๋ฆ
"password": "๋น๋ฐ๋ฒํธ ์
๋ ฅ", # MySQL ๋น๋ฐ๋ฒํธ
"db": "riot_game_db" # ์ฌ์ฉํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๋ฆ
}
# PUUID ๋ฐ์ดํฐ๋ฅผ MySQL์ ์ ์ฅ
await save_puuids_to_mysql(summoner_puuid_list, db_config)
# ๋น๋๊ธฐ ํจ์ ์คํ
await main()
์ ์ฅ์ ์ ๋์๊ณ ๋ค์ ์ ๋๋ก ๋ถ๋ฌ์ฌ ์ ์๋์ง ํ์ธํด๋ด ์๋ค.
import mysql.connector
# MySQL ์๋ฒ์ ์ฐ๊ฒฐ
connection = mysql.connector.connect(
host="localhost", # MySQL ์๋ฒ ํธ์คํธ ์ด๋ฆ (๋ณดํต ๋ก์ปฌ์ผ ๊ฒฝ์ฐ localhost)
user="root", # MySQL ์ฌ์ฉ์ ์ด๋ฆ
password="0224", # MySQL ์ฌ์ฉ์ ๋น๋ฐ๋ฒํธ
database="riot_game_db" # ์ฌ์ฉํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๋ฆ
)
# ์ฐ๊ฒฐ์ด ์ฑ๊ณตํ๋์ง ํ์ธ
if connection.is_connected():
print("MySQL ์ฐ๊ฒฐ ์ฑ๊ณต")
else:
print("MySQL ์ฐ๊ฒฐ ์คํจ")
MySQL ์๋ฒ์ ์ฐ๊ฒฐํ์ฌ DB๋ฅผ ์ ๋๋ก ๊ฐ์ง๊ณ ์์ต๋๋ค.
import pandas as pd
# ์ฟผ๋ฆฌ ์คํ ํ DataFrame์ผ๋ก ๋ณํ
query = "SELECT * FROM summoner_puuid" # ์ฌ์ฉํ ์ฟผ๋ฆฌ
df = pd.read_sql(query, connection)
# DataFrame ์ถ๋ ฅ
print(df)
summoner_puuid_list = df['puuid'].tolist()
์ ๊ฐ ์ธ ํ ์ด๋ธ๋ง์ SQL์์ ๊ฐ์ ธ์์ ํด๋น ํ ์ด๋ธ์ DFํ ํ๊ณ , ํ์ํ ์นผ๋ผ๋ง์ ๋ฆฌ์คํธ ํ์์ผ๋ก ๋ง๋ค์์ต๋๋ค.
MATCH-V4 ์์ MATCHID ๊ฐ์ ธ์ค๊ธฐ
import aiohttp
import asyncio
from asyncio_throttle import Throttler # asyncio_throttle ๊ฐ์ ธ์ค๊ธฐ
# ๋น๋๊ธฐ์ ์ผ๋ก ์ํ์ฌ matchID๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์
async def fetch_summoner_matchID(session, puuid, header, throttler):
url = f"https://asia.api.riotgames.com/lol/match/v5/matches/by-puuid/{puuid}/ids?type=ranked&start=0&count=1"
async with throttler: # ์์ฒญ ์๋๋ฅผ ์ ํํ๋ Throttler ์ฌ์ฉ
async with session.get(url, headers=header) as response:
if response.status == 429: # Rate limit ์ฒ๋ฆฌ
retry_after = int(response.headers.get('Retry-After', 60))
print(f"Rate limit exceeded for {puuid}. Sleeping for {retry_after} seconds.")
await asyncio.sleep(retry_after)
return await fetch_summoner_matchID(session, puuid, header, throttler) # ์ฌ์๋
if response.status == 200:
summoner_match_data = await response.json()
return {'puuid': puuid, 'match_ids': summoner_match_data}
else:
print(f"Error: {response.status} for PUUID {puuid}")
return {'puuid': puuid, 'match_ids': None}
# ๋น๋๊ธฐ์ ์ผ๋ก ์ฌ๋ฌ ์ํ์ฌ์ matchID๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์
async def fetch_all_summoner_matchIDs(api_key, summoner_puuid_list):
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0",
"Accept-Language": "ko,en;q=0.9,en-US;q=0.8",
"Accept-Charset": "application/x-www-form-urlencoded; charset=UTF-8",
"Origin": "https://developer.riotgames.com",
"X-Riot-Token": api_key
}
summoner_matchID_list = []
throttler = Throttler(rate_limit=20, period=1) # ์ด๋น ์ต๋ 20๊ฐ์ ์์ฒญ๋ง ํ์ฉ
async with aiohttp.ClientSession() as session:
tasks = []
for puuid in summoner_puuid_list:
task = fetch_summoner_matchID(session, puuid, header, throttler) # ๋น๋๊ธฐ ์์
์์ฑ
tasks.append(task)
# ๋ชจ๋ ๋น๋๊ธฐ ์์
์ ๋ณ๋ ฌ๋ก ์คํ
responses = await asyncio.gather(*tasks)
for response in responses:
if response and response.get('match_ids') is not None:
summoner_matchID_list.append(response)
return summoner_matchID_list
# ๋น๋๊ธฐ ์คํ์ ์ํ ๋ฉ์ธ ํจ์
async def main():
api_key = "my_api" # ํ๊ฒฝ ๋ณ์์์ API ํค ๊ฐ์ ธ์ค๊ธฐ
# ์ฌ๋ฌ ์ํ์ฌ์ matchID๋ฅผ ๋น๋๊ธฐ๋ก ๊ฐ์ ธ์ค๊ธฐ
summoner_matchID_list = await fetch_all_summoner_matchIDs(api_key, summoner_puuid_list)
# ๊ฒฐ๊ณผ ๋ฐํ
return summoner_matchID_list
# ๋น๋๊ธฐ ํจ์ ์คํ
summoner_matchID_list = await main()
# ๊ฒฐ๊ณผ ์ถ๋ ฅ
print(f"Summoner MatchID List: {summoner_matchID_list}")
์ต๊ทผ ํํ๋ง์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ต์๋ค.
MATCHID๋ฅผ ํ์ฉํด ๊ฒ์์ ๋ณด๋ฅผ ๋ถ๋ฌ์จ ๋ค์์ PUUID์ ๋ฆฌ์คํธ์ ์๋ ์ ๋ณด๋ง์ ๋จ๊ฒจ์ ๋ฝ๊ฒ ์ต๋๋ค.
์ฐ์ ์ ์ DB๋ฅผ ๊ตฌ์ถํด์ผ ํ๋๊น์.
MYSQL DB์ puuid, matchID ์ ์ฅ
import mysql.connector
# MySQL ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ
connection = mysql.connector.connect(
host="localhost", # MySQL ์๋ฒ ์ฃผ์
user="root", # MySQL ์ฌ์ฉ์๋ช
password="pw", # MySQL ๋น๋ฐ๋ฒํธ
database="riot_game_db" # ์ฌ์ฉํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๋ฆ
)
# ์ปค์ ์์ฑ
cursor = connection.cursor()
# puuid์ match_id ๋ฐ์ดํฐ๋ฅผ ํ
์ด๋ธ์ ์ฝ์
ํ๋ ํจ์
def insert_match_id(puuid, match_id):
sql = """
INSERT INTO summoner_list (puuid, match_id)
VALUES (%s, %s)
"""
cursor.execute(sql, (puuid, match_id))
# puuid์ ๊ฐ๊ฐ์ match_id๋ฅผ ํ
์ด๋ธ์ ์ฝ์
for entry in summoner_matchID_list:
puuid = entry['puuid']
match_ids = entry['match_ids']
for match_id in match_ids:
insert_match_id(puuid, match_id)
# ๋ณ๊ฒฝ์ฌํญ ์ปค๋ฐ
connection.commit()
# ์ปค์์ ์ฐ๊ฒฐ ์ข
๋ฃ
cursor.close()
connection.close()
์ ๋๋ก ์ ์ฅ๋์์ ํ์ธํ ์ ์์ต๋๋ค.
ํด๋น matchID๋ฅผ ๊ฐ์ง๊ณ ๊ฒ์์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ(puuid,summonerName)
import aiohttp
import asyncio
import mysql.connector
from asyncio_throttle import Throttler
# ๋น๋๊ธฐ์ ์ผ๋ก match ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์
async def fetch_match_data(session, match_id, api_key, throttler):
url = f"https://asia.api.riotgames.com/lol/match/v5/matches/{match_id}"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0",
"Accept-Language": "ko,en;q=0.9,en-US;q=0.8",
"Accept-Charset": "application/x-www-form-urlencoded; charset=UTF-8",
"Origin": "https://developer.riotgames.com",
"X-Riot-Token": api_key
}
async with throttler: # ์์ฒญ ์๋ ์ ํ
async with session.get(url, headers=headers) as response:
if response.status == 429: # Rate limit ์ฒ๋ฆฌ
retry_after = int(response.headers.get('Retry-After', 60)) # Retry-After ํค๋ ํ์ธ
print(f"Rate limit exceeded for match {match_id}. Sleeping for {retry_after} seconds.")
await asyncio.sleep(retry_after) # ๋น๋๊ธฐ ๋๊ธฐ
return await fetch_match_data(session, match_id, api_key, throttler) # ๋ค์ ์๋
elif response.status == 200:
match_data = await response.json() # JSON ๋ฐ์ดํฐ ๋ฐํ
queue_id = match_data.get('info', {}).get('queueId', None)
if queue_id == 420: # Solo Rank ๋ชจ๋ (Queue ID 420)๋ง ๊ฐ์ ธ์ด
return match_data
else:
print(f"Skipping match {match_id} because queueId is not 420")
return None
else:
print(f"Error: {response.status} for match ID {match_id}")
return None
async def fetch_all_matches(match_ids, api_key):
throttler = Throttler(rate_limit=20, period=1) # ์ด๋น 20๊ฐ์ ์์ฒญ์ผ๋ก ์ ํ
async with aiohttp.ClientSession() as session:
tasks = [fetch_match_data(session, match_id, api_key, throttler) for match_id in match_ids]
responses = await asyncio.gather(*tasks)
return [response for response in responses if response is not None]
# MYSQL ์ฐ๊ฒฐ ์ค์
def create_db_connection():
connection = mysql.connector.connect(
host="localhost", # MySQL ์๋ฒ ํธ์คํธ ์ด๋ฆ
user="root", # MySQL ์ฌ์ฉ์ ์ด๋ฆ
password="0224", # MySQL ์ฌ์ฉ์ ๋น๋ฐ๋ฒํธ
database="riot_game_db" # ์ฌ์ฉํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๋ฆ
)
return connection
# MYSQL์ match_id, puuid, summoner_name ๋ฐ์ดํฐ ์ฝ์
def insert_match_data(connection, match_data):
cursor = connection.cursor()
inser_query = """
INSERT INTO matches (match_id, puuid, summoner_name)
VALUES (%s, %s, %s)
"""
for match in match_data:
match_id = match.get('metadata', {}).get('matchId', 'Unknown Match ID')
for participant in match.get('info', {}).get('participants', []):
data = (
match_id,
participant.get('puuid'),
participant.get('summonerName')
)
try:
cursor.execute(inser_query, data)
except mysql.connector.Error as err:
print(f"Error: {err}")
connection.commit()
cursor.close()
# ๋น๋๊ธฐ ๋ฉ์ธ ํจ์
async def main():
api_key = "my_api" # Riot Games API ํค
# ์ฌ๋ฌ ๋งค์น ๋ฐ์ดํฐ๋ฅผ ๋น๋๊ธฐ๋ก ๊ฐ์ ธ์ค๊ธฐ
match_data_list = await fetch_all_matches(match_ids, api_key)
# MySQL ์ฐ๊ฒฐ ๋ฐ ๋ฐ์ดํฐ ์ฝ์
connection = create_db_connection()
insert_match_data(connection, match_data_list)
connection.close()
# asyncio ์คํ
await main()
์ด ์ฝ๋๋ฅผ ์คํํ์ฌ SQL์์ ๊ฐ์๋ฅผ ์ธ์ด๋ด ์๋ค.
4910๊ฐ๋ก ์ด๋ ๊ฒ ๋ง์ด ๋์ต๋๋ค...
๊ทธ ์ด์ ๋ ๊ทธ๋ง ํฐ์ด์ puuid ์ถ์ถ > ์ต๊ทผ ํํ matchID ์ถ์ถ > matchID 1๊ฐ์๋ 10๋ช ์ ์ ๋ณด๊ฐ ๋ค์ด์๊ธฐ์ ์ฐธ์ฌํ ์ฌ๋์ ๋ชจ๋ ์ ๋ณด๊ฐ ์ ๊ณต๋จ > ๊ทธ๋ฌ๋ฏ๋ก ๊ทธ๋ง ํฐ์ด puuid ์ถ์ถํ ๊ฒ๊ณผ ์ผ์น๋๋ ๊ฒ๋ง์ ๋จ๊ฒจ์ผ ํฉ๋๋ค
GrandMaster ํฐ์ด์ ํด๋น๋๋ ์ ์ ๋ง ์ถ์ถํ๊ธฐ
CREATE TABLE GM_users AS
SELECT m.match_id, m.puuid, m.summoner_name
FROM matches m
JOIN summoner_list s ON m.puuid = s.puuid;
๊ทธ๋๋ ์ฌ์ ํ 2611๊ฐ์ ๋๋ค. ์ผ๋จ ๊ทธ๋๋ ๋ง์คํฐ ํฐ์ด๊ฐ ์๋๊ฒฝ์ฐ๋ ๋ค ์ ์ธํ์์ต๋๋ค.
์ค๋ณต๋๋ ํญ์ด ์๋์ง ํ์ธํด๋ด ์๋ค.
#์ค๋ณตํญ ์๋์ง ํ์ธ
SELECT puuid, COUNT(*)
FROM GM_users
GROUP BY puuid
HAVING COUNT(*) > 1;
SELECT COUNT(*)
FROM (
SELECT puuid
FROM GM_users
GROUP BY puuid
HAVING COUNT(*) > 1
) AS duplicate_puuid;
๋์ผํ puuid๊ฐ ์ฌ๋ฌํ์ ์ฐธ์ฌํ๋ฉด์ matchID๋ง ๋ค๋ฅด๊ณ ์ค๋ณต๋ puuid๊ฐ ์๋ ๊ฒ ๊ฐ์ต๋๋ค.
SELECT *
FROM GM_users
WHERE puuid IN (
SELECT puuid
FROM GM_users
GROUP BY puuid
HAVING COUNT(DISTINCT summoner_name) > 1
);
puuid๊ฐ ์ค๋ณต๋๊ณ summonerName์ด ๋ค๋ฅธ ๋ชจ๋ ํ์ด ์๋์ง ์ฐพ์๋ดค๋๋ฐ ์๋ค์.
๋๋ณํ์ฌ๋์ด ์๋ ๋ด ๋๋ค. ๊ทธ๋ฌ๋ฉด ์ผ๋จ ์๋ก์ด ํ ์ด๋ธ์ ๋ง๋ค์ด์ ์ค๋ณต๊ฐ์ ์์ ์ค์๋ค.
CREATE TABLE GM_users2 AS
SELECT puuid, summoner_name
FROM GM_users;
puuid ๋ฆฌ์คํธ ๊ฐ์ 700๊ฐ์ธ๋ฐ ์ ๊ฐ ๊ฐ๊ณ ์๋ ๊ฒ์ธ 648๊ฐ ๋ฐ์ ์๋๋ค์.
์ด๋ค ๊ฐ๋ค์ด ๋๋ฝ ๋์๋์ง ํ์ธํด๋ด ์๋ค. duplicated_GM_users๋ผ๋ ํ ์ด๋ธ์ ๋ ๋ง๋ค์์ต๋๋ค.
duplicated_GM_users ํ ์ด๋ธ์ ์๋ puuid์ summoner_list ํ ์ด๋ธ์ ์๋ puuid๋ฅผ ๋น๊ตํ์ฌ,
duplicated_GM_users ํ ์ด๋ธ์ ์๋ puuid ๊ฐ์ ํ์ธํ๋ ค๋ฉด LEFT JOIN ๋๋ NOT IN์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
SELECT puuid
FROM summoner_list
WHERE puuid NOT IN (
SELECT puuid
FROM duplicated_GM_users
);
SELECT COUNT(*) AS missing_puuid_count
FROM summoner_list
WHERE puuid NOT IN (
SELECT puuid
FROM duplicated_GM_users
);
์ญ์ 52๊ฐ๊ฐ ๋๋ฝ๋์๋ค์.
์์ธ์ ๋ค์๊ณผ ๊ฐ์ด ์๊ฐํด ๋ณผ ์ ์์ต๋๋ค.
์ผ๋ถ puuid๊ฐ ๊ฒ์ ์ ๋ณด ํ ์ด๋ธ์ ์กด์ฌํ์ง ์์์ ๋๋ฝ๋ ๊ฒ์ผ ์ ์์ต๋๋ค.
matchID์์ ๊ทธ๋๋๋ง์คํฐ ์ ์ ์ ๊ฒ์ ์ ๋ณด๊ฐ ์ผ๋ถ ๋๋ฝ๋ ๊ฒฝ์ฐ์ ๋๋ค.
๋ง์ฝ matchID๋ก ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํ๋ ๊ณผ์ ์์ ํํฐ๋ง์ด ์๋ชป๋์๊ฑฐ๋ ์ผ๋ถ ๋ฐ์ดํฐ๊ฐ ๋๋ฝ๋์๋ค๋ฉด,
700๊ฐ์ puuid๋ฅผ ์์ ํ ๊ฐ์ ธ์ค์ง ๋ชปํ์ ์ ์์ต๋๋ค.
๋๋ฝ๋ 52๋ช ์ ๋ํด์๋ ๊ฒ์ํ์ ์ Summoner not found๋ก ํํํ๊ฒ ์ต๋๋ค.
์ด๋ ๊ฒ ํ์ฌ puuid ์ summoner_name์ผ๋ก ์กฐํฉ๋ ๊ทธ๋๋๋ง์คํฐ ์ ์ 648๋ช ์ ๋ฐ์ดํฐ ๋ฒ ์ด์ค๋ฅผ ๊ตฌ์ถํ์์ต๋๋ค.
์ด์ ์ ์ ๊ฐ ์์ ์ ์ด๋ฆ์ ๊ฒ์ํ์ ์, ์ ๊ฐ ๋ง๋ DB์์ puuid๋ฅผ ํธ์ถํ์ฌ ๊ฒ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ฌ์ ์์ต๋๋ค!