프로시저 작성을 완료 했으니 이제 스케쥴러에 등록을 해 보겠습니다.(자세하게 파악은 못했지만 스케줄과 잡은 구분되는 단어인것 같네요. 스케줄에 잡이 포함되는것 같습니다. 개별적인 job들을 따로 등록할수 있고 같은 시간에 동작할 job들은 스케줄을 만들어서 공통으로 동작할 시간으로 사용하는 거지요. 하지만 제 토드엔 스케줄이 안보이므로 일단 패스. 아마 sysadmin 이 아니거나 오라클10이 아니라서 그런듯.. 합니다.)
1. 작업이 시작될 날짜와 시간을 결정합니다.(first execution, At this time)
2. 매번 작동할 시간간격을 선택합니다. (subsequent executions)
3. What to excute 에 이전에 작성해둔 프로시저명을 입력합니다.
4. ShowSQL 버튼을 누르면 자동 작성될 SQL 구문을 미리 확인 할 수 있습니다.
5. OK 버튼을 누르고 완성된 잡을 선택하여 스크립트를 살펴보면 다음과 같습니다.
TEST_DATA 테이블의 값을 조금 수정해 두고 Job 을 1분뒤 첫 작동을 하도록 설정하고 등록하였습니다. 1분후 TEST_STATS 테이블에는 기대하던 대로 원하던 결과값이 정확히 변경 적용된것을 확인할 수 있었습니다. 또한 30분마다 작동하도록 설정하였으므로 소스테이블의 데이터를 다시한번 수정해 주고 30분 후에 다시한번 확인해 본 결과 원하던 값이 정확히 적용되었음을 확인할 수 있었습니다. 프로시저가 어려웠지 Job 등록은 어렵지 않네요. ^^
interval 은 다음작업할 시간까지의 간격을 나타내는 수식이 들어가는 부분이다.
'sysdate + 1/24' 1시간에 1번 'sysdate + 1' 1일에 1번 'sysdate + 7' 일주일에 한번
단순작업 주기가 아닌 특정 일시를 지정해 주고 싶다면 다음과 같이 작성다.
'trunc(sysdate) + 6 + 1/24' 매일 06시에 작업 실행 'trunc(sysdate, ''D'') + 7' 매주 일요일 00시에 작업 실행
위 잡들의 시간은 user_jobs 테이블에서 확인할수 있다. next_date 컬럼에서 다음에 작동할 시간을 알 수 있으며, interval 컬럼 부분을 복사해서 다음 쿼리를 사용해도 같은 결과를 얻을 수 있다.
SELECT trunc(sysdate) + 6 + 1/24 FROM DUAL;
하지만 'sysdate + 1' 부분을 집어넣고서 어랏 값이 달라~! 어떡~하지~ 같은 소리는 하지 말자. '지금 시간'으로 부터 계산되는거니까 당연히 다르다.
갑자기 통계쪽 데이터가 맞지 않다는 요청이 있어서 살펴 보았습니다. 일단은 검색을 통해 해당 테이블을 사용하는 곳이 있는지를 살펴 보았습니다. 통계를 보여주는 메인 페이지에서 SELECT 하는것 외에는 사용하는 곳이 없네요. 헐.. 대체 UPDATE 혹은 INSERT 를 해주는 곳이 없다면 이 테이블의 데이터는 대체 어디서 만들어 주는 것일까요.. 그래서 오라클에 혹시 예약작업이나 자동화 작업이 되는게 있는지 검색을 해보았습니다. 역시나.. jobs 라는 것이 있네요. 첨알았어요..;
바로 toad 의 schema browser 탭들을 뒤적여 보니 Jobs 가 있었고, 해당하는 테이블의 이름을 딴 스케쥴이 정의되어 있습니다. script를 살펴 보니 procedure 를 호출하도록 되어 있습니다. 이번엔 Proc 탭을 가서 찾아보니 빙고. 이곳에 작업이 정의 되어 있네요. 유레카!
하지만 전 DBA가 아니니 전문적으로 알필요까지는 없겠지만.. 그래도 간단하게 알고 넘어가봐야 겠습니다. 혹시라도 수동으로 동작시킨다던가, 스케쥴 시간을 조정하는 정도는 해야 할지도 모르니까요. 예제를 한두개 만들어 보는정도로 만족하려 합니다.
준비를 위해 테스트 테이블을 만들겠습니다. 년, 월 구분해서 갯수 뽑아내는 정도의 간단한 작업을 하려 합니다.
PL/SQL 은 Oracle’s Procedural Language extension to SQL 의 약자 이다.
SQL문장에서 변수정의, 조건처리(IF), 반복처리(LOOP, WHILE, FOR)등을 지원하며,오라클 자체에 내장되어 있는 Procedure Language 이다.
DECLARE문을 이용하여 정의되며, 선언문의 사용은 선택 사항 이다.
PL/SQL 문은 블록 구조로 되어 있고 PL/SQL자신이 컴파일 엔진을 가지고 있다.
PL/SQL의 장점
PL/SQL 문은 BLOCK 구조로 다수의 SQL 문을 한번에 ORACLE DB로 보내서 처리하므로 수행속도를 향상 시킬수 있다.
PL/SQL 의 모든 요소는 하나 또는 두개이상의 블록으로 구성하여 모듈화가 가능하다.
보다 강력한 프로그램을 작성하기 위해서 큰 블록안에 소블럭을 위치시킬 수 있다.
VARIABLE, CONSTANT, CURSOR, EXCEPTION을 정의하고, SQL문장과 Procedural 문장에서 사용 한다.
단순, 복잡한 데이터 형태의 변수를 선언 한다.
테이블의 데이터 구조와 컬럼명에 준하여 동적으로 변수를 선언 할 수 있다.
EXCEPTION 처리 루틴을 이용하여 Oracle Server Error를 처리 한다.
사용자 정의 에러를 선언하고 EXCEPTION 처리 루틴으로 처리 가능 하다.
끝이 없네요.. 전문가가 될것도 아니고 여기까지만 보겠습니다.
우선 procedure 를 작성해 보겠습니다.
사용하는 Toad 버전은 8.5.3.2, 오라클은9 입니다.
프로시저 에디터가 열리고 기본 문장들이 뭔가 많이 들어가 있는데요. 필요한 부분만 남기고 지우고 사용하면 되겠습니다.
다음은 최초 작성한 코드입니다.
CREATE OR REPLACE PROCEDURE pc_test_stats IS tmpVar NUMBER;
BEGIN tmpVar := 0; SELECT COUNT(*) INTO tmpVar FROM TEST_DATA WHERE t_year = '2012' AND t_month = '1'; END pc_test_stats; /
파란색의 부분들은 항상지켜져야 하는 문법입니다. 생성구문으로 시작하고 IS 와 BEGIN 사이에서 변수를 선언합니다. 프로시저를 끝낼때는 항상 '/' 를 넣어줘야합니다. Toad 의 프로시저에디터에서 작성을 마치면 F9 혹은 왼쪽 상단의화살표 버튼을 클릭하시면 컴파일이 실행됩니다. 문법의 오류가 있다면 여기서 에러를 출력하여 보여줍니다.
문제 없이 컴파일이 되었으면 다음으로 넘어가 보겠습니다. 이번엔 테스트용 통계 테이블에 값을 넣는 부분을 추가해 보겠습니다.
CREATE OR REPLACE PROCEDURE pc_test_stats IS
/* 변수가 선언되는 부분입니다. 타입을 지정해 주어야 합니다. IS 와 BEGIN 사이에 위치해야 합니다. */
tmpVar NUMBER;
BEGIN tmpVar := 0; SELECT COUNT(*) INTO tmpVar/* select 를 통해 얻은 결과값이 tmpVar 변수에 들어갑니다. */ FROM TEST_DATA WHERE t_year = '2012' AND t_month = '1'; INSERT INTO test_stats VALUES ('2012', '1', tmpVar); COMMIT; END pc_test_stats; /
이번에도 컴파일을 실행해 봅니다. 에러가 없이 통과 했다면 이제 실행을 시켜 봅시다. 토드의 Procs 탭으로 가보면 새로 작성한 프로시저가 목록에 추가되어 있는것을 볼수 있습니다. 선택하고 오른쪽 마우스를 클릭하면 메뉴가 나오는데 execute procedure 를 선택하여 실행합니다.
결과를 확인해 볼까요.
SELECT * FROM TEST_STATS;
정상적으로 작동하는걸 확인했습니다. 그럼 계속해서 이번엔 연별, 월별로 구분하는 작업을 추가해 보기로 하겠습니다.
우선은 루프문이 필요 할것 같습니다. 아마도 소스테이블의 연도와 달을 그룹으로 만든 값을 사용하면 될겠네요. 그럼 루프문은 어떻게 사용하는지 한번 적용해 볼까요.
그전에 DBMS Output 이라는 창을 열어두도록 하겠습니다. 콘솔같은거라고 생각합니다.(전문가가 아니라 저두 모릅니다--;)
View 메뉴에서 DBMS Output 을 선택해 줍시다.
아래와 같은 창이 열립니다.
반복문 (FOR, WHILE, LOOP)
다음은 루프를 적용하여 수정한 프로시져입니다.
CREATE OR REPLACE PROCEDURE pc_test_stats IS tmpVar NUMBER; v_year CHAR(4 byte); v_month CHAR(2 byte); BEGIN
FOR year_group IN (SELECT t_year, t_month FROM TEST_DATA GROUP BY t_year, t_month) LOOP tmpVar := 0; v_year := year_group.t_year; v_month := year_group.t_month; SELECT COUNT(*) INTO tmpVar FROM TEST_DATA WHERE t_year = v_year AND t_month = v_month; DELETE TEST_STATS WHERE t_year = v_year AND t_month = v_month; INSERT INTO test_stats VALUES (v_year, v_month, tmpVar); DBMS_OUTPUT.PUT_LINE(v_year || ':' || v_month || tmpVar); END LOOP; COMMIT; END pc_test_stats; /
연도와 월을 변수로 받기 위해 두개의 변수를 추가 했습니다. 컬럼명이 t_ 인데 변수를 v_ 로 했더니 눈에 잘 띄지도 않고 구분도 잘 안되서 오타때문에 컴파일 하다 오류가 몇번이나 났네요.. 구분이 잘 되게 사용하도록 합시다. ㅠㅠ
DBMS_OUPPUT.PUT_LINE 으로 표시한 부분이 DBMS Output 창에 출력됩니다. 출력이 되지 않는다면 BEGIN 다음 구문에 DBMS_OUTPUT.ENABLE; 를 입력해 보세요.
소스만 보게되면 그룹을 구성한 데이터를 선택하고 그걸 기반으로 루프를 돕니다. 한개의 row 씩 돌면서 각 변수에 값을 담고 해당하는 작업을 합니다. 기존의 데이터가 있을지 몰라서 DELETE 를 사용해서 먼저 삭제를 수행하도록 했습니다. 역시 컴파일후 프로시저를 실행시킨 후 TEST_STATS 의 데이터를 확인하니 원하는 결과값이 정상적으로 들어가 있음을 확인 할 수 있었습니다.
위의 FOR문외에도 WHILE 문처럼 사용 가능합니다. 무한루프에 빠질 위험이 큰 문장은 별로 사용하질 않는 주의라...
LOOP <- 세미콜론이 들어가지 않습니다.
EXIT; /* 바로 빠져나갑니다. */
EXIT WHEN index > 30; /* 조건문에 만족하는 경우 순환문을 빠져나갑니다. */
END LOOP;
혹은 WHILE index < 30 LOOP 의 형태로도 사용 가능합니다. while 문의 조건이 true 인동안 동작합니다. 이하 구문은 바로위의 예제와 같습니다.
조건문(IF)
간단하게 알아보려 했는데 글이 계속 길어 집니다. 다음은 IF 문입니다. 사용법만 적고 예제는 만들지 않습니다.
IF 조건문 THEN
ELSEIF 조건문 THEN
ELSE
END IF; <- 여기에만 세미콜론.
암시적커서(Implicit Cursor)
PL/SQL 내에서 SQL문이 실행되면 자동으로 커서가 생성되며, 그 속성을 사용할 수 있습니다.
BEGIN
/* SQL 이 시작되기전 커서가 자동으로 OPEN 됩니다. */
SELECT * FROM TEST_DATA;
/* SQL 이 종료 되면 커서가 자동으로 CLOSE 됩니다. */
/* 새로운 SQL 이 시작되기전 위 SQL에 대한 암시적 커서의 속성을 사용할 수 있습니다.
SQL%FOUND : 위 SQL 의 결과가 한개 이상 있는경우 true
SQL%NOTFOUND : 결과가 없는 경우 ture
SQL%ROWCOUNT : 결과 행의 수
END;
암시적 커서와 반대로 명시적커서(Explicit Cursor) 가 있는데요. 너무 깊이 가는거 같아서..-_-; 보지 않았습니다.
웹페이지에 음악을 집어넣는 가장 단순한 방법은 a href 링크를 이용하는 것입니다만 세련되지 못한 방법입니다.
그렇다면 다른방법은 무었이 있을까요? 예전에 사용하던 방식으로 Netscape용 <embed> 와 InternetExplorer(이하 IE) 용 <bgsound> 를 사용하는 방법이 있습니다. 하지만 이제는 시대의 유물이 되었습니다. 현재는 <object> 를 사용합니다. 다음은 <object> 태그를 사용하여 mp3 파일을 삽입하는 기본 코드입니다.
"type"은 파일의 특성(mp3, mov, ra 등..)을 확인하는 mime type 입니다. "data" 는 url 처럼 출력을 원하는 파일을 가르킵니다. test.mp3 를 출력을 원하는 파일의 이름이나 주소로 변경하면 됩니다. "width"와 "height"로 컨트롤러의 사이즈를 결정합니다. "autoplay"는 말 그대로의 뜻입니다. 그리고 모든 브라우저에서 인식되는것은 아니지만 추가적인 속성들을 사용할 수 있습니다.
지금까진 매우 쉽지만, 이제 조금씩 복잡해 집니다. 위의 코드는 W3C규약에 따른 필요한 모든것과 여러 브라우저들을 지원하기 위한 정보들을 모두 가지고 있습니다. 하지만 엿같은 IE가 항상 말썽이죠. IE6, 7 이 원하는 코드를 조금 추가해줘야 합니다.
"param" 태그는 <object> 안의 내용과 같은 내용을 포함하고 있습니다. 단지 표현을 다르게 하는것 뿐입니다. object에 속성이 추가되면 param 또한 추가 할 수 있습니다.
이제 다 끝난걸까요. 아닙니다. 이 Fucking IE 의 옛 버전에서 윈도우미디어용이 아닌 파일을 윈도우미디어로 사용할때의 문제를 해결하기 위한 방법을 추가해 줘야 합니다. 속성에 "class id" 를 추가하고 <object> 안에 또하나의 <object> 를 넣는 방식입니다. 하나는 IE를 위해 classid를 사용하고, 다른 하나는 기타브라우저들을 위해 mime type을 사용합니다. 표준을 준수하는 FireFox와 같은 착한 브라우저들은 classid 가 있는 object를 무시하고 mimetype 이 있는 object로 넘어갑니다. 하지만 IE는 classid 가 있는 object를 처리하고 나서 mimetype이 있는 object를 만나면 혼란을 일으키며 병신같은 화면출력을 만들거나 에러를 토해냅니다. 그래서 우리는 여기에 좀 독특한 주석을 달아 처리합니다. 일명 IE핵이라고 부르는 주석입니다. (IE는 정말 병신같은 브라우저입니다.) 그렇게 해서 만들어진 소스는 다음과 같습니다.
오디오와 마찬가지로 가장좋은 방법은 <object>를 사용하는 것입니다. 또한 오디오에서 사용한 방법과 꽤나 비슷한 방식으로 사용합니다. 오디오에서 사용한 예제에서 type 과 파일정의만 변경해 주면 됩니다. 단지 오디오에서는 컨트롤러의 높이만 정의해 주었지만 비디오의 높이를 정의할때는 비디오파일의 높이에 컨트롤러의 높이를 더해서 정의해 주어야 합니다. 이는 일반적으로 16-20픽셀 사이입니다. 따라서 비디오의 크기가 320 x 240 이라면 320 x 256 으로 지정해 주면 됩니다. 이 모두를 적용한 소스는 다음과 같습니다.
그리고 controller 파라미터는 여기선 쓸모가 없습니다. 컨트롤러를 보기위해선 컨트롤러부분을 별도로 삽입해 주어야 합니다. 기본적으로 지금까지 작성한 object 블럭 전체를 그대로 복사해서 붙이고 console 파라미터값을 one 에서 all 로 변경해 주기만 하면 됩니다. 마지막으로 다른것들은 그대로 두고 플로그인 참조를 삭제합니다. 변경된 소스는 다음과 같습니다.
물론 영어로 작성하긴 합니다만 -_-ㅋ 그 뜻이 아니고 한글로 작성된 문장을 외국사람이 이해할 수 있도록 해주는 번역가와 클라이언트의 언어를 컴퓨터가 알아듣는 언어로 번역해 주는 사람이란 점에서 비슷하다고 생각합니다.
좀 더 자세히 풀어 보겠습니다.
한글을 영문으로 번역하는 사람
한글을 영어로 번역 하는 작업은 크게 어렵지는 않습니다. 우리에겐 인터넷이 있으니까요.^^; 중학교 고등학교 6년간의 수업에서 어느정도 주워들은 정도의 기본만 있다면 google신의 힘을 빌어 누구든지 할 수 있습니다. 좀 막히는 부분들은 숙어, 속담, 숨은뜻, 관용어 등이 있겠지요? 하지만 이것도 검색하다 운이 좋다면 얻어 걸릴수도 있겠죠. 못찾을수도 있구요. 그보다는 번역가의 영어실력에 따라 얼마나 세련된 번역이 가능한지 정도의 차이가 있겠죠.
예를 들어 "숨기고 싶은 비밀" 이라는 말을 번역해야 합니다. 구글번역기로 돌려 봅니다.
You want to hidea secret
이게 외국의 정치계에서 사용하는 관용어구로는 다음과 같은 말을 사용한다고 합니다.(물론 검색해서 나온겁니다. 예로 들자고 쓴거고 틀릴 수도 있습니다. 저두 영어는 잘 모르거든요 ㅠㅠ)
skeleton in the closet
그냥 뜻만 보자면 벽장속의 해골입니다. 숨기고 싶은 비밀인거죠.
흑인영어도 예를 들어 보겠습니다.
"오랜만에 만나네요" 를 영어로 번역하는데 오리지널로 하면
It's been a while since I've been you
흑인영어로 하면
I haven't seen you in a minute
이라고 합니다. 미국인들에게 뭐로 해도 뜻은 통하겠죠? 미국에선 백인영어가 세련된 영어라고 하지요.
사투리도 있습니다.
한글을 "너랑 나랑" 으로 하든 "니캉 내캉" 으로 하든 영어로 번역할때 "You and Me" 라고 해주면 번역된 글을 보는사람에게 큰 문제가 없습니다. 하지만 번역을 사투리로 한다면 힘들어 지겠죠. 다음의 예를 들어 보겠습니다.
미국의 남부지방에서는 about to 대신 fixing to 를 사용한다고 합니다. 한술더떠 want to를 wanna 로 줄여서 사용하듯 fixna 로 줄여서 사용한다고 합니다. i'm fixna see my mama 는 곧 엄마를 만날거라는 뜻이라고 합니다. ..이게 뭥미.@_@.
남부지방 사람이 아닌 미국인중에도 알아듣는사람도 있겠고 못알아듣는 사람도 있겠죠. 식당아주머니에게 된장찌개뚝배기를 넘기며 "이거좀 뜨사주세요" 혹은 "데파주세요" 하면 눈치로 알아듣고 다시 데워 주시는 분도 있을거고 "네?..." 라고 못알아 듣는 분도 있는 것처럼요.
프로그래머
위에 적은 이야기가 그대로 반복됩니다.
학원이 됬든 독학이 됬든 기본기만 배운사람이든, 대학4년 전공으로 배운사람이든 프로그램은 누구나 짤 수 있습니다. 구글신이 계시니까요. 검색하면 다 나옵니다. 운좋게 얻어걸리면 남들이 다 짜놓은 소스를 그대로 퍼다 쓸수도 있습니다. 우왕ㅋ굳ㅋ 손안대고 코풀었네요. 혹은 숙어나 관용어구와 비교할 수 있는 라이브러리의 사용법을 배울수도 있습니다. 저의 경우 String.replaceAll() 을 사용할때 검색변수가 regex 여서 자꾸 정규식으로 적용되어 불편함을 느낀적이 있었습니다. 그래도 다른방도가 없는줄 알고 그냥 불편한대로 쓰다가 나중엔 직접 작성해서 쓰고 있었는데 우연히 어떤 소스를 보고 아파치에서 제공하는 StringUtil 라이브러리를 알게 되었습니다. 하나 얻어 걸린거죠.
어쨌거나 뭐가 됐든 번역은 됩니다. 컴퓨터가 알아듣는다는 이야기지요. 프로그램은 돌아갑니다.
바디랭귀지건 흑인영어건 사투리건 초등학생 수준의 영어건 뜻은 통하고 알아들어먹으면 장땡인거죠.
정말 그럴까요? 뭐.. 그렇긴 하죠.. 어쨌거나.
번역가와 비교해 봤을때 프로그래머의 기본 소양은 두가지라고 생각합니다.
첫번째는 한글로 문장을 만드는 일입니다. 번역가는 다른 문장가가 쓴 글을 번역하면 되지만 프로그래머는 스스로 글도 작성하고 번역도 해야되지요. 클라이언트(또는 본인)의 요구사항을 먼저 잘 만들어진 문장으로 만들어야만 합니다. 로직을 짜고 설계를 하는 능력과 같다고 생각합니다.
아직도 잘 믿겨 지진 않지만 저보다 경력이 많은 한 친구는 회사에서 면접을 담당하는데요. 면접자들중에는 4년제 전공을 하고도 정말 간단한 로직을 짜보도록 요청하면 30분이 넘도록 작성을 못하는 사람들이 종종 있다고 하더군요. 물론 보면 어떻게 돌아가는지는 이해한다고 하네요. 문장을 못 만들지만 독해는 가능한 케이스네요.
두번째는 점점 세련된 영문으로 번역할 수 있도록 노력하는겁니다. 사람도 보는것만으로 해석이 가능한 프로그램을 짜는 겁니다. 컴퓨터만 알아먹게 만들면 된다고 하시면 뭐 할말 없습니다.ㅋ
Calendar.DAY_OF_WEEK == 6 이라고 하면 컴퓨터가 알아듣는데 문제는 없습니다. 하지만,
Calendar.DAY_OF_WEEK == Calendar.FRIDAY 라고 적는다면.. 금요일인지 알아보는거구나..라고 사람도 알아보는데 어려움이 없겠죠. (예제의 허접함을 손가락질 하지 말아주셈..)
MailSender.sendMail(a1, a2, a3, a4);
이런 코드.. 짜증나죠 ㅋ 앞뒤로 한참을 추적하면서 분석해야 뭔지 찾을 수 있는.. 다음처럼 읽기 쉬운코드로 만들면 좋을텐데 말이죠. 그렇게 어려운 작업도 아닌데.
조금씩 더 나은 번역을 위해 조금더 나은 코드를 위해 생각하고, 고민하고 개선하는 시간이 필요합니다. 영어의 기초를 더 쌓고 숙어, 관용어구를 익히고 점점 더 세련된 문장을 완성해 가듯이, 프로그래밍의 기초를 더 쌓고 리팩토링 기법을 익히고 라이브러리, 프레임워크등의 사용법을 배워나가면서 점점 더 좋은 코드를 작성할 수 있게 되겠지요. 언제까지 복사&붙이기를 할 수는 없겠죠 ^^
적용하는 방법은 다음과 같습니다. 에디터를 실행하고 명령어 입력 모드에서 다음의 명령어를 입력합니다.
:syntax on
:colorscheme 스키마이름
항상 적용하려고 한다면 ~/.vimrc 설정파일에 입력해 두시면 됩니다.
현재의 설정 상태 (백업용).
scripte utf-8
" vim: set fenc=utf-8 tw=0: "
" 파일의 첫부분에 위의 2줄을 꼭 남겨 두십시오. "
"vim설정파일"
"vim 전용기능 사용"
set nocp
"옵션복원"
set all&
set enc=UTF-8
set fileencodings=UTF-8
set nocompatible
set backspace=indent,eol,start
set title
set tabstop=4
set shiftwidth=4
set cindent
set autoindent
set smartindent
set history=15
set ruler
set showcmd
set background=dark
set paste
set nu
set ai
syntax on
colorscheme zellner