BESPIN Tech Blog
  • Home
  • Tech
    • CSP

      AWS

      GCP

      NCP

      Cloud

      Migration

      LZ, Control Tower

      Backup

      Monitoring

      Container

      Infra

      OS

      Middleware

      Data

      RDB

      Big Data Platform

      Application

      CI/CD

      BESPICK 구독하기 ㅣ 1668-1280

  • Trend
  • IT
최신 리포트 다운로드 지금 바로 문의하기
BESPIN Tech Blog
  • Home
  • Tech
    • CSP

      AWS

      GCP

      NCP

      Cloud

      Migration

      LZ, Control Tower

      Backup

      Monitoring

      Container

      Infra

      OS

      Middleware

      Data

      RDB

      Big Data Platform

      Application

      CI/CD

      BESPICK 구독하기 ㅣ 1668-1280

  • Trend
  • IT
최신 리포트 다운로드 지금 바로 문의하기
BESPIN Tech Blog
BESPIN Tech Blog
  • Tech
    • CSP
      • AWS
      • GCP
      • NCP
    • Cloud
      • Migration
      • LZ, Control Tower
      • Backup
      • Monitoring
      • Container
    • Infra
      • OS
      • Middleware
    • Data
      • RDB
      • Big Data Platform
    • Application
      • CI/CD
  • Trend
  • IT
  • Contact US
TECHRDBData

Mysql JSON function 현업 프로젝트에서의 사용 예

by 형래 김 2023년 06월 30일
2023년 06월 30일
22

안녕하세요, 오늘은 베스핀글로벌 이진협 님이 작성해 주신 ‘Mysql JSON function 현업 프로젝트에서의 사용 예’에 대해 알아보겠습니다.

1. mysql에서 data type이 text나 json 으로 되어있을 경우에 사용하면 좋다.

문자열에서 like 검색으로 사용하는 경우 abcde가 있는 걸 검색하는 경우 일반적으로 targetCondition like ‘%abcde%’로 검색하게 되는데 이 경우 test, testa, btest등, test가 포함된 모든 것을 찾는다. json 구조로 된 key를 찾거나 value를 찾거나 정상적인 json형태인지 찾을 수 있다.
SMP 프로젝트에서는 JSON 구조로 된 컬럼이 다수 존재하여 검색 등 데이터 가공 등, 사용할 일이 많이 있다.
JSON_EXTRACT, JSON_UNQUOTE, ->, ->>
{
    "mcc": {},
    "country": {},
    "triggerEvent": {
        "sendingDay": "Fri",
        "appEventFilter": "testdate",
        "eventSelection": "AE",
        "targetTimeUnit": "days",
        "targetTimeValue": 1,
        "sendingFrequency": "weekly",
        "test": "weekly", 
        "targetPeriodType": 0
    }
}
JSON_EXTRACT
  • LIKE 검색으로 weekly를 찾게되면 sendingFrequency, test 두개가 존재하여 원하는 검색을 할수 없다.
  • SELECT * FROM TEST_TABLE WHERE JSON_EXTRACT(targetCondition, '$.triggerEvent.sendingFrequency') LIKE %weekly%'; 이렇게 검색하는 경우 "sendingFrequency": "weekly" 를 찾을 수 있다.
  • 아직 LIKE가 쿼리에있는 이유는 JSON_EXTRACT(targetCondition, '$.triggerEvent.sendingFrequency') 를 실행하게되면 결과가 "weekly" 이렇게 나오기 때문이다. LIKE를 빼고 따옴표를 위해 JSON_UNQUOTE 사용할 수 있다.
JSON_UNQUOTE
  • SELECT * FROM AUTOMARKETING_PLAN WHERE JSON_UNQUOTE(JSON_EXTRACT(targetCondition, '$.triggerEvent.sendingFrequency')) ='weekly';쿼리가 길어서 보기 좋지 않다. -> 를 이용한 쿼리로 간단하게 표현할 수 있다.
