본문 바로가기
AyoProject/AT 매매 실험실

[MySQL] INSERT WHERE NOT EXISTS

by 청양호박이 2021. 1. 28.

안녕하세요. 오늘은 기존에 구현했던 AT 시스템에서 한가지 변경이 필요한 부분에 대해서 실험실로 간략하게 진행을 해보고자 글을 적습니다. 이전에 아래에 해당하는 글을 작성하면서 한가지 꺼림직 했던 부분이 있습니다. 

 

과연 수천개에 달하는 기업정보를 전자공시시스템에서 제공하는 OPEN DART의 API로 받아올때, 혹시나 내 서버가 다운되는 상황이 발생하면 어떻게 하지?? 다시 처음부터 받아?? 그렇게 되면 기존에 DB에 저장되는 데이터는 중복되서 들어가는 건데... 다시 전체 삭제를 하고 처음부터??

 

이런저런 고민이 있었습니다. 개발자의 입장에서 데이터의 정합성과 무결성을 만족해야 하고 서비스를 제공하는데 있어서 지연이 발생하면 안되고... 하지만 기업의 재무제표는 분기에 한번씩 업데이트 되고, 나는 야간에 배치를 돌리는 방식으로 구상하고 있으니, 서버의 문제가 발생할 경우 다시 처음부터 그 배치를 돌려서 데이터를 받아오면 되는 일 이긴합니다. 

 

그렇다면, 해당 기간에 데이터를 조건으로 삭제하고 다시 돌리면 되기도 하겠지만... 단순하게 해당 배치만 다시 돌리면 된다는 생각으로 INSERT를 수행할때, 중복된 값이 있는지 확인하고 INSERT하는 방법을 적용해 보도록 하겠습니다. 이름하여, INSERT 중복 확인 후 수행하기!!!

 

자 그렇다면 기존에 관련글에 

2020/12/29 - [AyoProject/Ayotera-Trade] - [AT] 25. 우량주 종목 자동 예측 및 선정 (3-1)

 

[AT] 25. 우량주 종목 자동 예측 및 선정 (3-1)

지난 시간에는, 모든 종목에 대한 고유번호를 저장하고, 각 종목별로 재무제표 정보를 저장하는 로직을 구현해 보았습니다. 재무제표에는 상당히 많은 정보들이 있으며, 이 정보들을 모두 활용

ayoteralab.tistory.com

전자공시시스템으로부터 REST API를 호출하고 받아온 값을 DB에 저장하는 DML은 아래와 같습니다.

 

[sql_dml]

sql_dml = '''
    INSERT INTO fin_stat_info(stocks_id, bsns_year, bsns_quarter, revenue, revenue_add, operating_income, operating_income_add, operating_cashflow, investing_cashflow, financing_cashflow)
    VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
'''

해당 Query는 단순히 원하는 값을 해당 Table에 Insert하는 구문입니다. 게다가, 해당 Table에 Unique Key는 특별하게 존재하지 않기때문에 동일한 값을 넣고 수행할 경우에는 계속 중복되는 값이 저장되게 됩니다.

 

그렇다면 어떤 방식으로 구현을 해야 할까요??

 

 

1. WHERE NOT EXISTS


물론 INSERT에만 적용되는 구문은 아닙니다. SELECT에도 적용되고 그렇습니다. 해당 구문은 WHERE NOT EXISTS이후 구문에서 결과값이 존재하지 않을 경우, 앞의 구문을 구행한다... 입니다. 전체구문을 확인해 보면....

========================Previous========================
INSERT INTO fin_stat_info
    (stocks_id, bsns_year, bsns_quarter, revenue, revenue_add, operating_income, operating_income_add, operating_cashflow, investing_cashflow, financing_cashflow)
    SELECT 진짜value, 진짜value, 진짜value, 진짜value, 진짜value, 진짜value, 진짜value, 진짜value, 진짜value, 진짜value 
    FROM DUAL
========================Previous========================
    WHERE NOT EXISTS 
==========================Next==========================
        (SELECT * 
         FROM fin_stat_info 
         WHERE stocks_id = 진짜value AND bsns_year = 진짜value AND bsns_quarter = 진짜value)
