2024. 4. 4. 10:19

csv나 txt 파일에 데이터 양이 많아서, DB에 직접 업로드해서 볼려고 하면, 

업로드를 해야하는데, DBever나 기타 프로그램들을 통해서 업로드 하려면 너무 오래 걸린다.

 

그래서 오라클의 경우 DB로더를 사용해서 업로드를 하게 되는데....

 

파일 세팅해야되는 부분이 있고, 옵션들이 많이 있어서.... 

 

일단 한번 정리해 놓으려고 한다.

 

DB로더를 사용하기 위해서는 업로드 테이블, 필드값들에 대한 정보가 있는 control 파일(.ctl)을 작성해야 된다.

그리고, 실행하기 위해서 실행명령어를 작성하는데... 작성 내용이 길기 때문에 대부분 배치파일 (.bat) 파일을 생성해서

거기에 명령어를 작성하고 한번에 실행하는게 편하다.

 

예를 들어서 upload.ctl 파일을 생성하고, upload_run.bat 파일을 만들어서 bat파일안에 upload.ctl 파일을 작성해서 로드해주는거다. 

 

 

1. Control 파일에 대한 설명 

options(skip =1) 
LOAD DATA
CHARACTERSET  UTF8
INFILE 'log_001.CSV' 
INFILE 'log_002.CSV' 
BADFILE 'log_bad.bad'
DISCARDFILE 'log_bad.dsc'
APPEND
INTO TABLE "디비명"."테이블명"


FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"' AND '"'
trailing nullcols
(field01,
field02,
field03,
field04,
field05,
field06 char(350),
field07 char(350),
field08)

 1) options(skip =1) 

    - 이 옵션은 첫번째 줄은 생략한다는 명령어임 대부분 첫째줄은 필드명이 작성되어 있어서 생략해서.. 이렇게 작성함.

    - 하지만, 이 옵션은 여기control파일에 작성하는 것보다. bat 파일 실행 명령어에 작성하는 것을 추천한다. 이거는 뒤에서 다시 설명

 

 2) CHARACTERSET  UTF8

     - 한국어가 깨지면 UTF8로 하면 안깨지고 들어간다. 

     - 가끔 DB 설정 언어랑 안되서 업로드 안될때 있는데...그때는 DB 언어를 UTF8로 맞춰주는것을 추천한다.

 

 3) INFILE 'log_001.CSV' 
     - 입력할 데이터가 있는 파일명을 적어 주는 것이다. 

     - 하지만 파일이 많을때 여기에 적는 것보다, bat 파일에 개별로 실행하는 하는 것을 추천한다. 

     - 여기서는 INFILE 명령어를 생략하고 배치 파일 명령어에서 파일을 작성하는 것을 추천함. 

 

   4) BADFILE 'log_bad.bad'

      - 업로드할때 필드 길이 등으로 인해 업로드 되지 않는 데이터를 따로 저장한다. 

 

   5)DISCARDFILE 'log_bad.dsc'

       - 로그 업로드에 대한 정보 파일을 저장한다. 예) 업로드 파일 수, 실패수 등

 

   6) INTO TABLE "디비명"."테이블명"

       - 업로드될 디비유저명 과 테이블명을 작성해 줘야한다. 

 

   7) FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"' AND '"'

       - CSV 파일 업로드 할때 구분자를 지정해 주는거다. 

       - 기본 CSV파일은 콤마(,) 구분이고, 데이터들을 따옴표(")로 묶여 있기 때문에 위 명령어를 쓴다. 

       -> txt 파일의 탭 구분으로 할 경우에는 아래와 같이만 작성해준다. (9가 탭 코드 번호임)

        -> FIELDS TERMINATED BY X'9'

 

    8) trailing nullcols

       - 필드값에 null (값없음) 있어도 그냥 빈값으로 넣고 넘어가라는 이야기임. 
       - 이게 없으면 null값의 경우 에러가 남. 

   

   9) (field01, field02)

       -  이런식으로 괄호안에 DB 필드명을 순서대로 작성해주고, 마지막 콤마(,)는 빼준다. 

 

   10) field06 char(350),

       -  char(350) 또는 char(4000)으로 작성해준다. 

       - DB에 필드 사이즈를 4000으로 잡아도, 디비로더에서 디폴트로 255로 잡혀 있어서, 필드값 사이즈가 넘어가면, 에러가 나기 때문에 한 필드값이 긴거는 위처럼 하나씩 작성해준다. 

 

