2014/05/20

[Redmine] plugin install/uninstall

# Installing a plugin

- For Redmine 1.x:
rake db:migrate_plugins RAILS_ENV=production

- For Redmine 2.x:
rake redmine:plugins:migrate RAILS_ENV=production

# Uninstalling a plugin

- For Redmine 1.x:
rake db:migrate:plugin NAME=plugin_name VERSION=0 RAILS_ENV=production

- For Redmine 2.x:
rake redmine:plugins:migrate NAME=plugin_name VERSION=0 RAILS_ENV=production

2014/05/02

[MSSQL] SP ROLLBACK제어

SP에서 트랜잭션의 일관성을 유지하기 위해 로직으로 제어할 수도 있지만
SQL SERVER 옵션(XACT_ABORT)으로 쉽게 제어할 수도 있다.

SET XACT_ABORT ON/OFF

트랜잭션 시작 전
SET XACT_ABORT ON

INSERT …

UPDATE …

끝난 후
SET XACT_ABORT OFF

이 경우 SQL문이 하나라도 에러가 발생하면 모두 롤백된다.

무료(비로그인) 화상대화 서비스

작년 5월에 알게된 서비스인데 다른 곳에 메모해 두었다가 이제서야 블로그에 기록한다.

http://www.veckon.com/

대화방 명 입력하면 해당 이름으로 계정을 만들지 않고도 화상대화를 할 수 있는 서비스로
잘만 활용하면 유용할 듯 하다.

[Oracle] 년도, 분기 입력으로 날짜 구하기

입력 값 : 년도, 분기
- 년도 : 2013
- 분기 : 3

* SQL1
SELECT '2013' AS YEAR
     , LPAD(1 + (QT * 3), 2, '0') || '01' AS ST_MD
     , LPAD(3 + (QT * 3), 2, '0') || '31' AS END_MD
  FROM ( SELECT '3' - 1 AS QT FROM DUAL) X
* 결과1
YEAR ST_MD END_MD
2013 0701 0931

* SQL2
위 SQL1에서는 해당 분기의 마지막 일자를 31일로 고정시켰으나 정확하게 하기 위해서는 입력 년도와 계산에 의한 월을 가지고 LAST_DAY함수를 사용해야 함.
SELECT '2013' AS YEAR
     , LPAD(1 + (QT * 3), 2, '0') || '01' AS ST_MD
     , LPAD(3 + (QT * 3), 2, '0') || TO_CHAR(LAST_DAY(TO_DATE('2013'||LPAD(3 + (QT * 3), 2, '0'), 'YYYYMM')), 'DD') AS END_MD
  FROM ( SELECT '3' - 1 AS QT FROM DUAL) X
* 결과2
YEAR ST_MD END_MD
2013  0701  0930

상기의 SQL을 인라인뷰(자주 사용된다면 함수로 등록)로 하여 대상 테이블의 BETWEEN 조건으로 활용하면 됨.

[JavaScript] 팝업창 사이즈 조절

※ 개요 : 전자정부 프레임웍을 사용하여 화면 오픈 시 컨트롤러에서 에러가 발생하여 화면이(메인화
면/팝업화면) 에러페이지로 대체가 될 때 해당 에러페이지 구현.
※ 기능 : window.open으로 팝업창 오픈 또는 jQuery의 simplemodal 레이어팝업 오픈 시 사이즈와
위치를 동적으로 조절하는 기능.
※ 테스트 브라우저 : ie7/8/9/10, 크롬, 파폭, 사파리


 


<div id="div_main_wrap" style="display: none;">
    전달 메시지...
</div>
 

<div id="div_pop_wrap" style="display: none;">
    전달 메시지...
    <button type="button" title="닫기" onclick="fn_close()">닫기</button>
</div>

※ 레이어팝업의 경우 팝업화면에서 오픈 되는 팝업화면에 에러가 발생하여 상기의 에러페이지로 대체될 때 파폭, 사파리에서는(크롬도 동일했나…?) 브라우저 센터 포지션 조정에 약간의 문제가 있다.

updated at 2014.05.23
리사이즈 후 부모창보다 팝업창의 height가 큰 경우 자동으로 스크롤이 생기는데 이 경우 다시 resize 처리 추가

eclipse 단축키 Open Implementation

이클립스로 작업하다보면 Object 또는 Method Declaration 은 F3 단축키를 을 이용하여 빠르게 엑세스가 가능한데 Method Implementation 은 기본 단축키가 설정되어 있지 않다.
이는 사용자 지정을 해야 하는데 첨부의 이미지로 설명을 대체하며, 본인은 F3 바로 옆에 있는 F4로 지정함.
기존에 할당된 키는 삭제.


eclipse에서 console의 폰트 사이즈 변경법

[출처] http://codejob.co.kr/code/view/106/

[Windows] - [Preferences] - [General] - [Appearance] - [Colors and Fonts] - Debug - Console font

'Edit' 선택 후 변경!

[jQuery] radio box 값 지정하기

// html
<input type="radio" name="rdo_gbnCd" id="rdo_y" value="Y"/>예
<input type="radio" name="rdo_gbnCd" id="rdo_n" value="N"/>아니오

// script
var strGbnCd = "Y";
$("input:radio[name=rdo_gbnCd]").val( [strGbnCd] );  //radio box는 array 형태로 값 지정

상기의 방법(배열 형태로 값에 따른 노드 선택 지정)은 select 엘리먼트에도 적용됨.

[jQuery] 테이블 행 click toggle

jQuery toggleClass()와 removeClass()를 이용하여 table tr click시 background-color 지정 방법이 여러 가지 있는데
이번에 내가 사용한 방법은…


<tr onclick="$.fn_toggle()">
 

오픈강좌 - opentutorials.org

다양한 IT기술들에 대한 오픈강좌 사이트가 있어서 기록한다.

http://opentutorials.org

javax.sql.DataSource 인식 문제로 서비스 오류



org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlMapClient' defined in ServletContext…[…/ibatis_config.xml]: Error setting property values; nested exception is org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
PropertyAccessException 1: org.springframework.beans.TypeMismatchException: Failed to convert property value of type [org.jboss.resource.adapter.jdbc.WrapperDataSource] to required type [javax.sql.DataSource] for property 'dataSource'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [org.jboss.resource.adapter.jdbc.WrapperDataSource] to required type [javax.sql.DataSource] for property 'dataSource': no matching editors or conversion strategy found

이하 생략.


이번 케이스의 경우 애플리케이션 클래스로더 영역에 jdbc2_0-stdext.jar 파일이 포함되어 있어서 시스템에서 사용하는 db벤더의 jdbc 드라이버가 인식이 되지 않고 가로채기(?) 상황이 되어버린 것이었다.

문제가 되는 jdbc2_0-stdext.jar 파일을 삭제하니 바로 해결됨.

[jQueryMobile] orientationchange 이벤트 활용

//You can add the resize event in the event parameter of the bind function,
//if you're targeting iOS and orientationchange doesn't work.
//Since changing orientation fires the resize event too.
$(window).bind('orientationchange', function(e) {
//    if ("portrait" == $.event.special.orientationchange.orientation()) {
//        //Do whatever in portrait mode
//    } else {
//        //Do Whatever in landscape mode
//    }
    var orientation = window.orientation;
 
    if(90 == orientation || -90 == orientation) {
        //portrait
    } else {
        //landscape
    }
    
    //본문 내에 동적으로 삽입된 테이블의 width를 부모 div의 width로 적용
    $(테이블id).css("width", $(부모 div id).css("width"));
});