->, ->> (JSON_EXTRACT)
  • SELECT * FROM AUTOMARKETING_PLAN WHERE targetCondition->'$.triggerEvent.sendingFrequency' LIKE '%weekly%';
  • 위와 같이 JSON_EXTRACT를 바꿀수 있다. 쿼리결과는 JSON_EXTRACT와 동일하다. ““따옴표가 포함되어 조회 되는 것을 확인 할 수 있다. JSON_UNQUOTE와 JSON_EXTRACT를 같이쓰는 방법인 ->>를 사용하여 따옴표가 제거된 결과를 조회 할 수 있다.
  • SELECT * FROM AUTOMARKETING_PLAN WHERE targetCondition->>'$.triggerEvent.sendingFrequency' = 'weekly';

2. JSON_SEARCH

["LIGHTBLUE","BLUE","DEEPPINK"]
  • SELECT * FROM MARKETING_META WHERE JSON_SEARCH(displayBgColor, 'one', 'BLUE') IS NOT NULL;JSON_SEARCH를 사용하면 찾고자 하는 위치를 찾을 수 있다. 결과는 "$[1]"

3. JSON_EXTRACT와 JSON_SEARCH를 이용한 복잡한 쿼리 예

{
    "button1": {
        "downloadUri": "http://www.naver.com",
        "referrer": {
            "basic": [],
            "specificUrl": [
                {
                    "filterLabel": "gmleetest10",
                    "variableName": "r_gmleetest10",
                    "filterType": "appReferrer",
                    "status": "LIVE"
                },
                {
                    "filterLabel": "fqwef",
                    "variableName": "r_qwefqwefqwefqwef",
                    "filterType": "appReferrer",
                    "status": "LIVE"
                }
            ],
            "downloadUrl": [
                {
                    "filterLabel": "gmleetest11",
                    "variableName": "r_gmleetest11",
                    "filterType": "appReferrer",
                    "status": "LIVE"
                },
                {
                    "filterLabel": "gmtest1",
                    "variableName": "p_gmtest1",
                    "filterType": "appFilter",
                    "status": "LIVE"
                }
            ],
            "sendPush": false
        }
    },
    "button2": {
        "downloadUri": "http://www.daum.net",
        "referrer": {
            "basic": [],
            "specificUrl": [
                {
                    "filterLabel": "wqfwef",
                    "variableName": "r_qwefqwef",
                    "filterType": "appReferrer",
                    "status": "LIVE"
                },
                {
                    "filterLabel": "gmleetest13",
                    "variableName": "r_gmleetest13",
                    "filterType": "appReferrer",
                    "status": "LIVE"
                }
            ],
            "downloadUrl": [
                {
                    "filterLabel": "wefw",
                    "variableName": "r_efwef",
                    "filterType": "appReferrer",
                    "status": "LIVE"
                },
                {
                    "filterLabel": "aaaaaaaa",
                    "variableName": "p_aaaaaaaa",
                    "filterType": "appFilter",
                    "status": "LIVE"
                }
            ],
            "sendPush": false
        }
    },
    "button3": {
        "downloadUri": "http://www.naver.com",
        "referrer": {
            "basic": [],
            "specificUrl": [
                {
                    "filterLabel": "aaaaaaaa",
                    "variableName": "p_aaaaaaaa",
                    "filterType": "appFilter",
                    "status": "LIVE"
                },
                {
                    "filterLabel": "App version",
                    "variableName": "appVersion",
                    "filterType": "basicReferrer",
                    "status": "LIVE"
                }
            ],
            "downloadUrl": [
                {
                    "filterLabel": "MID",
                    "variableName": "mid",
                    "filterType": "basicReferrer",
                    "status": "LIVE"
                }
            ],
            "sendPush": true
        }
    }
}

4. 위 JSON 예시로 referrer.specificUrl배열 안에 있는 variableName의 value가 appVersion인 데이터가 있는지 확인하는 예제를 만들어보겠다.

a. specificUrl의 배열을 뽑아낸다.
SELECT * FROM TEMP_TEST WHERE JSON_EXTRACT(contents, '$.*.referrer.specificUrl[*].variableName') IS NOT null ;

위 쿼리 결과는 

["r_gmleetest10", "r_qwefqwefqwefqwef", "r_qwefqwef", "r_gmleetest13", "p_aaaaaaaa", "appVersion"]

이다.