-> 아래는 txt파일 탭 구분으로 사람들 전화번호랑 주소값 넣는거로 작성한거다.

    위에 설명했지만 아래 없는 것들은 배치파일에서 명령어에서 처리한다. 

LOAD DATA
CHARACTERSET  UTF8
APPEND
INTO TABLE "DBUSER"."LOG_TABLE"
FIELDS TERMINATED BY X'9'
trailing nullcols
(NAME,
MOBILE,
ADDRESS char(350),
ETC)

 

 

2. Control 파일 

이제는 실행파일을 만들어야 한다. 

이전에 작성한 글(https://tyson.tistory.com/234)을 참고해도 되지만 다시한번 정리하면, 

메모장에서 uplaod_run.bat 파일을 생성하고 아래와 같이 작성해준다.

sqlldr db유저/암호@디비아이피:포트/SID CONTROL=콘트롤파일명 data=데이터파일명 LOG=결과로그파일 BAD=실패데이터파일
sqlldr user/password@192.168.0.100:1521/SID CONTROL=upload.ctl data=log_data_01.txt LOG=log_01.log BAD=bad_log_01.bad 
sqlldr user/password@192.168.0.100:1521/SID CONTROL=upload.ctl data=log_data_02.txt LOG=log_02.log BAD=bad_log_02.bad
sqlldr user/password@192.168.0.100:1521/SID CONTROL=upload.ctl data=log_data_03.txt LOG=log_03.log BAD=bad_log_03.bad
sqlldr user/password@192.168.0.100:1521/SID CONTROL=upload.ctl data=log_data_04.txt LOG=log_04.log BAD=bad_log_04.bad skip=1

 

업로드 파일이 여러개일 경우 이전 control.ctl 파일 INFILE을 여러개 적는것보다

콘트롤파일에서는 생략하고, 위처럼 배치 파일에 개별로 작성해 주는것이 좋다.

 

그래야 각 로그가 생성되어 중간에 어디까지 들어갔는지, 어떤게 에러 났는지 확인하기 좋기 때문에 배치파일에 

개별 파일을 적는 것을 추천한다. 

 

그리고, 아까 말한 control 파일의 맨첫줄 제외하는 skip 옵션은 콘트롤 파일에서 제외하고, 

명령어에서 마지막 파일처럼 skip=1 옵션으로 적어 주는 것이 좋다.

 

각 파일들마다 어떤거는 필드값이 있고, 없는게 다르기 때문에 파일에 작성해 주는 것이 낫다.

 

여기는 직접 아이피를 적어 주었는데, tns파일에 세팅이 되어 있으면 tns명으로 작성해주면 된다. 

 

그리고, 위처럼 아이피를 직접적을때는 SID부분도 확인해서 작성해줘야 된다. 

처음에 SID안쓰니, 에러가 나오더라..

 

이것 저것 대량 파일을 전달 받아보니, txt파일에 탭 구분이 제일 안전하다...ㅠㅠ 

데이터 뽑을때 탭의 경우는 미리 스페이스로 치환해서 받으면 중간에 에러없이 대부분 잘 들어간다.

 

 

Posted by Tyson
2021. 12. 2. 21:41

탭구분으로 되어 있는 txt 파일의 데이터를 로더로 넣다가, 

마지막열에 값이 없는 것들이 아래처럼 에러가 나길래...

레코드 201467: 기각됨 - 테이블 "DB"."TABLE", 열 LAST_FIELD에 오류
논리 레코드가 종료하기 전에 열을 찾지 못했습니다 (TRAILING NULLCOLS 사용)

 

분명히 탭 순서는 다 들어갔고, 마지막열에 값이 없는것들에서만 위에처럼 에러가 난다.

 

ctl 파일내용 

LOAD DATA
CHARACTERSET  UTF8
INFILE 'log_202004.txt' 
BADFILE 'log_202004.bad'
DISCARDFILE 'log_202004.dsc'
APPEND
INTO TABLE "DB_USER_NAME"."TABLE_NAME"
FIELDS TERMINATED BY X'9'
(FIELD1_NM,
FIELD2_NM,
FIELD3_NM char(4000),
FIELD4_NM char(4000),
FIELD5_NM char(4000),
FIELD6_NM)

이렇게 입력중이였다.

 

마지막 열이 null이라도 그냥 넘어가게 하려면, 

아래처럼, 필드값 앞에

trailing nullcols 를 써주면 된다.

LOAD DATA
CHARACTERSET  UTF8
INFILE 'log_202004.txt' 
BADFILE 'log_202004.bad'
DISCARDFILE 'log_202004.dsc'
APPEND
INTO TABLE "DB_USER_NAME"."TABLE_NAME"
FIELDS TERMINATED BY X'9'
trailing nullcols
(FIELD1_NM,
FIELD2_NM,
FIELD3_NM char(4000),
FIELD4_NM char(4000),
FIELD5_NM char(4000),
FIELD6_NM)

 

 

참고 블로그 ( 로더 사용시 각 케이스별 옵션 사용법 있음)

: https://blog.naver.com/PostView.naver?blogId=polong77&logNo=140012601270&parentCategoryNo=&categoryNo=21&viewDate=&isShowPopularPosts=true&from=search 

 

Posted by Tyson
2021. 11. 1. 10:53

대용량 로그를 SQL Developer 또는 프로그램에서 넣으니까...

 

아카이브에 백업 로그가 엄청 쌓여서 풀찬다.

 

그래서, 찾아보니, sql로더를 사용해서 넣으라고 하더라...

 

먼저 sqlldr 이 설치 되어 있는지 확인해 보고, 없으면 설치해야한다.

 

cmd 명령 프롬프트에서 sqlldr을 실행해보고, 찾을수 없으라고 뜨면, 설치부터 진행

 

 

구조를 설명하면, ctl 파일(콘트롤파일)에 입력값에대한 정보를 작성해야한다.

 

그리고, sqlldr 를 실행하면 된다.

 

C\user> sqlldr 디비접속정보 CONTROL= ctl파일명 LOG = 로그파일명

 

하지만, 저렇게 하면, 매번 써야되는 불편함이 있어서, 

 

bat 파일을 생성해서 위 실행문을 미리 적어 놓고, bat 파일을 실행했다.

 

 

먼저 ctl 파일부터 설명하면, 

LOAD DATA
CHARACTERSET  UTF8
INFILE 'log_202004.txt' 
BADFILE 'log_202004.bad'
DISCARDFILE 'log_202004.dsc'
APPEND
INTO TABLE "DB_USER_NAME"."TABLE_NAME"
FIELDS TERMINATED BY X'9'
(FIELD1_NM,
FIELD2_NM,
FIELD3_NM char(4000),
FIELD4_NM char(4000),
FIELD5_NM char(4000),
FIELD6_NM)

CHARACTERSET 은 한글이 있으므로, UTF8로 적어준다.

 

INFILE 은 넣을 DATA의 TXT 파일이다.

BADFILE은 입력이 들어가지 않은 라인의 정보 모음이다.

BADFILE 이 생성되면, 들어가지 않은 데이터가 생겼으므로, BAD 파일의 로그만 따로 정리해서 다시 실행하면 된다.

(이게 생각보다 편하다... 전체 지우고 다시 넣는게 아니라...값이 잘못된서 못 들어간 정보만 확인해서 다시 넣을 수 있으므로..)

 

그리고, INTO TABLE 에 처음에 DB 유저명을 적고,  점 뒤에 넣을 테이블 명을 적으면 된다.

밑에 ( 괄호부터는 필드 명을 적어주는데, char(4000)적은거는, 따로 적어주지 않으면, 기본 default로 255자로 잡혀서 그 이상은 오류가 발생한다.

에러 "Field in data file exceeds maximum length" 가 생길때, 처리하기 위해서

char(4000) 최대값을 적어준거다. char 안적은거는 255로 잡힌다.

 

 

자 이제 ctl 파일은 준비가 되었다.

여러개를 입력해야하니, 그때마다 명령어를 쓰기 힘드니, 

에디터를 열고, bat 파일을 만들어 준다.(예, test.bat)

 

sqlldr 디비접속정보 CONTROL= ctl파일명 LOG = 로그파일명

sqlldr db_user/db_password@db_ip CONTROL = log_info.ctl LOG= importlog.log

@뒤에 db_ip에는 tns에 세팅이 되어있으면, tns명을 넣어줘도 된다.

 

 

저장하고, 명령 프롬프트에서 bat를 실행하면 된다.

 

로더를 사용하면, 생각보다 속도도 빠르고, 잘못된 필드값 정리도 되서, 오히려 작업하는데 유용하다.

처음 세팅이 복잡해서 그렇지, 한번하면, 그 이후에는 빠르게 작업할 있다.

 

실행하면, 아래처럼 레코드 수가 뜨고, 작업양을 볼수 있다.

SQL*Loader: Release 11.1.0.6.0 - Production on 수 9월 15 20:23:47 2021

Copyright (c) 1982, 2007, Oracle.  All rights reserved.

커밋 시점에 도달 - 논리 레코드 개수 18
커밋 시점에 도달 - 논리 레코드 개수 36
커밋 시점에 도달 - 논리 레코드 개수 54
커밋 시점에 도달 - 논리 레코드 개수 72
커밋 시점에 도달 - 논리 레코드 개수 90
커밋 시점에 도달 - 논리 레코드 개수 108
커밋 시점에 도달 - 논리 레코드 개수 126
커밋 시점에 도달 - 논리 레코드 개수 144
커밋 시점에 도달 - 논리 레코드 개수 162
커밋 시점에 도달 - 논리 레코드 개수 180

 

Posted by Tyson
2021. 8. 18. 11:00

php 날코딩으로 검색  기능을 만드는데, 

문자열 검색을 해야한다.

예로, 사용자명, 사용자 번호, 두개를 같이 검색해야되고,

인덱스도 없어서.... like 검색을 하려니 너무 느려질거 같다.

 

그  경우, DB에서  like 검색보다는 INSTR 를  사용하는걸 추천한다.

조건절에,  

SELECT * FROM USER 
      WHERE INSTR(UPPER(REPLACE(USER_NM, ' ', '')),  UPPER(REPLACE('검색어',' ', ''))) > 0

INSTR 은 문자열이 포함되었는지 확인하는거고, 

UPPER.  소문자로 입력된것도 다  대분자로 치환한다.

REPLACE 그리고,  혹시 스페이스가 들어가 있을수있으니, 스페이스를 없애는 작업이다.

 

>0 은 값이 1개라도 있으면, 리턴되는거다.

 

위 쿼리문에 AND 붙여서 조건식 추가하면 된다.

 

어자피 검색해서, 포함된 문자열 검색해서 목록을 내려주면 된다.

 

INSTR이  like 보다, 훨씬 빠르고, 간편하다.

Posted by Tyson
2021. 7. 20. 16:35

맥에서 SQLPro Studio 로 오라클 접속하는데...

 

ORA-21561 : OID generation failed  에러가 자꾸 뜨더라.

 

 hosts 파일에 localhost 이름을 넣어줘야 한다.

 

이전에 내 맥북의 hostname를 알아야한다.

 

1. 터미널 열기

2. $> hostname 입력

3. 예로 tyson-Macbook.local 이런식으로 뜰거다.

4. $> sudo vi /etc/hosts 입력 해서 host파일열기

5. 암호입력후 접속

6. 127.0.0.1 localhost 라고 써는곳에서 i 눌러서 수정 

7. 

127.0.0.1 localhost localhost.localdomain tyson-Macbook.local

127.0.0.1 localhost localhost.localdomain  [내호스트네임]

로 입력해준다.

8. esc 누른후 ":wq" 입력해서 저장후 나가기.

9. 그리고, 재접속하면 접속됨.

 

Posted by Tyson
2019. 10. 31. 18:23

오라클에서 로그값 시간 차이를 계산하려고 보니.... 

수식을 만들어야 되나 고민하다가...찾아보니..

 

이렇게 되어있는 로그 차를 구해야하는거였다.

2019-09-30 23:05:00

2019-09-30 23:55:00

 

아래처럼 TO_DATE 를 사용하면 된다.

 

TO_DATE(STIME,'YYYY-MM-DD HH24:MI:SS') - TO_DATE(ETIME,'YYYY-MM-DD HH24:MI:SS'))*24*60*60)

 

