상세 컨텐츠

본문 제목

[SQL] 글로벌 게임 플랫폼 플레이어 지표 및 GGR 조회 구조 설계

MySQL

by Jude_Juu 2026. 3. 5. 18:34

본문

 

분산된 플레이어 GGR/게임 지표를 통합하고 QA/운영에서 재사용 가능한 SQL 조회 구조를 설계


⚠️ 문제 정의

  • 플레이어별 GGR 산출 기준 불명확 → 담당자별 계산 방식 상이
  • 모니터링으로 실시간 확인 가능한 쿼리 설계
  • 복잡한 SQL로 조회/검증 비효율
  • 대용량 데이터 조회 성능 저하

🛠️ 수행 내용

역할 테이블 (가칭) 조인방식 설명
기본 플레이어 정보 alias1 기준 테이블 플레이어 ID, 이메일, 닉네임, 국가, 사이트, 소속 유형 등
플레이어 소속/에이전트 alias2 LEFT JOIN 각 플레이어의 Agent 코드 조회
게임별 통계 alias3 LEFT JOIN Poker GGR, Casino GGR, Reward, T/O 등 핵심 수익 지표
최신 개인 정보 alias4 OUTER APPLY 조건에 따라 최신 Tag / Code(가칭) 값 추출
플레이어 태그 alias5 서브쿼리 COUNT, 문자열 집계(STUFF + FOR XML PATH)로 태그 목록 생성
  • Player 기본 정보, Agent/Offline Code, 태그, 게임 통계 등 핵심 컬럼 구조 정의
  • 목적별 SQL 조회 구조 설계 (전체 분석 / GGR 중심 / 기본 조회)
  • 불필요 컬럼 제거, 조건별 그룹화 및 필터 적용으로 조회 효율 개선
  • OUTER APPLY 활용해 최신 player 정보 테이블 추출
  • QA/운영 공통 활용 가능한 데이터 조회 가이드 문서화
OUTER APPLY 사용 포인트
1. 언제쓰는 게 좋을지:
 기준 테이블 행마다 최신/특정 조건 데이터를 가져올 때
2. 유용한 점: LEFT JOIN으로는 구현하기 어려운 조건/정렬 적용 가능
                     기준 행별 다른 최신 데이터를 유연하게 가져올 수 있음
3. 주의할 점: 
데이터 양 많으면 성능 영향 가능 → 인덱스 최적화 필요 
                     가독성을 위해 주석과 함께 사용

 

더보기
더보기
SELECT
    -- 1. 기본 정보
	p.Id AS [Player ID],
    ISNULL(p.Email, '') AS [Email Address],
    ISNULL(p.MobileNumber, '') AS [Mobile Number],
    p.Username AS [Username],
    ISNULL(p.Nickname, '') AS [Nickname],
    CASE 
        WHEN p.AssociationType = 0 THEN 'Brand'
        WHEN p.AssociationType = 1 THEN 'Affiliate'
        WHEN p.AssociationType = 2 THEN 'Agent'
        ELSE CAST(p.AssociationType AS VARCHAR) 
    END AS [AssociationType],
    
    -- 2. PlayerAgent 테이블의 Code 값
    ISNULL(pa.Code, '') AS [Agent],
    
    -- SiteId == SiteName
    CASE p.Site
        WHEN 0 THEN 'None' WHEN 1 THEN 'GGPCOM' WHEN 2 THEN 'GGPEU' WHEN 3 THEN 'GGPPL'
        WHEN 4 THEN 'GGPDE' WHEN 5 THEN 'GGPNL' WHEN 6 THEN 'GGPRO' WHEN 7 THEN 'GGPJP'
        WHEN 8 THEN 'GGPBE' WHEN 9 THEN 'GGPCZ' WHEN 10 THEN 'GGPUK' WHEN 11 THEN 'GGPOK'
        WHEN 12 THEN 'GGPUKE' WHEN 13 THEN 'SevenXL' WHEN 14 THEN 'Natural8' WHEN 15 THEN 'DavaoPoker'
        WHEN 16 THEN 'GGPRU' WHEN 17 THEN 'GGPHU' WHEN 18 THEN 'GGPNG' WHEN 19 THEN 'GGPCW'
        WHEN 20 THEN 'TWOACE' WHEN 22 THEN 'GGPBR' WHEN 23 THEN 'GGPUA' WHEN 24 THEN 'EVPUKE'
        WHEN 25 THEN 'GGPFI' WHEN 27 THEN 'WSOPON' WHEN 28 THEN 'N8IN' WHEN 29 THEN 'GGPPH'
        WHEN 30 THEN 'GGPDK' WHEN 31 THEN 'OCNP' WHEN 32 THEN 'PokerArabia' WHEN 33 THEN 'GGVCOM'
        WHEN 34 THEN 'GGPBG' WHEN 35 THEN 'GGPBA' WHEN 36 THEN 'GGPSE' WHEN 37 THEN 'GGVSYS'
        WHEN 38 THEN 'GGVON'
        ELSE CAST(p.Site AS VARCHAR)
    END AS [Site],

    ISNULL(p.Country, '') AS [Country],
    ISNULL(CAST(p.AffiliateMemberId AS VARCHAR), '') AS [Affiliate Id],
    
    -- 3. IsOfflineCode 조건 배분
    ISNULL(ppi_latest.[B tag], '') AS [B tag],
    ISNULL(ppi_latest.[Offline Code], '') AS [Offline Code],
    
    -- 4. 태그
    (SELECT COUNT(*) 
     FROM GGCoreGGPCOM.dbo.PlayerTag pt 
     WHERE pt.PlayerId = p.Id) AS [tag_count],
     
    ISNULL((SELECT STUFF((
        SELECT ',' + t.Name
        FROM GGCoreGGPCOM.dbo.PlayerTag pt
        JOIN GGCoreGGPCOM.dbo.Tag t ON pt.TagId = t.Id
        WHERE pt.PlayerId = p.Id
        FOR XML PATH('')), 1, 1, '')), '') AS [Tag],

    -- 5. 게임 통계 
    SUM(ISNULL(pgs.PokerGGR, 0)) AS [Poker GGR],
    SUM(ISNULL(pgs.CasinoGGR, 0)) AS [Casino GGR],
    SUM(ISNULL(pgs.FishBuffetReward, 0) + ISNULL(pgs.StreamerReward, 0)) AS [Reward Program],   
    SUM(ISNULL(pgs.CasinoContribution, 0)) AS [Casino Contribution],
    SUM(ISNULL(pgs.ProfitAndLossPoker, 0)) AS [Poker P&L],
    SUM(ISNULL(pgs.NetworkGiveaway, 0)) AS [Network Giveaway],
    SUM(ISNULL(pgs.TournamentOverlayPlayerDeducted, 0)) AS [T/O],
    SUM(ISNULL(pgs.RakedHands, 0)) AS [Raked Hands],
    SUM(ISNULL(pgs.NonRakedHands, 0)) AS [Non Raked Hands],
    SUM(ISNULL(pgs.OceanRewards, 0)) AS [Ocean Rewards],
    SUM(ISNULL(pgs.OceanRewardsCostPoker, 0)) AS [Poker Reward Cost],
    SUM(ISNULL(pgs.OceanRewardsCostCasino, 0)) AS [Casino Reward Cost]