[출처] http://stackoverflow.com/questions/10023328/orientation-change-event-implementation-by-jquery-mobile-in-phone-gap

상단 주석 처리된 if문이 있을 때와 현재 적용된 아래 if문을 적용 했을 때 이벤트가 적용되는 시점의 차이가 있었다.
뭐가 다른지 참...
주석 처리된 부분을 적용할 경우 이벤트가 빨리 발생해 아래 css가 적용되는 시점이 실제 가로/세로
기울기 변경이 끝나기 전의 값을 읽어와 적용되는 현상이 발생한 것이다.
하여 구글링해서 현재의 window.orientation 속성을 읽어오는 것으로 기술이 되어 있다.(실제 사용하는 것은 없지만...)

[jQuery] 테이블의 행에 선택적 background-color 지정

//pTarget : $("#tableId tbody tr")
//pObj : 선택한 tr object - $(tr)
//ex) ....
 
//테이블 row 선택 시 동적 배경색 지정
function gfnChgRowColor(pTarget, pObj) {
    var viewCnt = 0;
    $.each($(pTarget), function(idx, obj) {
        if("none" != $(this).css("display")) viewCnt++;    //실제 보이는 row count 체크
        
        if($(pObj).index() == idx) {
            if(viewCnt%2 == 0) {
                $(obj).removeClass("table-blue");    //짝수 row 컬러 지정 class
            }
            $(obj).addClass("selected");    //선택한 row 컬러 지정 class
        } else {
            //삭제한 row 컬러 지정 class 는 남겨두고 다른 row들의 class 변경
            if(!$(obj).hasClass("deleted")) {
                $(obj).removeClass("selected");
                if(viewCnt%2 == 0) {
                    $(obj).addClass("table-blue");
                }
            }
        }
    });
}

참고로 jquery 셀렉터의 필터 중에 홀/짝수를 판단하는 필터가 있다.
:even/:odd

[jQuery] select box 변경

jQuery를 이용하여 select box의 내용을 동적으로 변경 시...

예를 들면 sel1 이라는 콤보에 sel2라는 콤보의 데이터(options)를 jQuery로 동적으로 변경 할 때엔
$("#sel1 option").each(function() {
    $(this).remove();
});
 
$("#sel2 option").each(function() {
    $("#sel1").append("");
});

또는

$.each($("#sel1 option"), function() {
    $(this).remove();
});
 
$.each($("#sel2 option"), function() {
    $("#sel1").append("");
});
※ 추가로 jQuery Mobile에선 내용 삽입(append) 후 refresh를 해줘야 반영됨.
$("#sel1").selectmenu("refresh");
또는
$("#sel1").selectmenu("refresh", true);

[jquerymobile] pageinit/pageshow event

... 중략 ...
답변 1 :
You're checking for the wrong events, pageinit and pageshow are what you should be concerned about.
pageinit fires everytime a page is loaded for the first time, jQM caches pages in the DOM/memory so when you navigate back from two.html to one.html, pageinit won't fire (it's already initialized)
pageshow fires everytime a page is shown, this is what you need to be looking for when you navigate back from two.html to one.html
Together you can pull off a lot of clean code, use pageinit for initializing, configuration etc and update your DOM to the initial state. If you have dynamic data on the page that may change between views, handle it in pageshow 
 