위 수식은 기본 소수점 값으로 나오기 때문에, 

24시간 곱하기, 60분, 60초 해주면, 

초 단위로 몇초 차이 나는지 값이 나온다.

 

Posted by Tyson
2018. 4. 27. 18:57

디비에 DATE 값에서 오늘 날짜 검색할때

DATA_TABLE 안에, CR_TIME이 등록일이다.


등록일은 DATE 형식으로, 입력시 SYSDATE 값을 넣는다.


오늘 등록된 갑만 보고 싶을때,



SELECT * FROM DATA_TABLE

WHERE TO_CHAR(CR_TIME,'YYYYMMDD') = TO_CHAR(SYSDATE,'YYYYMMDD')




Posted by Tyson
2018. 4. 24. 11:10

오라클 자동백을 하기 위해서 쉘 스크립트를 만들어서 쉘을 돌리게 백업하는 방법이다.


> vi backup.sh


치고 들어가서, 안에

밑에꺼를 써준다.

su - oracle -c "exp db유저/db패스워드 file=/home/oracle/backup/backup_`date +%Y%m%d`.dmp log=/home/oracle/backup/log/backup_log_`date +%Y%m%d`.log"


orcle 계정에서

 c 커멘드를 쓴다.

 exp 오라클 백업명령어

 유저명/유저패스워드 쓰고, 


