반응형

Intorduction


http://www.juso.go.kr


- 도로명 주소는 2014년부터 생활(법정)주소로 전면 사용됩니다.

- 도로명주소를 사용하지 않으면 은행, 카드, 보험 등 거래처의 우편물 수신에 불편함이 있을 수 있습니다.


이렇게 나와있다... Y2K[각주:1] 처럼 버그도 아니고, 그냥 체계가 바뀌는 거지만... 미리 준비하자. -_-/




데이터 입력


http://www.juso.go.kr


정보제공 게시판 쪽에 가보면 현재 11월 기준의 도로명 주소 데이터가 올라와 있다. 매월 말에 데이터가 갱신 되는듯 하다... ㅅㅂ



4개의 게시글 첨부파일을 다 다운로드 받은 후 txt 파일이 나올때까지 전부 압축을 해제하자.


 

도로명주소정보제공내용변경계획.hwp


파일을 보면 알겠지면 4개의 테이블 구조로 되어있다. 이것을 대충 ERD로 짜보면 아래와 같다. 네이밍 ㅅㅂ -_-/


road.txp


01


이제 텍스트 파일에서 테이블로 데이터를 넣어야 한다.


근데 이게 많은 양의 데이터라서 툴을 이용해서 넣기 번거로으므로 Java 로 만들어서 넣었다 -_-;; (템플릿 메소드 패턴 이용!)


 레이아웃

 건수

 설명

 도로명코드 (tbl_road)

356.792 

 시도 시군구 읍면동 도로명

 주소 (tbl_road_addr)

5,976,050 

 도로명코드 x 건물본번-건물부번

 지번 (tbl_addr_jibun)

7,943,977 

 주소에 해당하는 지번(옛날) 주소 (주소에 해당하는 지번 주소는 n 건)

 부가정보 (tbl_addr_info)

5,976,050 

 주소에 해당하는 부가정보 (우편번호가 여기에 있다)


zipcode.reader.zip


↑ 메이븐 프로젝트이다.




데이터 조회