Here's a good design for larger websites that we use in a production environment:
  1. bind a live event to all pages/dialogs pageinit and pageshow events in some include that is on every page:
    $(document).on('pageinit pageshow', 'div:jqmData(role="page"), div:jqmData(role="dialog")', function(event){
  2. I reference each page with a name: In this live event you can basically have a switch statement for each page "name", and then check event.type for pageinit/pageshow or both and put your code there, then every time a page is created/shown this event will be fired, it knows what page triggered it and then calls the corresponding code
  3. Now no matter what entry point a user lands on your site, all the handlers for all the pages are loaded. As you may already know, when you navigate to a page, it only pulls in <script/> within the div[data-role="page"] - ignoring any JS in the <head/>, placing separate JS on each page is a mess and should be avoided in any large site I believe
  4. Try not to use blanket selectors in your jQuery, e.g. $('div.myClass') since this will search all of your DOM which may have more than one jQM page in it. Luckily in the live event handler for pageinit/pageshow mentioned above, this refers to the current page. So do all DOM searches within it, e.g. $(this).find('div.myClass') this ensures you are only grabbing elements within the current page. (of course this isn't a concern for ids). Note in the pageshow event you can also use $.mobile.activePage, but this isn't available in the pageinit, so I don't use it for consistency

I eventually had too much code, so I built a handler object where each page's js is included in a separate js file and can register handlers with the live event
The drawback is that all your js for your entire site is loaded on the first page the user reaches, but minified even a large site is smaller than jQuery or jQM so this shouldn't be a concern. But if your site really is large I suppose you could look into RequireJS.
The advantage is you are no longer loading all your JS for each page through AJAX each time the user navigates to a new page. If all your JS is available on entry, you can now put debugger statements and debug much more easily!
... 중략 ...
답변 2 :
You require a thourough read of the jQuery Mobile event documentation:http://jquerymobile.com/demos/1.1.0/docs/api/events.html
The above links gives some great insight into when each of the events fire, here are a couple samples from the page:
pageinit
Triggered on the page being initialized, after initialization occurs. We recommend binding to this event instead of DOM ready() because this will work regardless of whether the page is loaded directly or if the content is pulled into another page as part of the Ajax navigation system.
.
pageshow
Triggered on the "toPage" after the transition animation has completed. Callbacks for this event will recieve a data object as their 2nd arg. This data object has the following properties on it: prevPage (object) A jQuery collection object that contains the page DOM element that we just transitioned away from. Note that this collection is empty when the first page is transitioned in during application startup.
To actually answer your question, don't use pageinit, use pageshowpageshow fires on the initial showing of a page (just after the pageinit event is fired on the element) but also on subsequent visits to the page.


※ 적용 결과
한 화면(html)에 사용되는 각 page 마다 pageshow 이벤트 핸들러로 동일 스크립트를 적용함.

모바일 웹 개발 시 유용한 라이브러리

[출처] http://kindlybugs.com/240

apprise

웹뷰에서 alert / confirm 등을 사용하면 팝업 메세지에 웹 페이지 주소가 노출되는 단점 아닌 단점이 있는데, 이것이 싫다면 div 를 통한 팝업 구현이 필요하다. 그리고 iOS 4.X나 안드로이드 웹뷰에서 position: fixed를 사용할 수 없어, 고정된 위치에 팝업을 띄우는 것이 귀찮은 편인데, 이를 대신해주는 라이브러리. 반복적인 class selector 호출 등의 최적화 되지 않은 jQuery 사용이 있어, 그러한 부분을 개선하여 사용하였다.

참고 : http://thrivingkings.com/apprise/


cross-slide

Ken-burns 스타일의 사진 슬라이드 효과를 내기 위해 사용

참고 : http://tobia.github.com/CrossSlide/
참고 : 사용기 / http://blog.naver.com/ez_/140156789842


iscroll

iOS / Android 등에서 pinch to zoom / pull to refresh / overflow:scroll 를 구현하기 위한 라이브러리. 많이 사용하진 않았지만, 웹에서 사용성을 높이기 위해서는 한 번 쯤 살펴볼만 하다.

참고 : http://cubiq.org/iscroll-4


jstorage

Local storage를 사용하기 위한 라이브러리. 서버와 통신할 필요가 없는 값들을 읽고 쓰기 위해 사용하였다. 간단하고 사용하기 편리하다.

참고 : http://en.wikipedia.org/wiki/Web_storage
참고 : http://www.jstorage.info/


lazyload

화면에 보이지 않는 부분의 이미지들은 굳이 미리 서버에서 가져올 필요가 없다. lazyload를 통해 트래픽을 줄이고, 페이지 로드 시간을 단축할 수 있다. 모든 웹 페이지에서 가지면 좋은 기능이지만, 모바일 웹에서는 반드시 가져야 할 요소.

참고 : http://www.appelsiini.net/projects/lazyload
참고 : 사용기 / http://blog.naver.com/ez_/140156676013


spin.js

ajax 요청등을 보내고 기다릴 때, 흔히 볼 수 있는 activity indicator를 animated gif 등으로 처리하는 것이 일반적이었다면, spin.js 를 통해 이미지 없이 멋진 spin image를 만들어낼 수 있다. 단, 안드로이드 일부기기에서 지원하지 않는 문제가 있어 현재는 울며 겨자먹기로 animated gif 를 사용중.

참고 : http://fgnass.github.com/spin.js/


swipe

모바일 기기의 swipe 기능을 이 라이브러리를 통해 웹에서 완벽히 재현할 수 있다. lazyload와 함께 사용해, 다른 페이지에 있는 이미지들을 나중에 불러오도록 구성하면 최적. 단, 기본적으로 제공하는 callback은 webkit의 transitionEnd 시점에 발생하는 것이라, swipe를 시작하는 시점에 callback을 받으려면 몇 줄의 코드를 추가해야 한다.

참고 : http://swipejs.com/
참고 : 수정된 swipe.js / https://gist.github.com/2404749


zflow

웹에서 coverflow 효과를 줄 때 사용한 라이브러리. iOS쪽은 iPhone 3Gs에서도 충분히 부드럽고 빠르게 작동하지만, Android에서는 OS와 기기에 따라 제대로 지원되지 않는 경우가 많다. 특히 rotateY 등의 transform 적용시, 잘못된 축으로 회전된 결과가 나오므로 Android기기일 경우는 몇 가지 fallback을 추가로 작업해야 사용가능한 상태가 된다. 안드로이드에서는 크기나 회전은 제외하고, opacity를 조정하는 정도로만 사용하고 있다. 이 점만 유의하면 충분히 쓸만한 라이브러리인 듯.

참고 : http://code.google.com/p/css-vfx/


출처 : http://blog.naver.com/ez_/140157300770

Window7 64bit + Oracle 11g Client 32bit + Toad 환경 설정법

Window7 64bit + Oracle 11g Client 32bit 환경 설정법


요약 :

Windows 7 64bit 에서 Toad 사용 방법
■ Toad 는 10.0.1.7부터 windows 7을 정식 지원한다.
■ Toad 는 현재(10.6.1.3)까지 32bit Oracle Client만을 지원한다.
■ 만약 Oracle DB를 설치하지 않고 Toad만을 사용한다면 반드시 Oracle Client 32bit 버전을 설치해야 한다.
■ 로컬 개발환경에서 DB를 사용하지 않고 Toad만을 사용한다면 굳이 Oracle Database를 설치할 필요가 없이 
   Client버전만 설치해도 된다.
■ Oracle Client 설치시 Toad에서 DB접속에 Direct 접속을 통해서 접속해야한다.(TNS 접속 불가)
■ 설치(setup.exe) 실행 전 3개의 파일을 수정해야한다.(Windows 7 Oracle 10g Client 설치시)
- Disk1/install/oraparam.ini 수정
- Disk1/stage/prereqs/client/refhost.xml 수정
- Disk1/stage/prereqs/client_prereqs/client/refhost.xml 수정

Window7 64bit환경에 jwFreeNote 5.9 설치 시 오류 해결법

jwFreeNote라는 노트 프로그램을 사용함에 있어서
32비트 OS에서 사용할 때는 문제가 안 되지만 64비트에선 실행 시 오류가 발생하는데
오류 알림창에서 '문제해결' 을 클릭해서 정보를 보면 Window Agent 미지원 어쩌고 하는 얘기를 하면서 윈도우 핫픽스를 설치하라고 안내한다.

패키지:
-----------------------------------------------------------
-----------------------------------------------------------
KB 문서 번호: 969168
언어: All (Global)
플랫폼: x64
위치: http://hotfixv4.microsoft.com/Microsoft%20Agent/latest/MSAgentWin7x64/200909210200/free/395040_intl_x64_zip.exe

설치 후엔 정상적으로 jwFreeNote가 실행되고 사용할 수 있다.

[jQuery] div객체에 focus지정하기


개요 : div객체는 focus를 받기 전에 tabindex가 지정되어야 하는데, div객체에 속성으로 tabindex를 할당하지 않고 jQuery로 tabindex를 지정한 뒤 focus function을 호출하면 됨.

$("#div_id").attr("tabindex", -1).focus();
또는 
$("#div_id").attr("tabindex", -1).focus({
    //do...
});

html에 DOCTYPE 사용 시 브라우저 리사이징 처리 팁



과거 회사 게시판에 올렸던 글인데 이번에 찾을 일이 있어서 블로그에 포시팅 해 둔다.

===========================================================================================

이번에 개발할 때 페이지에 DOCTYPE을 선언하여 개발하는데
기존에 DOCTYPE없을 때 개발했던 프레임구조(상하단으로 구분하고 하단프레임의 좌측에
div로 tree메뉴를 표현, 전체에는 iframe으로 업무화면을 표현. 좌측 트리메뉴를 숨길 수 있도록
구성하여 iframe의 업무화면이 동적으로 사이징 처리됨.)를 그대로 가져와서 화면을 구성했을 때 이상하게
리사이징을 하면 iframe이 윈도우의 height를 제대로 읽어오지 못하는 현상이 발생했습니다.

방식은 window.onresize 이벤트를 캐치해서
iframe.style.height = document.body.scrollHeight+"px";로
읽어오도록 했었죠

JavaScript의 스크롤된 위치를 알아오기 위해서 document.body.scrollTop을 사용함.

그런데, 상단에 DOCTYPE이 선언된 경우
(!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ...)

document.body.scrollTop의 값이 항상 0으로 출력된다.

이때는 document.documentElement.scrollTop으로 바꾸어 사용해야 한다.

결론 : body -> documentElement

[MySQL] ROWNUM 구하기

MySQL은 ORACLE이나 MSSQL처럼 ROW_NUMBER() OVER() 함수가 지원되지 않는다.
대신 sql문 내에서 변수(@변수명)가 지원된다.
SELECT A, B, @RNUM := @RNUM + 1 AS RNUM
  FROM T
     , (SELECT @RNUM := 0) A

위 처럼 인라인뷰에서 변수 선언 및 초기화를 하고 SELECT 절에서 ROW 만큼 1씩 증가시키는 구조.

추가로 PARTITION BY 를 쓸려면...
변수를 하나 더 쓰면 된다
SELECT A, B
     , CASE WHEN @V_A = A THEN @RNUM ELSE @RNUM := @RNUM + 1 END AS RNUM
     , @V_A := A
  FROM T
     , (SELECT @V_A := 0, @RNUM := 0) A

sql내에서 변수가 지정되다보니 변수를 아주 유용하게 활용할 수 있다.

Window7 자동로그인

1. 실행창에 netplwiz 입력
2. 해당 사용자 선택 후 '사용자 이름과 암호를 입력해야 이 컴퓨터를 사용할 수 있음' 체크박스 해제
3. '적용' 클릭 시 팝업창에 등록된 암호 입력

마음가짐

[출처] 공병호의 뉴스레터 No.1067(2013-01-03)

... 미국의 위대한 심리학자인 윌리엄 제임스는 이렇게 말했다.
우리 시대에 가장 위대한 발견은 자신의 마음을 바꾸는 것으로 해서
자신의 인생을 바꿀 수 있다는 것이다.
나는 거만하지 않겠다.
나는 일을 시키지만은 않고 바닥에서부터 함께 일하겠다.
지금 당장! 지금 당장! 나는 늘 언제나 밝게 웃는 사람이 되겠다....

[MSSQL] IDENTITY지정 컬럼에 명시적으로 INSERT하기

SET IDENTITY_INSERT 옵션을 이용하여 IDENTITY가 지정된 컬럼에 명시적으로 값을 입력할 수 있다.
그러나 UPDATE는 안 됨.
-- IDENTITY 컬럼 지정
CREATE TABLE ID_TEST (
    ID_KEY INT IDENTITY(1,1),
    ID_NOT INT
)
 
-- IDENTITY 컬럼에 명시적 입력 설정
SET IDENTITY_INSERT ID_TEST ON
 
INSERT INTO ID_TEST (ID_KEY, ID_NOT )
SELECT ID_KEY, VAL
  FROM (
        SELECT 1 AS ID_KEY, 11 AS VAL UNION ALL
        SELECT 2 AS ID_KEY, 12 AS VAL UNION ALL
        SELECT 3 AS ID_KEY, 13 AS VAL UNION ALL
        SELECT 4 AS ID_KEY, 14 AS VAL 
       ) A
 
-- IDENTITY 컬럼에 명시적 입력 해제
SET IDENTITY_INSERT ID_TEST OFF

혼자하는 심장발작 응급조치

간단하면서도 효과적인 방법으로 아주 유익한 정보가 있었군…

[출처] 미상

[MSSQL] Linked Server로 다른 DB 연동 시 주의점

1. MSSQL의 linked server를 이용하여 ORACLE 또는 다른 DB와 연동 시 성능에 대한 고찰이 잘 된 자료인 것 같아서 해당 URL을 기록해 둔다.

http://www.dator.co.kr/?mid=textyle&category=1036&vid=hjkim&document_srl=91461

2. 아래는 linked server 설정 및 문제 해결 방법에 대해 블로그 포스트에서 참조된 MS의 기술자료 URL이다.
이번에 인터페이스하면서 이기종(MSSQL, ORACLE) 간 트랜잭션 문제가 있어서 해당 자료의 가장 마지막에 간단히 언급된 방법(MSSQL의 XACT_ABORT 옵션 사용)으로 조치하니 잘 되는 것 같았다.
물론 상황에 따라 대응방법은 다르겠지만...

http://support.microsoft.com/kb/280106/ko

[MSSQL] 2008 R2 64bit 와 Oracle 11g 32bit 사이의 Linked Server 생성


SQL은 64bit, Oracle은 32bit... Linked Server 세팅 문제 시 
1) 32bit Clients를 먼저 깔고 64bit 를 설치! 
   - 설치 시 Base Directory 는 동일하게, Path는 다르게. 
2) 레지스트리 세팅 수정! 
   - HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSDTC\MTxOCI 와  
  - HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\MSDTC\MTxOCI 의 값을 아래의 파일명으로 변경한다.
a. OracleOciLib = oci.dll 
b. OracleSqlLib = orasql11.dll (이전: SQLLib80.dll) 
c. OracleXaLib = oraclient11.dll (이전: xa80.dll) 

DB2에서 ORACLE의 CONNECT BY LEVEL 사용하기

-- Oracle
SELECT LEVEL
  FROM DUAL
CONNECT BY LEVEL < 13;

-- DB2
SELECT RNUM
  FROM TABLE(VALUES '01','02','03','04','05','06','07','08','09','10','11','12') T1(RNUM);
으로 원하는 가상의 레코드 테이블을 만들 수 있다. 위의 쿼리는 스트링타입으로 12개의 레코드를 가지는 테이블을 만든 것이다. T1이라는 테이블 알리아스에 FETCH된 컬럼은 RNUM이라고 지정한 것이다. VALUES의 값은 원하는 대로 지정하면 된다. 참고로 ORACLE에서의 DUAL은 DB2에서 SYSIBM.SYSDUMMY1 이다.
SELECT CURRENT TIMESTAMP
  FROM SYSIBM.SYSDUMMY1;

[MSSQL] table backup

MSSQL에서 테이블단위 백업/복구를 하기 위해서는
MSSQL SERVER command 창에서 아래 명령어 실행.

1. backup
bcp DB명.dbo.테이블명 out 경로\파일명 -c /U유저ID /P유저PWD

2. recover
bcp DB명.dbo.테이블명 in 경로\파일명 -c /U유저ID /P유저PWD

아이폰 Passbook 활용하기

http://passbank.co.kr 에서 왠만한 멤버십 카드등록을 할 수 있다.
또한 카드 종류가 지속적으로 추가 업데이트 되고 있는 것 같다. 

아이폰 사파리로 접속 후 등록할 멤버십 카드를 선택하고 이름, 이메일, 멤버십카드 번호를 입력 후 Add to Passbook을 클릭하면 해당 멤버십카드 바코드가 Passbook 앱에 등록된다.

폴더 비교 및 동기화 FreeFileSync

FreeFileSync
폴더 비교 및 동기화를 시각화하여 작업할 수 있는 툴.

FreeFileSync is a folder comparison and synchronization tool providing highly optimized performance and usability without a needlessly complex user interface.

[MSSQL] 테이블스키마 조회

프로젝트에서 누군가 만든 쿼리인데 유용하게 쓰일 때가 있어서 포스팅한다.

--######## 스키마정보 마스터조회(마스터쿼리) ########--
SELECT A.TYPE TABLE_TYPE
      ,(CASE WHEN A.TYPE='U' THEN '테이블' WHEN A.TYPE='V' THEN '뷰' END) TABLE_TYPE_NM
      ,A.NAME TABLE_ID
      ,ISNULL(CONVERT(VARCHAR,Z.VALUE),'') TABLE_NAME
      ,A.CREATE_DATE TABLE_CREATE
      ,A.MODIFY_DATE TABLE_MODIFY
      ,A.OBJECT_ID
  FROM SYS.OBJECTS A WITH(NOLOCK)
  LEFT JOIN SYS.EXTENDED_PROPERTIES Z WITH(NOLOCK)
    ON Z.MAJOR_ID = A.OBJECT_ID
   AND Z.MINOR_ID = 0
 WHERE A.TYPE IN ('U','V')
   AND A.TYPE LIKE ? +'%'     --조건값(테이블유형 U:테이블,V:뷰)
   AND A.NAME = (CASE WHEN ? ='' THEN A.NAME ELSE ? END) --조건값(테이블ID)
   AND ISNULL(CONVERT(VARCHAR,Z.VALUE),'') LIKE '%'+?+'%' --조건값(테이블명)
   AND EXISTS(SELECT 1
                FROM INFORMATION_SCHEMA.COLUMNS S WITH(NOLOCK)
                LEFT JOIN SYS.EXTENDED_PROPERTIES T WITH(NOLOCK)
                  ON T.MAJOR_ID = A.OBJECT_ID
                 AND T.MINOR_ID = 0
                 AND T.NAME = 'MS_Description'
                LEFT JOIN SYS.EXTENDED_PROPERTIES U WITH(NOLOCK)
                  ON U.MAJOR_ID = A.OBJECT_ID
                 AND U.MINOR_ID = S.ORDINAL_POSITION
                 AND U.NAME = 'MS_Description'
               WHERE S.TABLE_NAME  = A.NAME
                 AND ISNULL(CONVERT(VARCHAR,U.VALUE),'') LIKE '%'+?+'%'  --조건값(컬럼명)
                 AND S.COLUMN_NAME = (CASE WHEN ? ='' THEN S.COLUMN_NAME ELSE ? END)  --조건값(컬럼ID)
             )
ORDER BY A.TYPE, A.NAME

--######## 스키마정보 상세조회(디테일쿼리) ########--
SELECT B.ORDINAL_POSITION      SEQ  --순번
      ,B.COLUMN_NAME COLUMN_ID
      ,ISNULL(CONVERT(VARCHAR,Y.VALUE),'') COLUMN_NAME
      ,CASE WHEN B.DATA_TYPE IN ('VARCHAR', 'NVARCHAR', 'char', 'nchar')
            THEN B.DATA_TYPE + '(' + CONVERT(VARCHAR(10), ISNULL(B.CHARACTER_MAXIMUM_LENGTH, B.NUMERIC_PRECISION)) + ')'
            WHEN B.DATA_TYPE IN ('DECIMAL')
            THEN B.DATA_TYPE + '(' + CONVERT(VARCHAR(10), B.NUMERIC_PRECISION) + ', ' + CONVERT(VARCHAR(10), B.NUMERIC_SCALE) + ')'
            ELSE B.DATA_TYPE
            END AS COLUMN_TYPE
      ,CASE WHEN B.COLUMN_NAME IS NOT NULL THEN 'YES' ELSE '' END AS IS_PK
      ,CASE WHEN B.IS_NULLABLE='NO' THEN 'YES' ELSE '' END AS IS_NOTNULL
      ,ISNULL(B.COLUMN_DEFAULT,'') AS DEFAULT_VALUE
  FROM SYS.OBJECTS A WITH(NOLOCK)
  JOIN INFORMATION_SCHEMA.COLUMNS B WITH(NOLOCK)
    ON B.TABLE_NAME = A.NAME
  LEFT JOIN SYS.EXTENDED_PROPERTIES Y WITH(NOLOCK)
    ON Y.MAJOR_ID = A.OBJECT_ID
   AND Y.MINOR_ID = B.ORDINAL_POSITION
   AND Y.NAME = 'MS_Description'
 WHERE A.OBJECT_ID = ?
ORDER BY B.ORDINAL_POSITION

--######## 스키마정보 조회(컬럼정보만조회쿼리) ########--
SELECT A.GUBUN             --구분
      ,A.TABLE_TYPE        --테이블유형
      ,A.TABLE_TYPE_NM     --테이블유형명
      ,A.TABLE_ID          --테이블ID
      ,A.TABLE_NAME        --테이블명
      ,A.TABLE_CREATE      --테이블생성일
      ,A.TABLE_MODIFY      --테이블수정일
      ,A.SEQ               --순번
      ,A.COLUMN_ID         --컬럼ID
      ,A.COLUMN_NAME       --컬럼명
      ,A.COLUMN_TYPE       --컬럼타입
      ,A.IS_PK             --PK
      ,A.IS_NOTNULL        --NotNull
      ,A.DEFAULT_VALUE     --디폴트값
  FROM (
        SELECT 'TABLE' GUBUN
              ,A.TYPE TABLE_TYPE
              ,(CASE WHEN A.TYPE='U' THEN '테이블' WHEN A.TYPE='V' THEN '뷰' END) TABLE_TYPE_NM
              ,A.NAME TABLE_ID
              ,ISNULL(CONVERT(VARCHAR,Z.VALUE),'') TABLE_NAME
              ,A.CREATE_DATE TABLE_CREATE
              ,A.MODIFY_DATE TABLE_MODIFY
              ,0             SEQ
              ,'' COLUMN_ID
              ,'' COLUMN_NAME
              ,'' COLUMN_TYPE
              ,'' IS_PK
              ,'' IS_NOTNULL
              ,'' DEFAULT_VALUE
          FROM SYS.OBJECTS A WITH(NOLOCK)
          LEFT JOIN SYS.EXTENDED_PROPERTIES Z WITH(NOLOCK)
            ON Z.MAJOR_ID = A.OBJECT_ID
           AND Z.MINOR_ID = 0
           AND Z.NAME = 'MS_Description'
         WHERE A.TYPE IN ('U','V')
        UNION ALL
        SELECT 'COLUMN' GUBUN
              ,A.TYPE TABLE_TYPE
              ,(CASE WHEN A.TYPE='U' THEN '테이블' WHEN A.TYPE='V' THEN '뷰' END) TABLE_TYPE_NM
              ,A.NAME TABLE_ID
              ,ISNULL(CONVERT(VARCHAR,Z.VALUE),'') TABLE_NAME
              ,A.CREATE_DATE TABLE_CREATE
              ,A.MODIFY_DATE TABLE_MODIFY
              ,B.ORDINAL_POSITION          SEQ
              ,B.COLUMN_NAME COLUMN_ID
              ,ISNULL(CONVERT(VARCHAR,Y.VALUE),'') COLUMN_NAME
              ,CASE WHEN B.DATA_TYPE IN ('VARCHAR', 'NVARCHAR', 'char', 'nchar')
                    THEN B.DATA_TYPE + '(' + CONVERT(VARCHAR(10), ISNULL(B.CHARACTER_MAXIMUM_LENGTH, B.NUMERIC_PRECISION)) + ')'
                    WHEN B.DATA_TYPE IN ('DECIMAL')
                    THEN B.DATA_TYPE + '(' + CONVERT(VARCHAR(10), B.NUMERIC_PRECISION) + ', ' + CONVERT(VARCHAR(10), B.NUMERIC_SCALE) + ')'
                    ELSE B.DATA_TYPE
                    END AS COLUMN_TYPE
              ,CASE WHEN C.COLUMN_NAME IS NOT NULL THEN 'YES' ELSE '' END AS IS_PK
              ,CASE WHEN B.IS_NULLABLE='NO' THEN 'YES' ELSE '' END AS IS_NOTNULL
              ,ISNULL(B.COLUMN_DEFAULT,'') AS DEFAULT_VALUE
          FROM SYS.OBJECTS A WITH(NOLOCK)
          JOIN INFORMATION_SCHEMA.COLUMNS B WITH(NOLOCK)
            ON B.TABLE_NAME = A.NAME
          LEFT JOIN (SELECT A.TABLE_NAME, B.COLUMN_NAME
      FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS A WITH(NOLOCK)
      JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE B WITH(NOLOCK)
        ON A.TABLE_NAME = B.TABLE_NAME
       AND A.CONSTRAINT_NAME = B.CONSTRAINT_NAME
     WHERE A.CONSTRAINT_TYPE = 'PRIMARY KEY'
                    ) C
            ON C.TABLE_NAME = A.NAME
           AND C.COLUMN_NAME = B.COLUMN_NAME
          LEFT JOIN SYS.EXTENDED_PROPERTIES Z WITH(NOLOCK)
            ON Z.MAJOR_ID = A.OBJECT_ID
           AND Z.MINOR_ID = 0
           AND Z.NAME = 'MS_Description'
          LEFT JOIN SYS.EXTENDED_PROPERTIES Y WITH(NOLOCK)
            ON Y.MAJOR_ID = A.OBJECT_ID
           AND Y.MINOR_ID = B.ORDINAL_POSITION
           AND Y.NAME = 'MS_Description'
         WHERE A.TYPE IN ('U','V')
        ) A
 WHERE A.GUBUN          = 'COLUMN'
         AND A.TABLE_TYPE  LIKE ?+'%'     --조건값(테이블유형 U:테이블,V:뷰)
         AND A.TABLE_ID    = (CASE WHEN ?='' THEN A.TABLE_ID ELSE ? END) --조건값(테이블ID)
         AND A.TABLE_NAME  LIKE '%'+?+'%' --조건값(테이블명)
         AND A.COLUMN_ID   = (CASE WHEN ?='' THEN A.COLUMN_ID ELSE ? END) --조건값(컬럼ID)
         AND A.COLUMN_NAME LIKE '%'+?+'%' --조건값(컬럼명)
ORDER BY A.TABLE_TYPE, A.TABLE_ID, A.SEQ, A.COLUMN_ID

### 수정 : 9/27(목)
PK 여부값 조회 부분 수정

윈도우 계정 비번 모를 경우

[출처] Life is Good

윈도우즈 계정의 비밀번호를 모를경우 해결하는 방법이 있어서 정리해 둡니다.

먼저 컴을 키면서 F8을 눌러서 안전모드로 들어갑니다. 안전모드 중에서 "안전모드 명령프롬프트" 사용을 선택하면 도스 (DOS) 상태로 부팅이 됩니다. 
도스 프롬프트에서 net user 라는 명령으로 등록된 계정들을 살펴봅니다.
만약에 홍길동 이라는 계정이 있다면, 역시 도스에서 net user 홍길동 1234 라고 하면 비밀번호가 1234로 바뀌게 됩니다.

다시 컴을 재부팅해서 홍길동 계정을 선택한 다음에 1234로 로그인 하면 됩니다.
즐거운 컴생활 하시길 바랍니다~ 

배려와 행복

배려와 행복의 관계…

[출처] 배려의 기술 - 지동직 지음


데이터베이스 모델링 - 정리

  • 모델링 순서 : 개념 -> 논리 -> 물리 모델링
          1. 실제 개념모델링 단계에서 ERD가 작성

  • 각 단계별 작업내용 요약
1. 개념모델링
   주요엔티티 도출
   관계지정

2. 논리모델링
   모든 속성 도출
   식별자 도출
   정규화
   M:M관계 제거
   Super-Sub타입 전개
   엔티티 통합
   이력적용(History엔티티 적용)
   Naming Standard
   도메인 작성

3. 물리모델링
   논리모델을 DBMS특성에 맞춰 물리적구조(Schema) 작성
   DB저장공간, 저장방법 등 전반적인 운용방법 고려
   성능고려 반정규화(역정규화) 고려
   테이블 분리/통합

데이터베이스 모델링 - 도메인

도메인 정의를 활용하여 물리모델에서의 컬럼속성 변경에 유연하게 대처하자. 


데이터베이스 모델링 - 정규화와 Naming Standard

간만에 교육 받는군.
새롭다...

* 정규화
제1정규화 : Primary Key에 대해 반복속성 분리.
제2정규화 : Primary Key에 대한 부분종속 속성 분리.
Primary Key가 복합키인 경우 각각에 대한 부분종속 제거해야 함.
제3정규화 : 일반 속성(컬럼) 중 종속관계에 있는 속성 분리.

* Naming Standard(ERWin에서 논리모델로 작성된 Physical모델의 한글명을 영문으로 일괄변경 방법)
(아래 수순은 개략적으로 정리한 것으로 완전하진 않음)
1. 메뉴 Tools > Names > Model Naming Option.. 에서 'Name Mapping'탭 선택 후
 Entity..., Attribute... 항목의 'Use Gloss'열 체크.
 이후 Export 버튼 클릭 후 csv로 저장.

2. 메뉴 Tools > Names > Edit Naming Standard.. 에서 'Glossary'탭 선택 후
 물리모델에 포함된 컬럼 중 두 개만 기입하고 각각 'P'와 'C'열을 지정한다.
 (P는 Entity, C는 Attribute 라 생각하면 되며, 해당되는 것에 체크하면 됨)
 Export 버튼을 클릭 후 .nsm 파일로 저장.

3. 메뉴 Tools > Data Browser 선택 > New ERwin Report 생성
 Report 타입은 Logical 선택.
 Name은 임의로 지정, Category는 Attribute 선택.
 Options 탭에서 Entity하위의 'Name'과 루트하위의 'Name' 항목에 체크.

4. 생성된 Object에서 우클릭 후 'Excute...' 실행.

5. 생성된 하위 Object에서 우클릭 후 'Export...' 선택 후 csv로 저장.

6. 5번에서 생성한 csv파일의 두 번째 열에 한글명에 부합하는 영문을 기입한다.

7. 메뉴 Tools > Names > Edit Naming Standard.. 에서 'Glossary'탭 선택 후
 6번에서 작성한 csv파일을 Import한다.
 Import내용을 확인 후 nsm파일로 저장한다.

8. 메뉴 Tools > Names > Model Naming Option.. 에서 'General'탭 선택 후
 7번에서 저장한 nsm파일을 불러온다.

9. 확인 후 Physical모델에서 반영되지 않았으면
 메뉴 Tools > Names > Model Naming Option.. 에서 'General'탭 선택 후 'Reload'버튼을 클릭하여 갱신한다.

[MSSQL] 근무일 수 구하기

[출처] http://www.sqler.com/83649

SELECT CASE WHEN SUBSTRING(ENTER_DT,5,2) > SUBSTRING(Z.RETIRE_DT,5,2)
            THEN DATEDIFF(YY, CONVERT(DATETIME, ENTER_DT), Z.RETIRE_DTM) - 1 
            ELSE DATEDIFF(YY, CONVERT(DATETIME, ENTER_DT), Z.RETIRE_DTM) 
       END AS 년
     , CASE WHEN RIGHT(ENTER_DT,2) > RIGHT(Z.RETIRE_DT,2)
            THEN DATEDIFF(M, CONVERT(DATETIME, ENTER_DT), Z.RETIRE_DTM)%12 - 1 
            ELSE DATEDIFF(M, CONVERT(DATETIME, ENTER_DT), Z.RETIRE_DTM)%12 
       END AS 개월
     , CASE WHEN RIGHT(ENTER_DT,2) > RIGHT(Z.RETIRE_DT,2)
            THEN DATEDIFF(D,CONVERT(CHAR(6),DATEADD(M,-1, Z.RETIRE_DTM),112)+RIGHT(ENTER_DT,2), Z.RETIRE_DTM)+1
            ELSE DATEDIFF(D,CONVERT(CHAR(6),DATEADD(M,0, Z.RETIRE_DTM),112)+RIGHT(ENTER_DT,2), Z.RETIRE_DTM)+1
       END AS 일
  FROM (
        SELECT '20100708' AS ENTER_DT
             , '20120301' AS RETIRE_DT
             , CONVERT(DATETIME, '20120301') AS RETIRE_DTM
       ) Z

결과 : 1년 7개월 23일

* 퇴사일이 20120308 이면
결과는 1년 8개월 1일

* 일자(마지막 2자리)에 따라 개월 수와 일 수가 계산됨(일 수가 무조건 양수로 표현되도록 함)

[MSSQL] MSSQL2008 사용 시 2PC 처리를 위한 설정

까먹기 전에 수집한 자료와 관련내용을 정리한 문서를 첨부해 두어야겠다.

<요약>
MSSQL에서 2PC(2Phase Commit - XA Transaction)을 처리하기 위해서는
1. OS레벨에서 DTC설정을 해야 하고
2. MSSQL서버에 추가로 dll 등록 후 프로시저를 실행해서 관련 모듈을 로드 해야 한다.

습관

습관 - 어린 새가 날갯짓을 연습하듯 매일매일 반복하여 마음에 꿰인 듯 익숙해진 것.

사람의 행동이 습관이 될 때까지 걸리는 기간은 평균 66일 이라고 한다. 

매번 실패하더라도 반복적으로 실행하는 것이 핵심.

읽어볼까...

로버트 제누아, <당신의 입을 다스려라>, 바다출판사

입을 잘못 놀려 난처한 경우가 한두 번이 아닌데...

걱정에 대처하는 3단계

[출처] 데일 카네기 자기관리론

■ 윌리스H.캐리어의 마법의 공식 -걱정을 극복하는 3단계-

·제1단계 스스로에게 ‘일어날 수 있는 최악은 어떤 것인가?’ 하고 물어보라.
·제2단계 필요한 경우 최악을 받아들일 준비를 하라.
·제3단계 침착하게 최악의 상황을 개선하기 위해 노력하라.

스트레스 줄이는 방법

[출처] 공병호의 뉴스레터 No.930(2011-11-17)

5. 와카야마 현립의과대학의 우에야마 다카시 교수는 알코올에 의한
스트레스 해소 효과가 실제로 어느 정도인지 연구했다.
그의 연구는 술을 마시면 스트레스가 풀리는 느낌이 들지만,
여전히 몸은 스트레스를 느낀다.
결국 술은 스트레스를 푸는 데 별다른 도움이 되지 않는다.
게다가 술은 몸에 그다지 이롭지 않다.
'술은 백약의 으뜸'이라고 하지만,
뇌를 생각하면 한 방울도 마시지 않는 것이 바람직하다.


6. 술이 뇌에 미치는 효과 중 하나는 대뇌피질의 활동을
강하게 억제한다는 것이다.
대뇌피질은 진화 과정에서 새로 생성된 부위다.
그렇다면 뇌의 중심부(뇌간)는 생명과 관련된 부위이므로
알코올에 영향을 받지 않도록 튼튼하게 만들어지지 않았을까?
그에 비해 새로 생긴 대뇌피질은 마음 같은 고차원적인 기능과
관련된 부위지만 생명유지에 꼭 필요한 부위는 아니기 때문에
알코올 같은 외적 요소에 쉽게 마비되지 않을까?


7. 대뇌피질의 기능 중 하나는 이성을 만들어내는 것이다.
이성의 대표적인 기능은 본능 억제다.
이성은 이기심이나 성욕 같은 본능을 억제함으로써 인간을
사회적 동물로 만든다.
본능은 뇌의 중심부에서 생겨난다.
대뇌피질은 동물적인 본능을 억제하도록 진화하면서 발달한
새로운 구조다.


8. 알코올은 그 대뇌피질을 억제한다. 즉 이성을 억제하는 것이다.
술에 취하면 잘 웃거나 잘 우는 식으로 성격이 변하기도 하는데,
이것은 숨어 있던 본능이나 본성의 발로라고 할 수 있다.
물론 술에 취했을 때 드러나는 성격이 반드시 본성이라고 말할 수는
없지만, 알코올이라는 화학물질을 대뇌피질의 활동을 억제하는
뇌과학적인 수단으로 바라보면 충분히 가능한 해석이다.

-출처: 이케가와 유지, (착각하는 뇌), 리더스북, pp.63-70

==================================================

담배를 끊어야 합니다. 술을 줄여야 합니다.

Paint.Net 으로 투명배경 이미지 만들기

무료로 사용할 수 있는 Paint.Net으로 투명배경 이미지를 간단하게 만들 수 있다.
도구의 '마술 봉' 사용.

이미지를 새로 만들 때 : 마술봉으로 배경을 선택하고 삭제버튼을 누르고 시작하면 됨.
이미지를 불러왔을 때 : 마술봉으로 흰색 부분의 배경을 선택하고 삭제버튼을 누르면 됨.


[prototype] getElementsByName 사용법

prototype에서는 getElementsByName 을 아래와 같이 사용한다.

$$("[name=객체명]")

ex) 
<input type=radio name=useYn value=Y>사용
<input type=radio name=useYn value=N>미사용
인 경우 
$$("[name=useYn]")[0].checked = true;
하면
'사용'에 체크가 됨.