file=은 저장 경로 및 파일명 를 적어주면 된다.

뒤에 `date +%Y%m%d`.dmp  이거는 파일명뒤에 날짜를 입력해준다.

예 ) backup_20180424.dmp 이렇게 저장된다.

여기에쓰는 콜론은 `이거다. 이거는 숫자1키옆에 있는 ~ 여기에 있는 콜론이다.

엔터옆의 " ' 이 아니다.

이거때문에 처음에 계속 에러 떴음.


그리고,  쉘 스크립트를 실행해 본다.

> ./backup.sh

또는 

> sh backup.sh 

하는데, 안 먹힐때가 있다.


이건 쉘 스크립트 실행권한을 줘야한다.


> chmod +x /home/oracle/backup/backup.sh

또는

> chmod +rx /home/oracle/backup/backup.sh


이렇게 해주고.

> ./backup.sh

하면 먹힌다. 


근데, 갑자기 


EXP-00056: ORACLE error 21561 encountered

ORA-21561: OID generation failed

에러를 토해낸다.

이거 해결법은 아래 포스트에 있다.


http://tyson.tistory.com/112




근데, 또 아래와 같은 에러가 뜬다.


Connected to: Oracle Database 11g Release 11.2.0.4.0 - 64bit Production

EXP-00028: failed to open /home/oracle/backup/backup_20180424.dmp for write

Export file: expdat.dmp >



이건, 오라클이 폴더권한이 없어서 그런거다.


그래서 위 경로 폴더에 777권한을 준다.


>chmod 777 /home/oracle/backup

>chmod 777 /home/oracle/backup/log


이렇게 준다.


그리고 다시 

> ./backup.sh

실행했을때, 자동으로 실행이 완료되면 스크립트 만들기는 끝난거다.



여기까지 하면 이제 cron에 등록만 해주면 된다.


크론에 등록법은 다음 포스트에서~

http://tyson.tistory.com/114



Posted by Tyson
2018. 4. 24. 10:49

오라클 백업시 (exp) 실행시 에러


Export: Release 11.2.0.4.0 - Production on Tue Apr 24 10:31:03 2018


Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.



EXP-00056: ORACLE error 21561 encountered

ORA-21561: OID generation failed


이란 에러가 계속떠서, 쉘 스크립트가 자동 실행이 안되는거다.


host파일에서 아이피 적고, 호스트 이름을 적어줘야한다.


vi /etc/hosts 


치면, 호스트 파일에 들어간다.


거기에서 내 아이피 호스트 이름을 써주면 된다.


예 :


192.168.0.10 TESTSERVER 


아이피 호스트이름(TESTSERVER)


이렇게 해주면 된다.


Posted by Tyson
2015. 10. 1. 21:54

쿠폰 번호를 디비에서 시퀀스를 써서 번호를 매겨야 하는데, 처음에 안 만들어서, 

디비에서 최고 높은 값을 찾아서, +1를 해주고, 다시 앞에 'U' 붙이고, 0000 붙여서 자릿수를 맞춰 주고 싶을때 쓰는거다.

밑에 예시처럼.

U0000001

U0000039

U0000040



select 'U'||substr('000000000'||to_char(max(to_number(replace(nvl(coupon_cd,'0'),'U',''))) + 1),-9,9) max_coupon

from tk_coupon



처음에

select replace(coupon_cd, 'U', '') from tk_coupon;   //앞에 'U'를 제거해줌.


select to_number(replace(coupon_cd, 'U', '')) from tk_coupon;  //스트링을 넘버로 바꿔줌.


select to_number(replace(nvl(coupon_cd, '0'), 'U', '')) from tk_coupon;  //nvl 혹시 모르니, nvl를 써서, null값을 0으로 바꿔줌.


select max(to_number(replace(nvl(coupon_cd, '0'), 'U', ''))) from tk_coupon;   //그 다음에, 그중에서 max로 최대값을 찾아줌.


select max(to_number(replace(nvl(coupon_cd, '0'), 'U', '')))+1 from tk_coupon;   //거기에 1를 더해줌.


select to_char(max(to_number(replace(nvl(coupon_cd, '0'), 'U', '')))+1) from tk_coupon;  //다시 number에서, char로 바꿔줌.


select '000000000'||to_char(max(to_number(replace(nvl(coupon_cd, '0'), 'U', '')))+1) from tk_coupon;  //앞에 0000000를 자리수 맞게 붙여줌.  0000000004 이렇게 됨. 그래서 앞에 한자리를 지워줘야함.


//혹시 모르니, 11이 됬을때는, 0를 하나 더 지워주어야 함. 그래서 substr( [값], [시작자리수], [자리수갯수] )를 써서, 앞에를 잘라줌. 시작 자릿수에 (-)를 붙였을때는 뒤에서 부터 시작임.

select substr('000000000'||to_char(max(to_number(replace(nvl(coupon_cd, '0'), 'U', '')))+1), -9.9) from tk_coupon;

위에서부터, 9자릿수까지함.

 

//그 다음에 앞에 U를 붙여주면됨.

select 'U'||substr('000000000'||to_char(max(to_number(replace(nvl(coupon_cd, '0'), 'U', '')))+1), -9.9) from tk_coupon;


 값 :  U000000005


//칼럼 이름이 너무 길므로, 뒤에 max를 붙여서 이름을 바꿔준다.

select 'U'||substr('000000000'||to_char(max(to_number(replace(nvl(coupon_cd, '0'), 'U', '')))+1), -9.9) max from tk_coupon;



아니면, 쉽게 to_char 만 쓰는 법도 있다.


select 'U'||trim(to_char(to_number('1234556') + 1,'000000000')) max_coupon

from dual;


to_char로 자릿수 잡아주는거다.하지만, trim를 써서, 빈칸을 없애줘야한다.



Posted by Tyson