==========================Next==========================

WHERE NOT EXISTS를 기준으로 이전에는 INSERT에 대한 내용을 작성합니다. 하지만 value 대신 위와같이 작성을 해 줍니다. 그리고 이후에는 중복된 값이 없는지 확인하는 로직을 작성합니다. 

 

간단하게 조건을 넣고 SELECT를 했을때 결과가 없으면 되겠죠?? 이렇게 되면 로직이 정확하게 동작합니다. 그렇다면 한번 실험을 해볼까요??

 

현재 DB에 해당 쿼리로 INSERT를 해보겠습니다. 첫번째 시도에는 새로운 데이터가 생겨야 하고, 두번째 시도에는 기존데이터만 유지되고 신규로 추가되는 중복데이터가 없어야 합니다.

 

[수행전]

SELECT COUNT(*) FROM fin_stat_info WHERE bsns_year = '2016' AND bsns_quarter = '3';

[1번 수행후]

INSERT INTO fin_stat_info
(stocks_id, bsns_year, bsns_quarter, revenue, revenue_add, operating_income, operating_income_add, operating_cashflow, investing_cashflow, financing_cashflow)
SELECT '053980', '2016', '3', '0', '0', '0', '0', '0', '0', '0' FROM DUAL
WHERE NOT EXISTS (
SELECT * FROM fin_stat_info WHERE stocks_id = '053980' AND bsns_year = '2016' AND bsns_quarter = '3');
	
	
	
SELECT COUNT(*) FROM fin_stat_info WHERE bsns_year = '2016' AND bsns_quarter = '3';

[2번 수행후]

INSERT INTO fin_stat_info
(stocks_id, bsns_year, bsns_quarter, revenue, revenue_add, operating_income, operating_income_add, operating_cashflow, investing_cashflow, financing_cashflow)
SELECT '053980', '2016', '3', '0', '0', '0', '0', '0', '0', '0' FROM DUAL
WHERE NOT EXISTS (
SELECT * FROM fin_stat_info WHERE stocks_id = '053980' AND bsns_year = '2016' AND bsns_quarter = '3');
	
	
	
SELECT COUNT(*) FROM fin_stat_info WHERE bsns_year = '2016' AND bsns_quarter = '3';

보시다시피 중복데이터가 발생하지 않는 것으로 확인되었습니다. 그렇다면 우리의 기존 소스도 좀 고쳐야 하겠죠?? 고쳐야 하는 부분을 좀 정리해 보겠습니다.

 

 

2. AT 소스 수정


[sql_dml 변경]

 

# sql_dml = '''
#     INSERT INTO fin_stat_info(stocks_id, bsns_year, bsns_quarter, revenue, revenue_add, operating_income, operating_income_add, operating_cashflow, investing_cashflow, financing_cashflow)
#     VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
# '''

# 중복데이터 체크하여 저장하는 로직으로 변경
sql_dml = '''
    INSERT INTO fin_stat_info(stocks_id, bsns_year, bsns_quarter, revenue, revenue_add, operating_income, operating_income_add, operating_cashflow, investing_cashflow, financing_cashflow)
    SELECT %s, %s, %s, %s, %s, %s, %s, %s, %s, %s FROM DUAL
    WHERE NOT EXISTS (SELECT * FROM fin_stat_info WHERE stocks_id = %s AND bsns_year = %s AND bsns_quarter = %s)
'''

[sql_data 변경]

sql_data = (i[0], this_year, str(quarter_info+1), revenue, revenue_add, 
			operating_income, operating_income_add, operating_cashflow, 
            investing_cashflow, financing_cashflow, i[0], this_year, str(quarter_info+1))

sql_data에서 추가되는 부분은 뒤에 추가 데이터 3가지 입니다. 종목명, 년도, 분기구분... 그럼 간략한 수정은 이정도로 마치겠습니다. 오늘은 INSERT WHERE NOT EXISTS에 대해서 알아보고 INSERT 시 중복체크하여 수행하는 방법에 대해서 알아보았습니다.

 

- Ayotera Lab -

댓글