[MSSQL] 달력

MSSQL 달력 SQL!
WITH TMP AS(
    SELECT CONVERT(VARCHAR(8), CONVERT(DATETIME, '201109' + dbo.Fn_LPAD(CAST(A.NUMBER + 1 AS VARCHAR ), 2, 0)),112) AS YMD
         , DATEPART(WK , CONVERT(DATETIME, '201109' + dbo.Fn_LPAD(CAST(A.NUMBER + 1 AS VARCHAR ), 2, 0))) AS WY    --WeekOfYear
         , DATEPART(DW , CONVERT(DATETIME, '201109' + dbo.Fn_LPAD(CAST(A.NUMBER + 1 AS VARCHAR ), 2, 0))) AS DW    --DayOfWeek
         , A.number AS NUM
         , '201109' AS CUR_YM
         , '2011' AS CUR_YYYY
         , '09' AS CUR_MM
      FROM master.dbo.spt_values A
     WHERE A.TYPE = 'P'
       AND A.NUMBER < dbo.Fn_GetLastDay('2011', '09')
)
SELECT X.RNUM
     , MIN(CASE X.DW WHEN 1 THEN X.YMD ELSE NULL END) AS COL_SUN
     , MIN(CASE X.DW WHEN 2 THEN X.YMD ELSE NULL END) AS COL_MON
     , MIN(CASE X.DW WHEN 3 THEN X.YMD ELSE NULL END) AS COL_THU
     , MIN(CASE X.DW WHEN 4 THEN X.YMD ELSE NULL END) AS COL_WED
     , MIN(CASE X.DW WHEN 5 THEN X.YMD ELSE NULL END) AS COL_THU
     , MIN(CASE X.DW WHEN 6 THEN X.YMD ELSE NULL END) AS COL_FRI
     , MIN(CASE X.DW WHEN 7 THEN X.YMD ELSE NULL END) AS COL_SAT
  FROM (
        SELECT CUR_YM, YMD, WY, DW
             , DENSE_RANK() OVER(ORDER BY WY) AS RNUM
          FROM TMP
       ) X