b. 이 결과를 이용하여 JSON_SEARCH로 JSON_EXTRACT를 감싸고 appVersion를 찾는다.
SELECT * FROM TEMP_TEST WHERE JSON_SEARCH(JSON_EXTRACT(contents, '$.*.referrer.specificUrl[*].variableName'),'one','appVersion') IS NOT NULL ;

5. 위 쿼리에서 JSON_EXTRACT를 복합적으로 사용하는 JSON_FUNCTION에서는 ->나, ->> 를 사용할 수는 없다. (mysql 8 버전 기준)

6. JSON_CONTAINS을 사용할 수도 있다.

JSON_CONTAINS : 0과 1을 반환한다.
SELECT * FROM TEMP_TEST WHERE JSON_CONTAINS(JSON_EXTRACT(contents, '$.*.referrer.specificUrl[*].variableName'), '"appVersion"', '$');

7. 그 외 JSON_FUNCTION

JSON_REPLACE
  • 프로젝트 내 쿼리에서는 사용 중인 쿼리는 없고, json 필드 안의 value를 마이그레이션하는경우 용이하게 사용하였다. 예) customFilters의 0번째 배열 안에 있는 filterLabel의 값을 ‘Marketing Opt-in’ 변경한다.
JSON_REPLACE(LastServicedCustomFilters, '$.customFilters[0].filterLabel', 'Marketing Opt-in')
  • 마이그레이션 사용 예 : triggerEvent의 eventSelection이 ‘OI’ 인 것을 찾아서 bagreementDate를 Array type으로 변경하고 첫 번째 배열에는 현재 값, 두 번째 배열에는 +1일이 되게 수정하라.
{

    "model": [],
    "deregi": "ALL",
    "device": [],

    "agreement": 1,
    "excludeModel": [],
    "optinSpecify": {
        "specify": false
    },
    "targetMethod": "AUTOM",
    "triggerEvent": {
        "sendingDay": "",
        "scheduleDelay": 0,
        "eventSelection": "OI",
        "targetTimeUnit": "days",
        "targetTimeValue": 1,
        "sendingFrequency": "daily",
        "targetPeriodType": 0
    },
    "excludeDevice": [],
    "allMncSelected": false,
    "bagreementDate": "2022-05-15 15:00:00",
    "excludeOsLevel": [],
    "allCountrySelected": true,
    "includeNewOsVersion": 0,
    "includeNewSdkVersion": 0,
    "excludeAllMncSelected": false,
    "excludeLowerSDKversion": false
}

a. 실행 쿼리

UPDATE TEMP_TEST
SET contents = JSON_REPLACE(targetCondition, '$.bagreementDate', JSON_ARRAY(JSON_EXTRACT(targetCondition, '$.bagreementDate'), DATE_ADD(DATE_FORMAT(JSON_UNQUOTE(JSON_EXTRACT(targetCondition, '$.bagreementDate')),'%Y-%m-%d %T'), INTERVAL 1 DAY )))
WHERE JSON_EXTRACT(targetCondition, '$.triggerEvent.eventSelection') in ('OI')

b. 결과 확인

    "triggerEvent": {
        "sendingDay": "",
        "scheduleDelay": 0,
        "eventSelection": "OI",
        "targetTimeUnit": "days",
        "targetTimeValue": 1,
        "sendingFrequency": "daily",
        "targetPeriodType": 0
    },
    "excludeDevice": [],
    "allMncSelected": false,
    "bagreementDate": [
        "2022-05-15 15:00:00",
        "2022-05-16 15:00:00"
    ],
    "excludeOsLevel": [],
    "allCountrySelected": true,
    "includeNewOsVersion": 0,
JSON_CONTAINS_PATH
  • json key가 가변인 경우 해당 키가 있는지 검색해 볼 수 있다.

예) ${customFilter}에 값을 가변적으로 지정한다.