안전행정부에서 도로명 주소를 검색해 가면서 분석한 결과 아래와 같은 공식(?)이 나왔다. 


 구분

 공식

 도로명 주소

 #도로명코드.시도명# [#도로명코드.시군구명#] #도로명코드.도로명# [#주소.지하여부#=="1"?"지하"]

 #주소.건물번호본번#[-#주소.건물번호부번#!="0"?#주소.건물번호부번#]

 [(#도로명코드.읍면동명#[, #부가정보.공동주택여부#=="1"?#부가정보.시군구건물명#])]

 도로명 주소 영문

 [#주소.지하여부#=="1"?"Jiha, "] #주소.건물번호본번#[-#주소.건물번호부번]

 [, #도로명코드.읍면동명영문#] [, #도로명코드.시군구명영문#], #도로명코드.시도명영문#

 지번 주소 (~2013 주소)

 #지번.시도명# #지번.시군구명# [#지번.법정읍면동명#] [#지번.법정동명#] [#지번.법정리명#]

 [#지번.산여부#=="1"?"산"] [#지번.지번본번#[-#지번.지번부번#]] [#부가정보.시군구건물명#]


음.. 어렵다.. -_-... 위 3개의 경우를 쿼리(오라클)로 뽑아보면 아래와 같다. 쿼리로 보는게 더 편할지도? ㅋㅋ


select /* 우편번호 */ t3.zipcode as zipcode /* 도로명 주소 */ , t1.sido_name || case when t1.sigun_name is not null then ' ' || t1.sigun_name end || ' ' || t1.road_name || decode(t2.base_yn, '1', ' ' || '지하') || ' ' || t2.bldg_no1 || case when t2.bldg_no2 != 0 then '-' || t2.bldg_no2 end || ' (' || t1.eup_name || case when t3.apt_yn = '1' and t3.sigun_bldg_name is not null then ', ' || t3.sigun_bldg_name end || ')' as address /* 도로명 주소 영문 */ , decode(t2.base_yn, '1', 'Jiha' || ' ') || t2.bldg_no1 || case when t2.bldg_no2 != 0 then '-' || t2.bldg_no2 end || ', ' || t1.road_name_eng || case when t1.sigun_name_eng is not null then ', ' || t1.sigun_name_eng end || ', ' || t1.sido_name_eng as address_eng /* 지번 주소 (~2013 주소) */ , t4.sido_name || case when nvl(t4.gugun_name, t1.sigun_name) is not null then ' ' || nvl(t4.gugun_name, t1.sigun_name) end || case when nvl(t4.eup_name, t1.eup_name) is not null then ' ' || nvl(t4.eup_name, t1.eup_name) end || case when t4.ri_name is not null then ' ' || t4.ri_name end || decode(t4.san_yn, '1', '산') || ' ' || t4.ji_no1 || case when t4.ji_no2 != 0 then '-' || t4.ji_no2 end || case when t3.sigun_bldg_name is not null then ' ' || t3.sigun_bldg_name end as address_jibun

/* 관리번호(PK) */ , t2.num from tbl_road t1 join tbl_road_addr t2 on t1.road_code = t2.road_code and t1.eup_seq = t2.eup_seq join tbl_road_info t3 on t2.num = t3.num join tbl_road_jibun t4 on t2.num = t4.num where t1.using_yn = '0' and t4.dele_yn = '1' and to_char(sysdate, 'YYYYMMDD') between nvl(t1.noti_date, '11110101') and nvl(t1.cancel_date, '99991231') and to_char(sysdate, 'YYYYMMDD') >= nvl(t2.noti_date, '11110101') ;


뭐 보면 대충 이렇게 나온다.





데이터 가공


데이터의 양이 너무 많다. 4개의 테이블만 덤프를 떠도 1.8GB 정도 한다.


내가 이 도로명주소 데이터를 뽑는 이유는 우편번호를 사용하기 위함이기 때문에 필요없는거 다 날리고 다른 테이블에 다시 넣어보자.


아래 ERD 는 도로명 주소를 표현할 수 있는 최소한의 데이터만 사용했을 때의 테이블이다.


zipcode_road.txp



아래는 insert select 문이다.


insert into zipcode_road (
	zipcode
    , road
    , sido
    , sigun
    , eup
    , under_yn
    , bldg_no1
    , bldg_no2
    , bldg
    , num
    , apply_date
)
select
	t3.zipcode
    , t1.road_name
	, t1.sido_name
    , t1.sigun_name
    , t1.eup_name
	, decode(t2.base_yn, '1', 'Y', 'N') as under_yn
    , t2.bldg_no1
    , decode(t2.bldg_no2, 0, null, t2.bldg_no2) as bldg_no2
    , case when t3.apt_yn = '1' and t3.sigun_bldg_name is not null then t3.sigun_bldg_name end as bldg
    , t2.num
    , to_char(sysdate, 'YYYYMMDD') as apply_date
from
	tbl_road t1
join
	tbl_road_addr t2
on
	t1.road_code = t2.road_code
    and t1.eup_seq = t2.eup_seq
join
	tbl_road_info t3
on
	t2.num = t3.num
where
	t1.using_yn = '0'
	and to_char(sysdate, 'YYYYMMDD') between nvl(t1.noti_date, '11110101') and nvl(t1.cancel_date, '99991231')
	and to_char(sysdate, 'YYYYMMDD') >= nvl(t2.noti_date, '11110101')
;


이렇게 넣으니 데이터는 5,975,824건에 650MB 정도 된다. 이래도 많다... 예전 우편번호는 5만건 정도밖에 안되는데 ㅜㅜ




Web Application


이 데이터를 기반으로 조회하는걸 한번 만들어 봤다.


http://antop.nerv.kr/zipcode


zipcode.war


zipcode.zip


↑ 메이븐 프로젝트


  1. 컴퓨터 프로그램 내에의 연도 표기 중에서 두 자리 숫자인 세기(century)를 생략한 연도 표현으로 인해 2000년에 컴퓨터 운영 체제 및 각종 업무용 응용 프로그램 등에서 2000년을 1900년과 동일하게 「00」년으로 인식함으로써 발생될 수 있는 각종 문제를 말한다. 또한 밀레니엄 버그를 Y2K 문제라고도 하는데, Y는 연도(year)의 첫 글자를 딴 것이고, K는 1000(kilo)에서 딴 것으로 2000년을 의미한다. [본문으로]
반응형

'Java+ > Example' 카테고리의 다른 글

LOGBack Configurator with JMX  (0) 2014.07.20
현지어로 언어명 보여주기  (0) 2014.02.09
JSTL Custom Tag using Spring Beans  (0) 2013.12.01
Spring Message Source from Database  (1) 2013.03.03
Infinite Routing DataSource  (1) 2013.01.13
Mybatis Type Handler  (1) 2012.09.30
Using AUTO_INCREMENT keys  (0) 2011.03.01
//