GROUP BY X.RNUM
※ 아래 사용자정의 함수는 같이 프로젝트를 수행한 동료가 작성한 것임을 밝힌다.
/*****###### USER DEFINE FUNCTION : Fn_LPAD ######*****/
USE [user id]
GO
/****** Object:  UserDefinedFunction [dbo].[Fn_LPAD]    Script Date: 09/16/2011 12:53:55 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[Fn_LPAD]
(@I_STR varchar(200), @I_STR_LEN int, @I_FILL_STR varchar(1))
RETURNS varchar(200)
WITH EXECUTE AS CALLER
AS
BEGIN
DECLARE @R_STR VARCHAR(200),
    @T_DIFF_LEN INT,
    @T_STR_LEN INT,
    @O_STR_LEN INT,
    @POS INT
    SET @O_STR_LEN = LEN(@I_STR)
    SET @T_STR_LEN = 0
    SET @POS = 1
    WHILE @O_STR_LEN >= @POS
    BEGIN
        IF LEN(UNICODE(SUBSTRING(@I_STR,@POS,@POS+1))) > 3
        BEGIN
            SET @T_STR_LEN = @T_STR_LEN + 2
        END
        ELSE
        BEGIN
            SET @T_STR_LEN = @T_STR_LEN + 1       
        END
        SET @POS = @POS+1   
    END
 SET @T_DIFF_LEN = @I_STR_LEN -  @T_STR_LEN
 IF @T_DIFF_LEN >= 0 
  SET @R_STR = REPLICATE(@I_FILL_STR, @T_DIFF_LEN) + @I_STR
 ELSE
  SET @R_STR = @I_STR
     RETURN substring(@R_STR,1,@I_STR_LEN )
END
  
 
/*****###### USER DEFINE FUNCTION : Fn_GetLastDay ######*****/
USE [user id]
GO
/****** Object:  UserDefinedFunction [dbo].[Fn_GetLastDay]    Script Date: 09/16/2011 13:59:45 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[Fn_GetLastDay]
(@YYYY varchar(4), @MM varchar(2))
RETURNS varchar(2)
WITH EXECUTE AS CALLER
AS
BEGIN
DECLARE @LASTDAY VARCHAR(2)
SELECT 
 @LASTDAY = DATEPART(DAY, DATEADD(MONTH, 1, @YYYY + '-' + @MM + '-01')-(DAY(@YYYY + '-' + @MM + '-01')))
RETURN @LASTDAY
END

jstl을 이용하는 jsp에서 라인피트(\n), 캐리지리턴(\r), 줄바꿈(\r\n) 값 replace 방법


< 요약 >
import taglib
[% 
pageContext.setAttribute("crlf", "\r\n"); 
pageContext.setAttribute("cr", "\r"); 
pageContext.setAttribute("lf", "\n"); 
%] 

${fn:replace(문자열, crlf, [br/])} 

전자정부프레임워크 - 파일업로드



개요

업로드는 한 컴퓨터 시스템에서 다른 시스템으로 파일을 전송하는 것을 말하는데, 대개 작은 컴퓨터에서 큰 컴퓨터로 옮길 때 이런 용어를 사용한다. 네트웍 사용자의 관점에서 보면, 파일을 업로드하는 것은 그 파일을 받을 수 있도록 설정된 다른 컴퓨터에 파일을 보내는 것이다. 전자게시판 상의 다른 사용자와 이미지 파일을 공유하기를 원하는 사람들은 그 전자게시판에 파일을 업로드하면 된다.
그러면 반대편 입장에 있는 사람은 그 파일을 다운로드하게 되는데, 여기서 다운로드는 대개 큰 컴퓨터에서 작은 컴퓨터로 파일을 전송하는 것을 의미한다. 인터넷 사용자의 입장에서의 다운로드란 다른 컴퓨터에서 파일을 받는 것이다.

설명

파일 업로드 기능을 구현하기 위해서는 먼저 빈 설정 파일에 다음과 같이 MultiCommonsMultipartResolver를 정의해야한다. 본 가이드에서는 Apache Commens FileUpload에서 재공하는 CommonsMultipartResolver를 사용하기를 권장한다. CommonsMultipartResolver를 수정하여 사용할 경우 많은 부분에 시간과 노력이 들어갈 것이다.
 
 id="local.MultiCommonsMultipartResolver"
 class="egovframework.rte.util.web.resolver.MultiCommonsMultipartResolver">
  name="maxUploadSize" value="100000000" />
  name="maxInMemorySize" value="100000000" />
>
[권장]만약 스프링에서 제공하는 Apache Commens FileUpload API를 이용하여 파일 업로드를 처리하는 CommonsMultipartResolver를 사용하려고 하면 빈 설정파일에 다음과 같이 정의한다.


 id="spring.RegularCommonsMultipartResolver"
 class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
  name="maxUploadSize" value="100000000" />
  name="maxInMemorySize" value="100000000" />
>
또한 해당 컨트롤러의 property로 파일의 업로드 위치를 지정해주고 컨트롤러에서 setter 메소드를 통해 지정된 파일 업로드 위치를 불러올 수 있다. 사용예는 다음과 같다.
fileUploadProperties.properties
# windows NT일 경우  
file.upload.path=C:\\temp
 
# Unix일 경우
file.upload.path=/usr/file/upload
@Resource(name = "fileUploadProperties")
Properties fileUploadProperties;
..
..
..
 String uploadPath = fileUploadProperties
   .getProperty("file.upload.path");
 File saveFolder = new File(uploadPath);
..
..
..
파일 업로드를 위해 JSP파일의 입력 폼 타입을 file로 지정하고 form의 enctype을 multipart/form-data로 지정한다. 예시는 다음과 같다. 이때 CommonsMultipartResolver를 사용할 경우 form의 name을 다르게 설정하여야 한다. 중복된 이름을 사용할 경우 에러가 발생한다.
<form method="post" action=""
enctype="multipart/form-data">
  <p>Type:
    <input type="text" name="type" value="genericFileMulti" size="60" />
  </p>
  <p>File1:
    <input type="file" name="file[]" size="60" />
  </p>
  <p>File2:
    <input type="file" name="file[]" size="60" />
  </p>
  <p>
    <input type="submit" value="Upload" />
  </p>
</form>
다음은 파일 업로드를 위해 Controller를 구현한 모습이다.
@Controller("genericFileUploadController")
public class GenericFileUploadController {
 
@Resource(name = "multipartResolver")
CommonsMultipartResolver multipartResolver;
 
@Resource(name = "fileUploadProperties")
Properties fileUploadProperties;
 
@SuppressWarnings("unchecked")
@RequestMapping(value = "/upload/genericMulti.do")
public String multipartProcess(final HttpServletRequest request, Model model)
 throws Exception {
 
final long startTime = System.nanoTime();
 
/*
 * validate request type
 */