JSON_CONTAINS_PATH(targetCondition, 'all', '$.custom.${customFilter}')=1
JSON_VALID
  • db에 insert될때 기본적으로 유효한 JSON이 들어가야 하겠지만 그렇지 않은 경우 유효한지 검증하는 함수다. SMP에서는 datatype을 text 컬럼에서 json 컬럼으로 변경한 컬럼이 있었다 이 경우 invalid한경우에 오류를 토해낸다. 그래서 JSON_VALID 를 이용해서 row를 찾고 valid한 json으로 변경 후 datatype을 json으로 변경하였다.
  • json 컬럼인 경우 datatype을 text로 하는 것 보다 json type으로 하는 게 insert가 안되기 때문에 파싱하다가 운영 중에 Exception발생하는 것을 미연에 방지 할 수 있다.
  • 사용 예) TEST_TEMP의 contents와 targetCondition 이 json구조가 invalid하면 STAT_CUSTOM에서 삭제하라
DELETE FROM STAT_CUSTOM WHERE MID IN (SELECT mid FROM TEST_TEMP WHERE (JSON_VALID(contents) = 0 OR JSON_VALID(targetCondition) = 0));

8. 프로젝트를 진행하면서 가장 많이 쓰는 것은

JSON_EXTRACT, JSON_SEARCH, JSON_CONTAINS_PATH, JSON_CONTAINS 이다. JSON_EXTRACT 만 잘 사용해도 좋을 것 같다. JSON_EXTRACT는 결과 값을 재사용 하는 경우에 사용하고, JSON_CONTAINS는 원하는 값이 있는지 찾을 경우, JSON_CONTAINS_PATH는 특정 key를 찾을 경우에 사용하면 좋다.

감사합니다~ 🙂

관련

mysqlMySQL JSON functionsJSON_EXTRACTJSON_UNQUOTEJSON_SEARCHJSON_CONTAINSJSON_CONTAINS_PATHJSON_VALIDJSON_REPLACEJSON data processingMySQL JSON data queries

HOT Trend

Recent Posts

  • 딜로이트도, 맥킨지도, 베스핀글로벌도: AI 에이전트로 일 바꾸는 시대

    2025년 07월 04일 클라우드베스핀글로벌clouddata데이터AI인공지능HelpNow AIbespinglobalAI에이전트helpnow업무자동화딜로이트
  • ⚔️데이터센터에서 시작된 전쟁? 요즘 뜨는 AIDC 개념부터 트렌드까지!

    2025년 06월 27일 클라우드clouddata데이터AI데이터센터클라우드 데이터센터bespinglobalAIDCAI 인프라베스핀글로벌
  • 구글부터 엔비디아까지, 빅테크 기업들의 AI 전략 최신본📖

    2025년 06월 20일 cloud베스핀글로벌클라우드data데이터AI구글마이크로소프트엔비디아AI에이전트google I/ONVIDIA GTC 2025Microsoft build 2025
  • AI를 연결한다고? 업계가 주목하는 ‘MCP’ 알아보기🔍

    2025년 06월 13일 베스핀글로벌클라우드cloudAIMCP
  • [WhaTap] RDS Failover/Reboot 관제 2 – RDS Failover

    2025년 05월 30일 RDSRDS FailoverRebootFailoverbespin global

베스핀글로벌은 모든 기업의 AI 혁신을 실현하기 위해, 세상에서 가장 혁신적이고 자동화된 AI 서비스와 솔루션을 만들어갑니다.
상호 : 베스핀글로벌 주식회사 ㅣ 대표자명 : 김써니, 허양호 ㅣ 사업자등록증번호 : 638-87-00223 ㅣ 통신판매번호 : 2019-서울서초-0347 ㅣ 대표전화 : 1668-1280
사업장주소지 : 서울특별시 서초구 강남대로 327, 13,14,15,16층(서초동,대륭서초타워) ㅣ 이메일 : info@bespinglobal.com ㅣ 개인정보 처리방침 ㅣ 개인정보 처리방침 안내

© 2026 BESPIN GLOBAL, All Rights Reserved.

BESPINGLOBAL
패밀리 사이트
China MEA SEA US

BESPIN Tech Blog
  • Home
  • Tech
    • CSP

      AWS

      GCP

      NCP

      Cloud

      Migration

      LZ, Control Tower

      Backup

      Monitoring

      Container

      Infra

      OS

      Middleware

      Data

      RDB

      Big Data Platform

      Application

      CI/CD

      BESPICK 구독하기 ㅣ 1668-1280

  • Trend
  • IT