FROM 
    GGCoreGGPCOM.dbo.Player p
LEFT JOIN 
    GGCoreGGPCOM.dbo.PlayerAgent pa ON p.Id = pa.PlayerId
LEFT JOIN 
    GGCoreGGPCOM.dbo.PlayerGameStatistics pgs ON p.AccountId = pgs.AccountId 
OUTER APPLY (
    SELECT TOP 1 
        CASE WHEN ppi.IsOfflineCode = 0 THEN ppi.BTag ELSE NULL END AS [B tag],
        CASE WHEN ppi.IsOfflineCode = 1 THEN ppi.BTag ELSE NULL END AS [Offline Code]
    FROM GGCoreGGPCOM.dbo.PlayerPersonalInformation ppi
    WHERE ppi.PlayerId = p.Id
    ORDER BY pgs.PokerGGR DESC 
) AS ppi_latest


-- 조회 대상 조건입력
WHERE 
    [조건입력]
    
GROUP BY 
    p.Id, p.MobileNumber, p.Email, p.Username, p.Nickname, p.AssociationType, p.Site,
    pa.Code, p.Country, p.AffiliateMemberId,
    ppi_latest.[B tag], ppi_latest.[Offline Code]
ORDER BY 
    [Poker GGR] DESC;

📊 쿼리 요약

  • 기본 정보: ID, Email, Mobile, Nickname, Site, Country 등 
  • 소속/Agent: Agent 코드, Atag / OffCode 조건 처리
  • 태그: tag_count, Tag 문자열 집계
  • 게임 통계: 포커 총 수익, 카지노 총 수익, 리워드, 카지노 기여금, 포커 손익, 토너먼트 차감액 등 핵심 수익 지표핵심 지표
  • 최신 개인 정보: OUTER APPLY로 최신 Player정보 테이블에서 추출
  • 쿼리 구조: 조건별 그룹화, Poker GGR 기준 정렬
  • 최적화: 불필요 컬럼 제거, 필터 적용으로 조회 성능 향상

🎯 결과

  • 플레이어 GGR/지표 기준 통일 → 데이터 해석 오류 제거
  • 데이터 조회 시간 단축 및 반복 작업 감소
  • QA/운영 공통으로 활용 가능한 표준 쿼리 확보
  • 신규 인원 온보딩 시 데이터 이해도 향상

🚀 역할 및 기여

  • 플레이어 지표 및 GGR 산출 로직 정의 주도
  • SQL 조회 구조 설계 및 표준화 수행
  • QA/운영 공통 데이터 기준 정립 기여

관련글 더보기