Assert.state(request instanceof MultipartHttpServletRequest,
  "request !instanceof MultipartHttpServletRequest");
final MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
 
/*
 * validate text input
 */
Assert.state(request.getParameter("type").equals("genericFileMulti"),
  "type != genericFileMulti");
 
/*
 * extract files
 */
final Map<String, MultipartFile> files = multiRequest.getFileMap();
Assert.notNull(files, "files is null");
Assert.state(files.size() > 0, "0 files exist");
 
/*
 * process files
 */
String uploadPath = fileUploadProperties
  .getProperty("file.upload.path");
File saveFolder = new File(uploadPath);
 
// 디렉토리 생성
if (!saveFolder.exists() || saveFolder.isFile()) {
 saveFolder.mkdirs();
}
 
Iterator<Entry<String, MultipartFile>> itr = files.entrySet()
  .iterator();
MultipartFile file;
List fileInfoList = new ArrayList();
String filePath;
 
while (itr.hasNext()) {
 Entry<String, MultipartFile> entry = itr.next();
 System.out.println("[" + entry.getKey() + "]");
 
 file = entry.getValue();
 if (!"".equals(file.getOriginalFilename())) {
  filePath = uploadPath + "\\" + file.getOriginalFilename();
  file.transferTo(new File(filePath));
 
  FileInfoVO fileInfoVO = new FileInfoVO();
  fileInfoVO.setFilePath(filePath);
  fileInfoVO.setFileName(file.getOriginalFilename());
  fileInfoVO.setFileSize(file.getSize());
  fileInfoList.add(fileInfoVO);
 }
}
 
// 여기서는 DB에 파일관련 정보를 저장하지 않고 단순히 success 페이지로 포워딩 하여 재확인 가능토록 함
model.addAttribute("fileInfoList", fileInfoList);
model.addAttribute("uploadPath", uploadPath);
 
final long estimatedTime = System.nanoTime() - startTime;
System.out.println(estimatedTime + " " + getClass().getSimpleName());
 
return "success";
 
 }
}
Tomcat에서는 일반적으로 웹 어플리케이션이 GET과 POST 방식으로 파라미터를 넘겨 받을 때 request.setCharacterEncoding()을 통한 문자셋 인코딩이 필요하다.