시작...

블로그 이미지
mutjin

Article Category

분류 전체보기 (148)
기록 (3)
개발새발 (8)
2010년 이전 글 (133)
호주로의 여행.. (41)
VC++ 자료 (12)
C/C++ 자료 (16)
프로그래밍 (43)
computer (12)
기타... (9)

Recent Post

Recent Comment

Recent Trackback

Calendar

«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Archive

My Link

  • Total
  • Today
  • Yesterday
  1. 2008.03.04
    000 싸이트 자바스크립트 유틸 메소드 모음
  2. 2007.10.23
    다중 접속 서버 프로그래밍
  3. 2007.10.23
    Dialog Window 띄우면서, 작업표시줄에서 감추기
  4. 2007.10.23
    중복 실행 방지.
  5. 2007.10.23
    [강좌] 기초적인 압축 알고리즘 하이텔 퍼옴..
  6. 2007.10.12
    class 들의 단계적 참조 관계
  7. 2007.09.21
    IOCP (IOCompletionPort) 분석
  8. 2007.08.17
    프로그래밍 :: 오라클 강좌
  9. 2007.08.17
    Oracle 10g의 Recycle Bin의 기능에 대해서...
  10. 2007.07.03
    리눅스 기본명령어

/*************************************************************
최종수정일:

일반함수

btMov_AddList
checkNumber

일반함수

BT_getComboData 셀렉트 생성
BT_CheckLastAcctno 계좌번호 끝에 3자리 000 제거
BT_makeAcntnoDash 계좌번호에 하이픈을 넣음
BT_MakeAcntList 계좌번호를 리스트로 만듬
BT_MakePayAcntList 계좌번호를 리스트로 만듬
BT_ReduceDash 하이픈을 삭제
BT_makeCardnoDash 카드번호 하이픈 넣기
BT_getToday 오늘 날짜열을 YYYYMMDD의 형식으로 만듬
BT_make2Length 월일을 두자리로 만듬

BT_makeCardnoDash 카드번호 하이픈 넣음
BT_makeMembernoDash 회원번호(16자리) 하이픈 넣기

BT_TrimSpace 공백없애기

BT_calc 금액 더하기 계산
BT_Del_comma 콤마 삭제
BT_Add_comma 입력폼 작성시 콤마 추가
BTCom_Replace 문자변환

BT_Add_Displaycomma 금액 Display 시 콤마 추가
BT_Add_NumberComma 금액의 앞자리 0을 없애고 콤마추가
BT_Add_NumberComma1
BT_toMoneyF 환율,외화에 소수점,콤마 추가

BT_Reduce_comma 콤마 제거

BT_isAlphabet 값이 알파벳만 있는지 체크
BT_isNumber 값이 숫자만 있는지 체크
BT_number 숫자만 입력
BT_isTrsfPass 이체 비밀번호 체크 루틴

BT_getRandomNumber 씨크릿 카드 번호 생성

BT_makeCustnoDash 9자리 고객번호 하이픈을 넣음

BT_makeResnoDash 주민번호 하이픈 넣기

BT_makeLoannoDash 대출계좌에 하이픈 넣기

BT_makeDateDash yyyy-mm-dd
BT_makeDateDash_1 yyyy-mm
BT_makeDateDash_2 mm-dd
BT_makeDateDash_3 mm
BT_makeTime 00:00:00

BT_StrToInt 문자열을 10진수로 변환

BT_makeDecimalPoint 소수점이 포함된 숫자 앞에 포함된 0 을 제거

last_page 페이지 설정

BT_EngNum 숫자와영어만 허용

BT_SetServiceCode ServiceCode박아주기
BT_Setreturn_url return_url 박아주기
BT_getRandomNumber() { //씨크릿 카드 순차번호 생성

pwCheck() 비밀번호 연번 확인 => 주석확인

***************************************************************/
var alphaArray = new Array();
alphaArray[0]  = 'a' ;alphaArray[1] = 'b';alphaArray[2] = 'c';alphaArray[3] = 'd';
alphaArray[4]  = 'e' ;alphaArray[5] = 'f';alphaArray[6] = 'g';alphaArray[7] = 'h';
alphaArray[8]  = 'i' ;alphaArray[9] = 'j';alphaArray[10] = 'k';alphaArray[11] = 'l';
alphaArray[12] = 'm';alphaArray[13] = 'n';alphaArray[14] = 'o';alphaArray[15] = 'p';
alphaArray[16] = 'q';alphaArray[17] = 'r';alphaArray[18] = 's';alphaArray[19] = 't';
alphaArray[20] = 'u';alphaArray[21] = 'v';alphaArray[22] = 'w';alphaArray[23] = 'x';
alphaArray[24] = 'y';alphaArray[25] = 'z';
alphaArray[26] = 'A';alphaArray[27] = 'B';alphaArray[28] = 'C';alphaArray[29] = 'D';
alphaArray[30] = 'E';alphaArray[31] = 'F';alphaArray[32] = 'G';alphaArray[33] = 'H';
alphaArray[34] = 'I';alphaArray[35] = 'J';alphaArray[36] = 'K';alphaArray[37] = 'L';
alphaArray[38] = 'M';alphaArray[39] = 'N';alphaArray[40] = 'O';alphaArray[41] = 'P';
alphaArray[42] = 'Q';alphaArray[43] = 'R';alphaArray[44] = 'S';alphaArray[45] = 'T';
alphaArray[46] = 'U';alphaArray[47] = 'V';alphaArray[48] = 'W';alphaArray[49] = 'X';
alphaArray[50] = 'Y';alphaArray[51] = 'Z';

function getCode(argObj1,argObj2){
 Key1 = argObj1;
 Key2 = argObj2;
 if(top.iWallet.LoadCode_state == false){
  top.iWallet.LoadCode = top.iWallet.LoadCode + 1;
  if(top.iWallet.LoadCode <= 5){
   setTimeout("getCode(Key1,Key2)", 1000)
  }else{
   alert("코드 초기화에 실패하였습니다.\n처음으로 돌아갑니다.")
   SID = get_sessionid();
   CryptoClient.Logout(SID); 
   top.location.href="/btindex.asp";
  }
 }else{
  retString = ""
  try {
   sKey = argObj1 + "^" + argObj2;
   retString = top.iWallet.sTradcode[sKey];
   if (!retString) retString = "";
   return retString;
  }catch(e) {
   return "";
  } 
 }
}

//OPEN창에서 사용
function getCode2(argObj1,argObj2){
 Key1 = argObj1;
 Key2 = argObj2;
 if(opener.top.iWallet.LoadCode_state == false){
  opener.top.iWallet.LoadCode = opener.top.iWallet.LoadCode + 1;
  if(opener.top.iWallet.LoadCode <= 5){
   setTimeout("getCode2(Key1,Key2)", 1000)
  }else{
   alert("코드 초기화에 실패하였습니다.\n처음으로 돌아갑니다.")
   SID = get_sessionid();
   CryptoClient.Logout(SID); 
   top.location.href="/btindex.asp";
  }
 }else{
  retString = ""
  try {
   sKey = argObj1 + "^" + argObj2;
   retString = opener.top.iWallet.sTradcode[sKey];
   if (!retString) retString = "";
   return retString;
  }catch(e) {
   return "";
  } 
 }
}

function BT_LoadCode(){
 var dgbcode=ttradcode();
 tmp1 = dgbcode.split("^^^");
 for(k=0;k<tmp1.length;k++){
  tmp2 = tmp1[k].split("^^");
  top.iWallet.sTradcode[tmp2[0]]=tmp2[1];
 }
}

//코드구분, 셀렉트이름, selected값
function BT_getComboData(argObj1,selname,argObj2){
 Key1 = argObj1;
 Key2 = selname;
 Key3 = argObj2;

 if(top.iWallet.LoadCode_state == false){
  top.iWallet.LoadCode = top.iWallet.LoadCode + 1;
  if(top.iWallet.LoadCode <= 5){
   setTimeout("BT_getComboData(Key1,Key2,Key3)", 1000)
  }else{
   alert("코드 초기화에 실패하였습니다.\n처음으로 돌아갑니다.")
   SID = get_sessionid();
   CryptoClient.Logout(SID); 
   top.location.href="/btindex.asp";
  }
 }else{
  try {
    var data=top.iWallet.ttradcode();
    var split_data=data.split("^^^");
    var len = split_data.length;
    var L_ListText = "<select name=\"" + selname + "\" id=\"" + selname + "\">";
    

    for(i=0;i<len;i++) {
     var splitdata_in=split_data[i].split("^^");
     var splitdata_in2=splitdata_in[0].split("^");

     if(splitdata_in2[0] == argObj1)
     {
      if (splitdata_in2[1] == argObj2) {
       L_ListText += "\t<option value=\"" + splitdata_in2[1] + "\" selected>" + splitdata_in[1] + "</option>\n";
      } else {
      L_ListText += "\t<option value=\"" + splitdata_in2[1] + "\">" + splitdata_in[1] + "</option>\n";
      }
     }
     
    }

    L_ListText = L_ListText + "</select>"
    return L_ListText;
   }catch(e) {
   return false;
   }  
 }
}

function btAlertNoValue ( thisvalue , alertvalue )
{
 if ( thisvalue.value == "" )
 {
  var smsg;
  smsg = alertvalue + "을(를) 입력하셔야 합니다.";
  alert(smsg);
  thisvalue.focus();
  return 1;
 }

 return 0;
}


function btMov_AddList(argObj, argData, argValue,selval){
 
 argObj.length = argObj.length + 1 
 argObj.options(argObj.length-1).text = argData
 argObj.options(argObj.length-1).value = argValue
 if(selval != ""  && selval == argValue) argObj.options(argObj.length-1).selected = true;

}

//숫자외의 문자 check
function checkNumber(data) {
 t = data.value ;
 for(i=0;i<t.length;i++)
  if (t.charAt(i)<'0' || t.charAt(i)>'9') {
  if (t.charAt(i) != '*') {
   alert("숫자만 입력해주세요.") ;
   data.value="";
   data.focus() ;
   return false ;
  }
 }
}


function btTextCheckDate(Dnum,StaYer,StaMon,StaDay,EndYer,EndMon,EndDay)
{

     now = new Date();
     var cur_year= now.getYear();
  var cur_month =  now.getMonth();
  var month =  now.getMonth()+1;
  month=new String(month);
  var cur_day = now.getDate();
  cur_day=new String(cur_day);
     var d_cur_date = new Date(cur_year,cur_month,cur_day);
  var dategubun;
     
  var num = Dnum;
 
        eval("doc."+StaYer+".readOnly = true");
        eval("doc."+StaMon+".readOnly = true");
        eval("doc."+StaDay+".readOnly = true");
        eval("doc."+EndYer+".readOnly = true");
        eval("doc."+EndMon+".readOnly = true");
        eval("doc."+EndDay+".readOnly = true");
  if(num==0){ //당일
   var before_date = new Date(Date.parse(d_cur_date) - 1*1000*60*60*24);
   dategubun = "1주일전";
  }else if(num==1){ //1주일전
   var before_date = new Date(Date.parse(d_cur_date) - 7*1000*60*60*24);
   dategubun = "1주일전";
  }else if(num==2){ //15일전
   var before_date = new Date(Date.parse(d_cur_date) - 15*1000*60*60*24);
   dategubun = "15일전";
  } else if(num==3){ //30일
   var before_date = new Date(Date.parse(d_cur_date) - 30*1000*60*60*24);
   dategubun = "30일";
  } else if(num==4){ //기간설정(3개월) 
   var before_date = new Date(Date.parse(d_cur_date) - 91*1000*60*60*24);
          eval("doc."+StaYer+".readOnly = false");
          eval("doc."+StaMon+".readOnly = false");
          eval("doc."+StaDay+".readOnly = false");
          eval("doc."+EndYer+".readOnly = false");
          eval("doc."+EndMon+".readOnly = false");
          eval("doc."+EndDay+".readOnly = false");  
   dategubun = "기간설정";
  }
 
  var yest_date = new Date(Date.parse(d_cur_date)-1000*60*60*24);
  var yest_year = new String(yest_date.getYear());
  var yest_month = new String(yest_date.getMonth()+1);
  
  
  if(yest_month.length==1){
   yest_month = '0'+yest_month;
  }
     
  if(month.length==1){
   month = '0'+ month;
  }
     
     
  if(cur_day.length==1){
   cur_day = '0'+cur_day;
  }
     
  var before_year = new String(before_date.getYear());
  var before_month = new String(before_date.getMonth() +1);
  if(before_month.length==1){
   before_month = '0'+before_month;
  }
  var before_day = new String(before_date.getDate());
  if(before_day.length==1){
   before_day = '0'+before_day;
  }

    if(num==0){
          eval("doc."+StaYer+".value=cur_year");
          eval("doc."+StaMon+".value=month");
          eval("doc."+StaDay+".value=cur_day");
          eval("doc."+EndYer+".value=cur_year");
          eval("doc."+EndMon+".value=month");
          eval("doc."+EndDay+".value=cur_day");
         }
         else if(num==4){
        eval("doc."+StaYer+".value=''");
          eval("doc."+StaMon+".value=''");
          eval("doc."+StaDay+".value=''");
          eval("doc."+EndYer+".value=''");
          eval("doc."+EndMon+".value=''");
          eval("doc."+EndDay+".value=''");                
  } 
         else
     {
      eval("doc."+StaYer+".value=before_year");
        eval("doc."+StaMon+".value=before_month");
        eval("doc."+StaDay+".value=before_day");
        eval("doc."+EndYer+".value=cur_year");
        eval("doc."+EndMon+".value=month");
        eval("doc."+EndDay+".value=cur_day");
     }
}


//*--  필드 AutoSkip  --*//
function btAutoSkip(){

 var  el = event.srcElement
 if ((el.value == null) || (event.keyCode==13)) return(false)
  
 // 방향키 무시
 var sKeys = "8;16;46;;37;38;39;40;33;34;35;36;45;229;"
 if (sKeys.indexOf(event.keyCode+";") > -1) return;

 if  (el.tagName == "INPUT" )
  if  (el.value.length  >=  el.maxLength ) {
   var i=0
   while (el != el.form.elements[i] )  i++
   if ( (i+1) != el.form.elements.length ) {
    while ( ( el.form.elements[i+1].type == "hidden" ) ||
     ( el.form.elements[i+1].type == "button" ) ||
     ( el.form.elements[i+1].type == "checkbox" ) ||
     ( el.form.elements[i+1].type == "radio" ) ||
     ( el.form.elements[i+1].tagName == "FIELDSET" ) ||
     ( el.form.elements[i+1].style.display == "none" )  ||
     ( el.form.elements[i+1].disabled == true ) ||
     ( el.form.elements[i+1].style.visibility == "hidden" )) {
    i++
    if ( (i+1) == el.form.elements.length ) return;
   }
   }
   else{
    el.form.elements[i].focus();
    return(false);
   }
       
   el.form.elements[i+1].focus()
   if(el.form.elements[i+1].tagName != "SELECT") el.form.elements[i+1].select()
   else if(el.form.elements[i+1].tagName == "SELECT") {
    if(el.form.elements[i+1].value==null || el.form.elements[i+1].selectedIndex==-1)
                el.form.elements[i+1].value = "";
   }
  }
}

//계좌번호에 하이픈 넣기 - pansory
function BT_makeAcntnoDash (val) {
 var DashedAcntno = val 
 if (val.length == 11) { //계좌번호가 11자리일 경우
  DashedAcntno = val.substring(0,3) + "-" + val.substring(3,5) + "-" + val.substring(5)
 } else if (val.length == 12){
  DashedAcntno = val.substring(0,3) + "-" + val.substring(3,5) + "-" + val.substring(5,11) + "-" + val.substring(11)
 }else if(val.length == 13) { //계좌번호가 13자리일 경우
  DashedAcntno = val.substring(0,3) + "-" + val.substring(3,5) + "-" + val.substring(5,11) + "-" + val.substring(11)
 } else if (val.length == 14) { //계좌번호가 14자리일 경우
  DashedAcntno = val.substring(0,3) + "-" + val.substring(3,5) + "-" + val.substring(5,11) + "-" + val.substring(11)
 } else if (val.length == 16){
  DashedAcntno = val.substring(0,3) + "-" + val.substring(3,5) + "-" + val.substring(5,11) + "-" + val.substring(11)
 } 
 return DashedAcntno;
}

//계좌번호 끝3자리에서 000 제거
function BT_CheckLastAcctno(val){
 var TempAccntno = val;
 var len = val.length;
 var tempAcc = len - 3;
 var lastAccNo = val.substring(tempAcc, len);
 
 if (lastAccNo == "000"){  
  TempAccntno = BT_makeAcntnoDash(val.substring(0, tempAcc));
 } else {  
  TempAccntno = BT_makeAcntnoDash(TempAccntno);
 }
 return TempAccntno;
}

//계좌번호 선택..
function BT_SelectAcntno(USR_AccsList, NeedAcntno) {
 
 var no = NeedAcntno.length;
 var Acntno_No = USR_AccsList.length;
 var SelectedAcntno = new Array();
 var k = 0;

 if (no == 0) {
  SelectedAcntno = USR_AccsList;
  //나중에 확인 필요함.. 고른 것들 중에 첫번째 것을 세션에 넣기..????  
  save_session("ACNTNO", USR_AccsList[0]);
  save_flush();
  
 } else {
  for (var i=0; i < Acntno_No ; i++) {
   
   for(var j=0 ; j < no; j++) {
    
     if(USR_AccsList[i].length > 12) {
      stCode = USR_AccsList[i].substring( 9, 11);
      
     } else {
      stCode = "0"; //Case Error
     }
     
     if (stCode == NeedAcntno[j]) {
      SelectedAcntno[k] = USR_AccsList[i];
      
      
      
      if (k == "0") {
       //나중에 확인 필요함.. 고른 것들 중에 첫번째 것을 세션에 넣기..????  
       save_session("ACNTNO", USR_AccsList[i]);
       save_flush();
      }
      
      k++;
     }
   }
  }
 }
 
 return SelectedAcntno;
 
}

//계좌번호 Array를 셀렉트 박스로 변환 - pansory
//조건에 따라(0: 조회, 1: 이체가능, 2: 저축성, 4: 대출, 5: 신탁, 6: 기타)
function BT_MakeAcntList(val, selectedval,selname,condition) {
 var Acct = BT_KindAcct(val,condition);
 var tempAcct = Acct.split(",");
 
 var L_ListText = "<select name=\"" + selname + "\" id=\"" + selname + "\">";

 for(var i=0; i< tempAcct.length - 1; i++)  {
  if (tempAcct[i] == selectedval) {
   
   L_ListText += "\t<option value=\"" + tempAcct[i] + "\" selected>" + BT_makeAcntnoDash(tempAcct[i]) + "</option>\n";
  } else {
   L_ListText += "\t<option value=\"" + tempAcct[i] + "\">" + BT_makeAcntnoDash(tempAcct[i]) + "</option>\n";
  }
  
 }
 
 L_ListText += "</select>\n";

 return L_ListText;
}


//계좌종류별로계좌번호가져오기
/*[1] 11      -> /s100/bc101_r2.jsp  (1080) (계좌상세조회 결과와 같은 화면 사용)  
[2] 19 ~ 28 -> /s100/bc102_r3.jsp  (1020) (적립식예금)  
[3] 31 ~ 34 -> /s400/bc419_r1.jsp  (4190) (외화예금)  
[4] 40 ~ 49 -> /s100/bc102_r2.jsp  (1130) (대출계좌)  
[5] 50 ~ 73 -> /s100/bc102_r1.jsp  (1020) (기타)  
[6] 그 외   -> /s100/bc1090_r1.jsp (1090) (요구불예금)*/
function BT_KindAcct(Acct,kind)
{
 var tmpAcct = "";//new Array;
 var flag = new Array;

 flag = get_session("IGBGYEJI");

 for(i=0; i< Acct.length; i++){
  if(kind == ""){
   tmpAcct = tmpAcct + Acct[i] + ",";
  }else if(BT_StrToInt(kind) == BT_StrToInt(flag[i])) {
     tmpAcct = tmpAcct + Acct[i] + ",";
  }
 }
 return tmpAcct;
}

// "-" 삭제 - pansory
function BT_ReduceDash(val)
{
 var x, ch;
 var i=0;
 var newVal="";
 for(x=0; x <val.length ; x++){
  ch=val.substring(x,x+1);
  if(ch != "-")  newVal += ch;
 }
 return newVal;
}


//오늘 날짜열 만들기 - pansory
function BT_getToday() {
 var today = new Date();
 var yyyy, mm, dd;
 var Today;
 
 yyyy = today.getYear();
 mm = BT_make2Length(today.getMonth() + 1);
 dd = BT_make2Length(today.getDate());
 
 Today = yyyy.toString() + mm.toString() + dd.toString();
 
 return Today;
}


// 월일을 두자리로 만들기 - pansory
function BT_make2Length(val) {
 if(val < 10) {
  val = "0" + val;
 }
 return val;
}

//공백 없애기
function BT_TrimSpace(str) {
 var count = str.length;
 var len = count;                
 var st = 0;

 while ((st < len) && (str.charAt(st) <= ' ')) {
  st++;
 }
 while ((st < len) && (str.charAt(len - 1) <= ' ')) {
  len--;
 }                
 return ((st > 0) || (len < count)) ? str.substring(st, len) : str ;  
}

//공백 없애기
function BT_TrimSpace1(str) {
 var count = str.length;
 var len = count;                
 var st = 0;
 
 while ((st < len) && (toString(str.charAt(st)) <= toString(' '))) {
  st++;
 }
 while ((st < len) && (toString(str.charAt(len - 1)) <= toString(' '))) {
  len--;
 }       
 
 return ((st > 0) || (len < count)) ? str.substring(st, len) : str ;  
 
}

//session의 PAY_ACNTNO 와 ACNTNO(val) 값 비교
function BT_ComparePayAcntno(val) {
 
 var USR_AccsList = get_session("ACCS");
 var check = "";
 
 for (var i=0; i < USR_AccsList.length; i++) {
  if (USR_AccsList[i] == val) {
   check =  "1";
  }
 }
 return check;
}

// 금액 더하기 계산하기
function BT_calc(string,name)
{
 var sum = 0;
 BT_Del_comma(doc.form.REC_AMT);

 if (eval(string) == 0 ) {
  doc.form.REC_AMT.value = "";
 }
 else {
  sum = doc.form.REC_AMT.value;
  if (sum == "") {
   sum = 0;
  }
  sum = eval(sum) + eval(string);
  doc.form.REC_AMT.value = sum;
 } 

 doc.form.REC_AMT.focus();
}

// 금액 더하기 계산하기
function BT_Card_calc(string,name)
{
 var sum = 0;
 BT_Del_comma(doc.form.SEV_AMT);

 if (eval(string) == 0 ) {
  doc.form.SEV_AMT.value = "";
 }
 else {
  sum = doc.form.SEV_AMT.value;
  if (sum == "") {
   sum = 0;
  }
  sum = eval(sum) + eval(string);
  doc.form.SEV_AMT.value = sum;
 } 

 doc.form.SEV_AMT.focus();
}

 

//이체 비밀번호 체크
function BT_isTrsfPass(val)
{
// 이체비밀번호는 4자리이어야 한다.(자리수 검사는 따로 해야 한다.)
// 영문자가 1개이상 포함되어야 하며, 영문자와 숫자의 조합만 허락한다.
 var len = val.length;
 var i;
 var alphanum = 0;
 
 for(i=0;i<len;i++) {
  if ( BT_isAlphabet(val.charAt(i)) )
   alphanum = alphanum + 1;
  else if ( isNaN(val.charAt(i)) )
   return false;
 }
 if ( alphanum > 0 )
  return true;
 else
  return false;
}

//알파벳인지 체크 - 이체비밀번호 체크와 세트
function BT_isAlphabet(val)
{
 var alphaStr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
 if ( alphaStr.indexOf(val) < 0 )
  return false;
 else
  return true;
}

//숫자만 있는지 체크
function BT_isNumber(val)
{
 var numberStr = "0123456789";
 
 if ( numberStr.indexOf(val) < 0 )
  return false;
 else
  return true;
}

function BT_number(val){

  if ((event.keyCode<48)||(event.keyCode>57 )){  
   if(event.keyCode != 8  ) // 백스페이스 제외
   {
    event.returnValue=false;
   }
  }
}


// 금액 입력시 "," 자동 입력 & 우측 정렬
function BT_Add_comma(REC_AMT)
{    

 if(!BT_isAllNumber(REC_AMT.value))
 {
  alert("금액을 숫자로 입력해 주세요.");
  REC_AMT.value = "";
  REC_AMT.focus();
  return false;
 }
 var src
     var i;
 var factor;
 var su;
 var Spacesize = 0;

 factor = REC_AMT.value.length % 3;
 su = (REC_AMT.value.length - factor) /3;
    src = REC_AMT.value.substring(0,factor);

   for(i=0; i<su ; i++)
 {
    if ((factor==0)&&(i==0))// " XXX "인 경우
  {
    src += REC_AMT.value.substring(factor+(3*i), factor+3+(3*i));
  }
  else
  {
   src +=",";
   src += REC_AMT.value.substring(factor+(3*i), factor+3+(3*i));
        }
    }
  REC_AMT.value=src;
  return true;
}

function BT_Add_NumberComma(val) {
 var Ret_val = BT_StrToInt(val);
 Ret_val = BT_Add_Displaycomma(Ret_val);
 
 return Ret_val;
}

function BT_Add_NumberComma1(val) {
 var Ret_val = BT_StrToInt(val);
 var Zerodel = Ret_val;
 if (Zerodel == "0")
  Ret_val = "";
  
 else
  Ret_val = BT_Add_Displaycomma(Ret_val);
 
 return Ret_val;
}

function BT_Add_Number(val) {
 var Ret_val = BT_StrToInt(val); 
 return Ret_val;
}
function BT_Add_Displaycomma(val) {

 var src;
    var i;
 var factor;
 var su;
 var Spacesize = 0;
 
 var String_val = val.toString();
 
 factor = String_val.length % 3;
 su = (String_val.length - factor) /3;
    src = String_val.substring(0,factor);

   for(i=0; i<su ; i++)
 {
    if ((factor==0)&&(i==0))// " XXX "인 경우
  {
    src += String_val.substring(factor+(3*i), factor+3+(3*i));
  }
  else
  {
   if ( String_val.substring(factor+(3*i) - 1, factor+(3*i)) != "-" ) src +=",";
   src += String_val.substring(factor+(3*i), factor+3+(3*i));
        }
    }
  return src;
}

function BT_Add_Card_comma(SEV_AMT)
{

 if(!BT_isAllNumber(form.SEV_AMT.value))
 {
  alert("금액을 숫자로 입력해 주세요.");
  form.SEV_AMT.value = "";
  form.SEV_AMT.focus();
  return false;
 }
 var src
     var i;
 var factor;
 var su;
 var Spacesize = 0;

 factor = SEV_AMT.value.length % 3;
 su = (SEV_AMT.value.length - factor) /3;
    src = SEV_AMT.value.substring(0,factor);

   for(i=0; i<su ; i++)
 {
    if ((factor==0)&&(i==0))// " XXX "인 경우
  {
    src += SEV_AMT.value.substring(factor+(3*i), factor+3+(3*i));
  }
  else
  {
   src +=",";
   src += SEV_AMT.value.substring(factor+(3*i), factor+3+(3*i));
        }
    }
  SEV_AMT.value=src;
  return true;
}

//전체 값이 숫자로만 되어 있는지 체크
function BT_isAllNumber(val)
{
 var len = val.length;
 var i=0;
 
 for(i=0;i<len;i++) {
  if ( isNaN(val.charAt(i)) ) return false;
 }
 return true;
}

// 컴마(",") 자동 삭제
function BT_Del_comma(REC_AMT)
{
 REC_AMT.value = BT_Reduce_comma(REC_AMT.value);
 return true;
}

// 컴마(",") 자동 삭제
function BT_Del_Card_comma(SEV_AMT)
{
 SEV_AMT.value = BT_Reduce_comma(SEV_AMT.value);
 return true;
}

function BT_Reduce_comma(account_number)
{
 var x, ch;
 var i=0;
 var newVal="";
 for(x=0; x <account_number.length ; x++){
  ch=account_number.substring(x,x+1);
  if(ch != ",")  newVal += ch;
 }
 return newVal;
}

function BTCom_Replace(originalString, findText, replaceText){

 var pos = 0
 var preStr = ""
 var postStr = ""

 pos = originalString.indexOf(findText)
 
 while (pos != -1) {
  preString = originalString.substr(0,pos)
  postString = originalString.substring(pos+findText.length)
  originalString = preString + replaceText + postString
  pos = originalString.indexOf(findText)
 }
 
 return originalString
}

function BT_getRandomNumber() { //씨크릿 카드 순차번호 생성
 k=Math.round(Math.random()*30)
 if(k == 0) k = k + 1
 var L_Number = BT_make2Length(k);
 return L_Number;
}


//9자리 고객번호에 하이픈 넣기 - pansory
function BT_makeCustnoDash (val) {
 DashedCustno = val.substring(0,3) + "-" + val.substring(3,9);
 return DashedCustno;
}

//주민번호에 하이픈 넣기
function BT_makeResnoDash (val) {
 if (val.length == 10) { //기업의 경우
  DashedResno = val.substring(0,3) + "-" + val.substring(3,5) + "-" + val.substring(5);
 } else { //개인의 경우
  if (val.substring(0,3) == "000"){
   DashedResno = val.substring(3,6) + "-" + val.substring(6,8) + "-" + val.substring(8,13);
  } else {
   DashedResno = val.substring(0,6) + "-" + val.substring(6,13);
  }
  
 }
 return DashedResno;
}


//카드번호에 하이픈 넣기 - pansory
function BT_makeCardnoDash (val) {
  DashedAcntno = val.substring(0,4) + "-" + val.substring(4,8) + "-" + val.substring(8,12) + "-" + val.substring(12,16);
 return DashedAcntno;
}

//회원번호(16자리)에 하이픈 넣기 - pansory
function BT_makeMembernoDash (val) {
  DashedAcntno = val.substring(0,4) + "-" + val.substring(4,8) + "-" + val.substring(8,12) + "-" + val.substring(12,16);
 return DashedAcntno;
}

//카드번호 Array를 셀렉트 박스로 변환 - pansory
function BT_MakeCardList(val, selectedval) {
 
 var L_ListText = "<select name=\"ACNTNO\" id=\"ACNTNO\">";

 for(var i=0; i< val.length; i++)  {
  if (val[i] == selectedval) {
   L_ListText += "\t<option value=\"" + val[i] + "\" selected>" + BT_makeCardnoDash(val[i]) + "</option>\n";
  } else {
   L_ListText += "\t<option value=\"" + val[i] + "\">" + BT_makeCardnoDash(val[i]) + "</option>\n";
  }
  
 }
 
 L_ListText += "</select>\n";

 return L_ListText;
}

//카드번호 Array를 셀렉트 박스로 변환 - pansory
function BT_makeCardnoList(val) {
 
 var L_ListText = "<select name=\"CARD_NO\" id=\"CARD_NO\">";

 for(var i=0; i< val.length; i++)  {
  if (i == 0) {
   L_ListText += "\t<option value=\"" + val[i] + "\" selected>" + BT_makeCardnoDash(val[i]) + "</option>\n";
  } else {
   L_ListText += "\t<option value=\"" + val[i] + "\">" + BT_makeCardnoDash(val[i]) + "</option>\n";
  }
  
 }
 
 L_ListText += "</select>\n";

 return L_ListText;
}

//카드번호 선택..
function BT_SelectCardno(USR_AccsList, NeedCardno) {
 
 var no = NeedCardno.length;
 var Cardno_No = USR_AccsList.length;
 var SelectedCardno = new Array();
 var k = 0;

 if (no == 0) {
  SelectedCardno = USR_AccsList;
  //나중에 확인 필요함.. 고른 것들 중에 첫번째 것을 세션에 넣기..????  
  save_session("CARD_NO", USR_AccsList[0]);
  save_flush();
  
 } else {
  for (var i=0; i < Cardno_No ; i++) {
   
   for(var j=0 ; j < no; j++) {
    
     if(USR_AccsList[i].length > 12) {
      stCode = USR_AccsList[i].substring( 9, 11);
      
     } else {
      stCode = "0"; //Case Error
     }
     
     if (stCode == NeedAcntno[j]) {
      SelectedCardno[k] = USR_AccsList[i];
      
      if (k == "0") {
       //나중에 확인 필요함.. 고른 것들 중에 첫번째 것을 세션에 넣기..????  
       save_session("CARD_NO", USR_AccsList[i]);
       save_flush();
      }
      k++;
     }
   }
  }
 }
 return SelectedCardno;
}

function BT_makeLoannoDash (val) {
  DashedLoanno = val.substring(0,3) + "-" + val.substring(3,9) + "-" + val.substring(9,11) + "-" + val.substring(11,16)
 return DashedLoanno;
}

function BT_makeDateDash (val) {
  if (val == "00000000")
   DashedDate = "";
  else
   DashedDate = val.substring(0,4) + "-" + val.substring(4,6) + "-" + val.substring(6,8);
   
 return DashedDate;
}

function BT_makeDateDash_1 (val) {
  if (val == "000000")
   DashedDate_1 = "";
  else
   DashedDate_1 = val.substring(0,4) + "-" + val.substring(4,6);
   
 return DashedDate_1;
}
function BT_makeDateDash_2 (val) {
  if (val == "00000")
   DashedDate_2 = "";
  else
   DashedDate_2 = val.substring(0,2) + "-" + val.substring(2);
   
 return DashedDate_2;
}

function BT_makeDateDash_3 (val) {
  if (val == "00000000")
   DashedDate_3 = "";
  else
   DashedDate_3 = val.substring(6,8);
   
 return DashedDate_3;
}

function BT_makeDateSlash (val) {
  if (val == "00000000")
   DashedDate_1 = "";
  else
   DashedDate_1 = val.substring(0,4) + "/" + val.substring(4,6);
   
 return DashedDate_1;
}

function BT_makeTime (val) {
  ReturnTime = val.substring(0,2) + ":" + val.substring(2,4) + ":" + val.substring(4,6);
 return ReturnTime;
}

//문자열을 10진수로 변환
function BT_StrToInt(val) {
 var Re_int = 0
 
 if (val != "")
  var Re_int = parseInt(val,10);
 else
  Re_int = 0;
 
 return Re_int;
}

 

function BT_makeDecimalPoint(val) {
 var ReturnVal = val.split(".");
 ReturnVal = BT_Add_NumberComma(ReturnVal[0]) + "." + ReturnVal[1];
 return ReturnVal;
 
}


//페이지 설정
function last_page(val){
 var last_page = val%10;
 var index = parseInt(val/10);

 if (last_page > 0){
  return(index+1);
 }else
  return(index);


//소수점이하 자리수 설정
function BT_makeCipherPoint(val,cipher)
{
 
 var PreCipher = val.length - cipher;

 var Preval = val.substring(0,PreCipher);
 var Nextval = val.substring(PreCipher);
 var Returnval = Preval + "." + Nextval;

 return Returnval
}

//숫자와 영어만 허용
function BT_EngNum(obj,isUP){

 //if (event.keyCode == 9 || event.keyCode == 37 || event.keyCode == 39) return;//에러 발생 수정함.
 var returnValue = "";
 for (var i = 0; i < obj.value.length; i++){
  if ((obj.value.charAt(i) >= "0" && obj.value.charAt(i) <= "9") || (obj.value.charAt(i) >= "a" &&  obj.value.charAt(i) <= "z") || (obj.value.charAt(i) >= "A" && obj.value.charAt(i) <= "Z") ){
   returnValue += obj.value.charAt(i);
  }else{
   returnValue += "";
  }
 }

 obj.value = returnValue;
 obj.focus();
}


//날짜 계산 -- jjung
function BT_getDate(Dnum, gubun, StaYer,StaMon,StaDay,EndYer,EndMon,EndDay){
 var cur_year, cur_month, cur_day, cur_hour, cur_min, cur_sec, d_cur_date
 var index=0;
 var Mnum=0;

 var theDate = btGetCurrTime(2,1);
 var now = new Date();
 var daynum = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
 var monname = new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');

 if(theDate == ""){
     cur_year= now.getYear();
  cur_month =  now.getMonth() + 1;
  cur_month = new String(cur_month);
  cur_day = new String(now.getDate());
  cur_hour = theDate.substring(8,10);
  cur_min = theDate.substring(10,12);
  cur_sec = theDate.substring(12);
 } 
    else {
  cur_year = theDate.substring(0,4);
  cur_month = theDate.substring(4,6);
  cur_day = theDate.substring(6,8);
  cur_hour = theDate.substring(8,10);
  cur_min = theDate.substring(10,12);
  cur_sec = theDate.substring(12,14);
 }
   
 daynum[1] = cday(cur_year);
    change_month = monname[BT_StrToInt(cur_month) - 1];
 tmpDate = new String(change_month + cur_day + "," + cur_year + " " + cur_hour + ":" + cur_min + ":" + cur_sec );
 d_cur_date = new Date(tmpDate);

 if(gubun == "mon"){
  tmpMonth = BT_StrToInt(cur_month) + Dnum;
  if (tmpMonth == 0)
  {
   tmpMonth = "12";
   change_month = monname[BT_StrToInt(tmpMonth) - 1];
   tmpDate = new String(change_month + cur_day + "," + (cur_year - 1) + " " + cur_hour + ":" + cur_min + ":" + cur_sec );
  }
  else if (tmpMonth == -1)
  {
   tmpMonth = "11";
   change_month = monname[BT_StrToInt(tmpMonth) - 1];
   tmpDate = new String(change_month + cur_day + "," + (cur_year - 1) + " " + cur_hour + ":" + cur_min + ":" + cur_sec );
  }
  else {
   change_month = monname[BT_StrToInt(tmpMonth) - 1];
   tmpDate = new String(change_month + cur_day + "," + cur_year + " " + cur_hour + ":" + cur_min + ":" + cur_sec );
  }
  before_date = new Date(tmpDate);
 }else{
  var before_date = new Date(Date.parse(d_cur_date) + BT_StrToInt(Dnum)*1000*60*60*24);
 }

 if(theDate.length==0) {   
  var before_year = new String(before_date.getYear());
  var before_month = new String(before_date.getMonth() + 1);

 }else {
  var before_year = new String(before_date.getYear());
  var before_month = new String(before_date.getMonth() + 1);
 } 

 if(before_month.length==1){
  before_month = '0'+before_month;
 }
 var before_day = new String(before_date.getDate());

 if(before_day.length==1){
  before_day = '0'+before_day;
 }
 if(StaYer != "") eval("doc."+StaYer+".value=before_year");
 if(StaMon != "") eval("doc."+StaMon+".value=before_month");
 if(StaDay != "") eval("doc."+StaDay+".value=before_day");
 
 if(EndYer != "") eval("doc."+EndYer+".value=before_year");
 if(EndMon != "") eval("doc."+EndMon+".value=before_month");
 if(EndDay != "") eval("doc."+EndDay+".value=before_day");

 if(StaYer == "" && StaMon == "" && StaDay == "" && EndYer == "" && EndMon == "" &&  EndDay == "") return before_year + before_month + before_day;

}

//val : 전체 값, point : 소수점 앞에 자리수
function BT_toMoneyF(val,point,gubun){
 var foreVal = 0;
 var downVale = 0;
 if (BT_TrimSpace(val) == ""){
  return foreVal;
 } else {
  if(point == "" || point == "0") {
   foreVal = val;
   downVal = "";
  } else {
   if(gubun == "1"){
    foreVal = val.substring(0,point);
   } else{
    foreVal = BT_Add_NumberComma(val.substring(0,point));
   }
   downVal = val.substring(point);
  }
  return foreVal + "." + downVal;
 }
}


function BT_SetServiceCode(code){
 save_session("SERVICE_CODE",code);    
 save_flush();     
}

function BT_Setreturn_url(val){
 save_session("RETURN_URL",val);    
 save_flush();     
}

//2년 윤년처리
function cday(year)
{
 //2월달일때 윤년 처리
 if ((year % 4) == 0) { //윤년
  if ((year % 100) == 0) { //평년
   if ((year % 400) == 0) { //윤년
    daynum = 29;
   }
   else {//평년
    daynum = 28;
   }
  }
  else { //윤년
   daynum = 29;
  }
 }
 else {//평년
  daynum = 28;
 }
 return daynum;
}

/**
* 입력한 숫자 및 영문(조합도 상관없음)이 비밀번호로 사용 가능한지 다음과 같은 제한사항을
* 검사하는 메소드
* 1. 숫자의 경우 하나의 숫자 조합
* 2. 숫자의 경우 오름차순 및 내림차순
* 3. 영문의 경우 하나의 영문 조합(대소문자는 다른 문자로 인식함)
* 4. 영문의 경우 오름차순 및 내림차순
* @obj 입력폼의 object
* @return true : 비밀번호로 사용가능
* @return false : 비밀번호로 사용할 수 없음. 각 상황에 맞는 메시지가 내장되어 있음.
*/
function pwCheck(obj)
{
 var val = obj.value;
 var flag = false;

 for(i=0;i<val.length;i++)
 {
  if(!BT_isNumber(val.charAt(i)))//숫자 체크
  {
   flag = true;
   break;
  }
 }

 if(flag)//숫자와 영문 혼합 or 영문 조합으로 예상됨
 {
  for(i=0;i<val.length;i++)
  {
   if(!BT_isAlphabet(val.charAt(i)))//영문 체크
   {
    flag = false;
    break;
   }
  }

  if(flag)//*** 영문으로만 조합 연번 체크 요구됨 ***
  {
   if(check_alpha_all_dup(val))//*** 같은 영문자만의 조합 검사 ***
   {
    alert("입력하신 비밀번호가 모두 같은 영문입니다.");
    return false;
   }
   else//*** 오름 차순 및 내림 차순 검사 ***
   {
    if(check_alpha_asc(val))//*** 오름차순 검사 ***
    {
     alert("입력하신 비밀번호가 영문 오름차순입니다.");
     return false;
    }
    else//*** 내림차순 검사 ***
    {
     if(check_alpha_desc(val))
     {
      alert("입력하신 비밀번호가 영문 내림차순입니다.");
      return false;
     }
     else//*** 비밀번호로 사용가능 ***
     {
      return true;
     }
    }
   }
  }
  else//*** 영문 및 숫자 조합 - 비밀번호로 상용가능 ***
  {
   return true;
  }
 }
 else//*** 숫자로만 조합되었으므로 연번 체크 요구됨 ****
 {
  if(check_digit_all_dup(val))//*** 같은 숫자만의 조합 검사 ***
  {
   alert("입력하신 비밀번호가 모두 같은 숫자입니다.");
   return false;
  }
  else//*** 오름 차순 및 내림 차순 검사 ***
  {
   if(check_digit_asc(val))//*** 오름차순 검사 ***
   {
    alert("입력하신 비밀번호가 오름차순입니다.");
    return false;
   }
   else//*** 내림차순 검사 ***
   {
    if(check_digit_desc(val))
    {
     alert("입력하신 비밀번호가 내림차순입니다.");
     return false;
    }
    else//*** 비밀번호로 사용가능 ***
    {
     return true;
    }
   }
  }
 }
}


/**
* 숫자로만 구성된 문자열이 내림차순의 숫자들인지 확인
* @return true : 내림차순이다.
* @return false : 내림차순이 아니다.
*/
function check_digit_desc(val)
{
 var init_cnt = 0;
 var flag = true;

 for(i=0;i<numberArray.length;i++)
 {
  if(val.charAt(0) == numberArray[i])
  {
   init_cnt = i;
   break;
  }
 }

 var init_cnt_tmp = init_cnt;
 for(i=0;i<val.length;i++)
 {
  if(val.charAt(i) == numberArray[init_cnt_tmp])
  {
  }
  else
  {
   flag = false;
   break;
  }
  
  init_cnt_tmp -= 1;
  if(init_cnt_tmp == -1)
  {
   init_cnt_tmp = numberArray.length - 1;
  }
 }

 return flag;
}

/**
* 영문으로만 구성된 문자열이 내림차순인지 확인
* @return true : 내림차순이다.
* @return false : 내림차순이 아니다.
*/
function check_alpha_desc(val)
{
 var init_cnt = 0;
 var flag = true;

 for(i=0;i<alphaArray.length;i++)
 {
  if(val.charAt(0) == alphaArray[i])
  {
   init_cnt = i;
   break;
  }
 }

 var init_cnt_tmp = init_cnt;
 for(i=0;i<val.length;i++)
 {
  if(val.charAt(i) == alphaArray[init_cnt_tmp])
  {
  }
  else
  {
   flag = false;
   break;
  }
  
  init_cnt_tmp -= 1;
  if(init_cnt_tmp == -1)
  {
   init_cnt_tmp = alphaArray.length - 1;
  }
 }

 return flag;
}


/**
* 숫자로만 구성된 문자열이 오름차순의 숫자들인지 확인
* @return true : 오름차순이다.
* @return false : 오름차순이 아니다.
*/
function check_digit_asc(val)
{
 var init_cnt = 0;
 var flag = true;

 for(i=0;i<numberArray.length;i++)
 {
  if(val.charAt(0) == numberArray[i])
  {
   init_cnt = i;
   break;
  }
 }

 var init_cnt_tmp = init_cnt;
 for(i=0;i<val.length;i++)
 {
  if(val.charAt(i) == numberArray[init_cnt_tmp])
  {
  }
  else
  {
   flag = false;
   break;
  }
  
  init_cnt_tmp += 1;
  if(init_cnt_tmp == numberArray.length)
  {
   init_cnt_tmp = 0;
  }
 }

 return flag;
}

/**
* 영문으로만 구성된 문자열이 오름차순 인지 확인
* @return true : 오름차순이다.
* @return false : 오름차순이 아니다.
*/
function check_alpha_asc(val)
{
 var init_cnt = 0;
 var flag = true;

 for(i=0;i<alphaArray.length;i++)
 {
  if(val.charAt(0) == alphaArray[i])
  {
   init_cnt = i;
   break;
  }
 }

 var init_cnt_tmp = init_cnt;
 for(i=0;i<val.length;i++)
 {
  if(val.charAt(i) == alphaArray[init_cnt_tmp])
  {
  }
  else
  {
   flag = false;
   break;
  }
  
  init_cnt_tmp += 1;
  if(init_cnt_tmp == alphaArray.length)
  {
   init_cnt_tmp = 0;
  }
 }

 return flag;
}

/**
* 숫자로만 구성된 문자열이 같은 숫자로 조합되었는지 확인
* @return true : 동일한 값으로 조합. 비밀번호로 사용하면 안됨.
* @return false : 다른 숫자가 적어도 하나 존재. 비밀번호로 사용해도 괜찮음.
*/
function check_digit_all_dup(val)
{
 var flag = true;

 for(i=0;i<numberArray.length;i++)
 {
  flag = true;

  for(j=0;j<val.length;j++)
  {
   if(val.charAt(j) == numberArray[i])
   {
   }
   else
   {
    flag = false;
    break;
   }
  }

  if(flag)
  {
   break;
  }
  else
  {
   continue;
  }
 }

 return flag;
}

/**
* 영문으로만 구성된 문자열이 같은 영문으로 조합되었는지 확인
* @return true : 동일한 영문으로 조합. 비밀번호로 사용하면 안됨.
* @return false : 다른 영문이 적어도 하나 존재. 비밀번호로 사용해도 괜찮음.
*/
function check_alpha_all_dup(val)
{
 var flag = true;

 for(i=0;i<alphaArray.length;i++)
 {
  flag = true;

  for(j=0;j<val.length;j++)
  {
   if(val.charAt(j) == alphaArray[i])
   {
   }
   else
   {
    flag = false;
    break;
   }
  }

  if(flag)
  {
   break;
  }
  else
  {
   continue;
  }
 }

 return flag;
}

 

and
 
and

BOOLCDialog::OnInitDialog()
{
      CDialog::OnInitDialog();
      ModifyStyleEx( WS_EX_APPWINDOW,WS_EX_TOOLWINDOW,0 );
      returnTRUE
}

and

BOOL CWinApp::InitInstance()
{
    // Mutex 생성
    HANDLE hMutexOneInstance =  ::CreateMutex(NULL, TRUE, _T("Unique Name of Mutex"));

    BOOL bFound = FALSE;
    // 만약 이미 만들어져 있다면 Instance가 이미 존재함
    if (::GetLastError() == ERROR_ALREADY_EXISTS)
        bFound = TRUE;


    if ( hMutexOneInstance )
        ::ReleaseMutex(hMutexOneInstance);
 
    // 이미 하나의 Instance가 존재하면 프로그램 종료
    if(bFound) {
        AfxMessageBox("이미 실행중입니다");
        return FALSE;
    }
 
         ........

}

 

and

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

[강좌] 기초적인 압축 알고리즘 하이텔 퍼옴..

_____________________________________________________________________

 RLE / RLE+ / FAX / FAX+ / Lempel-Zip 방식압축기법

---------------------------------------------------------------------

 

 !!***********************************************************!!

 

< RLE (Run Length Encoding) 방식 >

 

 가장 쉽지만 모든것이 그렇듯 가장 압출률이 저조한 방법입니다.

 

 화일을 16 진수로 나타낸 코드를 읽어서 다음과 같은 예가 있다면

 

 

   <데이터>

   00 00 1C 1C 1C F3 F3 F3 F3 F3 D8 11 11 11 11 11

 

   

 위의 자료는 16byte의 자료입니다.

 

 RLE 방식으로 압축을 하면 다음과 같이 나타낼수 있습니다.

 

 

   <RLE 압축>

   00 02 1C 03 F3 05 D8 01 11 05

 

   

 대상코드와 그 코드의 갯수를 나란히 적은 것임을 알수 있습니다.

 

 이방법은 일반적으로 독립적으로 쓰이기보다는 여러가지 기법과 혼용되어

 

 쓰이는 방법입니다. 또한 연속된 자료가 자주 나타나는 그림화일등에서

 

 압축률을 높일수 있습니다. 다른 일반 자료는 오히려 압축한것이

 

 더큰 역효과를 가져옵니다. 이유는 자료코드 하나와 갯수코드 하나씩해서

 

 최악의 경우는(연속된자료가 전혀없는경우) 꼭 원본보다 두배의 자료가

 

 되기 때문이죠.

 

-----------------------------------------------------------------------

< RLE 보완형 >

 

 RLE의 단점은 연속되지 않은 자료의 압축시에 오히려 그 압축화일의 용량

 

 이 더욱 커진다는 것이었습니다. 그러나 일부 그림자료등을 제외하면

 

 대부분의 자료들은 같은 코드의 반복은 그리 눈에 띄지 않습니다...

 

 여기서 보일 방법은 RLE의 갯수를 세는 부분을 달리 하는 것입니다.

 

 기존에 01 02 03 ...처럼 숫자를 썼던 것 대신 C0 C1 C2 ...등으로 바꾸어

 

 쓰는 것입니다. 이 방법은 글쎄요. RLE 방법과 그다지 별차이가 없어

 

 보이지만 코딩시에 새로운 규칙을 첨가함으로써 변화를 도모합니다.

 

 그 규칙이라 함은 갯수를 설정하면 코드의 갯수가 바뀌지 않는이상 다시

 

 설정하지 않는다는 것입니다. (이해가 가실까.....그렇다면 예제를..)

 

 

   <데이터>

   F9 03 5D E3 21 00 EE 45 33 76 DE 3D 2F F4 5C B2

   

 

 위와 같은 16byte 데이터의 RLE 보완형으로 압축하면 다음과 같습니다.

 

 

   <RLE 보완압축>

   C0 F9 03 5D E3 21 00 EE 45 33 76 DE 3D 2F F4 5C B2

 

   

 17byte 로 원본보다 1byte나 손해를 보았습니다. 그러나 RLE 보다는

 

 훨씬 좋은 방법임을 알수 있습니다.

 

 위의 예는 전혀 연속되는 자료가 없었다는 겁니다. 그러나 다음의 예와

 

 같이 연속되는 자료가 존재하면 이야기는 달라집니다.

 

 

   <데이터>

   03 03 03 03 5F E3 21 00 EE 45 33 76 DE 3D 2F F4 5C

 

   <RLE 보완압축>

   C3 03 C0 5F E3 21 00 EE 45 33 76 DE 3D 2F F4 5C

 

 

 자 1byte의 압축 효과를 가져왔습니다.

 

 하지만 혹자는 여기서 이런 의문을 갖을수도 있겠습니다. 만일 데이터상에

 

 C0...CF 의 자료가 존재하면 어떻게 하는가....만일 다음과 같은 자료가

 

 있다면 예 치고는 너무 속보이는 예제입니다만....헐~

 

 

   <데이터>

   C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF

 

 

   <RLE 보완압축?>

   C0 C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF

 

 

 위의 압축된것이 맞을까요?  흐흐......절대 아니죠....위의 것을 다시 풀어

 

 쓴다고 생각하면 전혀 다른 해석이 생기게 됩니다.

 

 지금까지 쓴 RLE 보완형의 규칙을 보면 갯수는 C0...CF로적되 첨음에는 갯수

 

 다음에 코드순이었습니다....따라서 압축된것을 거기에 준하여 해석하면

 

 C0 C0 는 C0가 1개로 해석되지만 다음부터는 문제가 생기죠...C1 C2 에서는

 

 엉뚱하게도 C2 라는 코드가 2개인것으로 해석된다는 맹점입니다.

 

 따라서 이런경우를 위한 한가지의 규칙이 더 필요하게 됩니다.

 

 * 만일 데이커상에 C0...CF 의 자료가 있으경우 그부분에 대해서 특별히

   기존의 RLE 방법으로 압축한다. 갯수를 적을때는 역

 C0...CF 코드를 이용

   한다.

 

 이해를 돕기위한 예제는 다음과 같습니다.

 

   

   <데이터>

   34 DE C3 C3 C3 F4 F4 F4 DE C0 36 8D B1 A0 00 01

   

 

 

 위와 같은 16byte의 자료를 압축합니다. 압축시 주의할사항으로는 C# 코드발견

 

 시 RLE로 압축하고( 갯수 + 코드 쌍형태) 다시 RLE 보완형을 시작하는 것입니다

 

 즉, 앞에 압축한것과 별도의 압축을 한다고 생각하고 다시 C# 형태의 갯수를 쓰

 

 는것부터 하는거죠....압축된것을 보면 다음과 같습니다.(~~ 친부분 주의할곳)

                                       

 

   <RLE 보완압축>

   C0 34 DE C2 C3 C2 F4 C0 DE C0 C0 C0 36 8D B1 A0 00 01

                  ~~                ~~

   

 처음부터 차근차근 살펴보겠습니다.

   

 먼저 C0의 의미는 34 DE 라는 데이터가 한개씩 있다는 뜻입니다.

   

 C2 C3 는 C3 데이터가 3개 있다는 이야기입니다.

   

 C2 F4 는 F4 데이터가 3개있다는 의미인데...문제는 이전에 쓰인 C2 의 의미가

 

 뒤에나오는 C3 C2 F4 까지 모두 3개씩이 아닌가 하는 해석의 오류를 나을수 있

 

 다는 것입니다. 그러나 압축에서 규칙을 정한것처럼 C0...CF 자료가 둘이상 존재

   

 할때는 이것이 특수한 규칙에 의해서 압축된 RLE 방식이라는 것을 잊어서는 안

 

 됩니다...따라서 압축을 풀때에도 C0...CF 코드가 나오면 두개씩 짝을지어 RLE

 

 방식으로 해석하고 풀어야 한다는 이야기입니다. 둘씩 짝을 지어 해석한후 다시

 

 나오는 C2 는 다음에 나오는 자료가 C# 형태가 아니기 때문에 보완형으로 압축된

 

 것임을 알수 있습니다...그래서 F4가 3개 연속이라는 뜻이죠...다음에 연속되는

 

 C0의 해석에서는 C#형태가 연속되므로 이것은 RLE 방식의 압축입니다. 따라서 첫

 

 C0는 갯수 다음은 코드...해서 C0 가 하나있다는 의미이구요...(역시 2개씩 짝을

 

 짓죠...RLE 방식은 두개씩의 짝을 만들어 냅니다...) 다음에 나오는 C0는 38 8D

 

 B1 A0 00 01 이라는 코드가 모두 하나씩 존재한다는 의미입니다.

 

 역시 다음코드인 DE 가 1개라는 의미죠...조금은 복잡한듯 싶지만 그 규칙을 완

 

 전히 이해한다면 별루 어려울것은 없습니다.

 

 실전을 위해 압축된 자료의 원본을 만들어보는 연습을 하겠습니다.

 

 

   <RLE 보완압축 자료>

   C0 34 DE C2 C3 C2 F4 C0 DE C0 C0 C0 36 8D B1 A0 00 01

 

 

 C0 34 DE 가지는 34 DE 가 하나씩 있다는 의미입니다. 다음에 나온 C2 C3 C2...

 

 C#의 형태가 연속해있으므로 두개씩 묶어서 생각합니다. C2 C3 는 RLE 압축이

 

 니까...C3 라는 데이터가 3개라는 의미겠죠...다음...C2는 다시 RLE 보완형의

 

 첫부분이니까...갯수를 나타내고 다음에 나오는 F4라는 데이터의 갯수죠...

 

 따라서 F4 3개.....C0 DE 는 DE 가 1개 다음에 역시 연속되는 C0 중에...두개를

 

 취해서 C0가 1개있다는 의미이고....세번째 C0는 RLE 보완형 첫번째인 갯수 따라

 

 서 36 8D B1 A0 00 01 이 하나씩... 이상을 종합하면...

 

 

   <복원데이터>

   34 DE C3 C3 C3 F4 F4 F4 DE C0 36 8D B1 A0 00 01

   

 

 이 됩니다.....원래의 모습을 찾았죠?    이해가 가십니까?

 

 규칙에 충실하면 어려울것이 없습니다. RLE 방식은 가장 기초적인 방식으로 다른

 

 압축 기법을 공부하는데에 기본이 된다구나 할까요....

 

---------------------------------------------------------------------------

  

<FAX 압축>

 

 이 압축 방법은 현재 많이 쓰이는 사무기기인 팩시밀리에서 사용하는 압축 방식입

 

 니다. 압축률또한 위에서 언급된 RLE 계열의 방식보다 좋으며 RLE방식을 제외한

 

 기타다른 압축방식보다 구현하기가 쉬워서 맣이 사용되고 있습니다.

 

 간단히 설명하자면 이전까지 사용하던 16진 코드를 2진코드로 바꾸어 압축하는

 

 방식입니다. 다른 말로 비트맵이라는 표현을 쓰기도 합니다. 마우스의 커서등을

 

 구현할때 모눈종이에 그리던것 생각하시면 빠르겠네요..

 

 자 우선 아래와 같은 32byte의 데이터를 읽어들입니다.

 

 

   <데이터>

   00 00 0F F0 1F F8 1F F8   1F F8 0F F0 00 00 00 00

   0F F0 11 88 11 88 11 88   11 88 11 88 0F F0 00 00

   

 

 위의 데이터를 RLE 보완압축 방식으로 압축하면 다음과 같겠죠 (쩝 압축률

0%?)

 

 

   <RLE 보완압축>

   C1 00 C0 0F F0 1F F8 1F   F8 1F F8 0F F0 C3 00 C0

   0F F0 11 88 11 88 11 88   11 88 11 88 0F F0 C1 00

   

 

 비교를 위해서 RLE 방법을 쓰면 다음과 같습니다. (흐...팽창률 170%?)

 

 

   <RLE 압축>

   00 02 0F 01 F0 01 1F 01   F8 01 1F 01 F8 01 1F 01

   F8 01 0F 01 F0 01 00 04   0F 01 F0 01 11 01 88 01

   11 01 88 01 11 01 88 01   11 01 88 01 11 01 88 01

   0F 01 F0 01 00 02

 

   

 비교상으로도 RLE 보완형이 월등히 좋다는 것을 알수 있습니다....그럼 FAX 압축

 

 을 위해서 우선 비트맵으로 구성해보도록 하겠습니다.

 

 위의 데이터를 16 by 16 비트맵으로 나타내면 다음과 같습니다.(정사각형모양)

 

 

               <비트맵>        l   <16진>

                               l  

         0000 0000 0000 0000   l   00  00

         0000 1111 1111 0000   l   0F  F0

         0001 1111 1111 1000   l   1F  F8

         0001 1111 1111 1000   l   1F  F8

         0001 1111 1111 1000   l   1F  F8

         0000 1111 1111 0000   l   0F  F0

         0000 0000 0000 0000   l   00  00

         0000 0000 0000 0000   l   00  00

         0000 1111 1111 0000   l   0F  F0

         0001 0001 1000 1000   l   11  88

         0001 0001 1000 1000   l   11  88

         0001 0001 1000 1000   l   11  88

         0001 0001 1000 1000   l   11  88

         0001 0001 1000 1000   l   11  88

         0000 1111 1111 0000   l   0F  F0

         0000 0000 0000 0000   l   00  00

         

 

 먼저 일단계로 위의 비트맵에서 0이 많아지는 방향으로 데이터를 규칙있게

 

 변형시키는 것입니다. 먼저 기존의 0은 그대로 두고 0에서 1로 변화되는 부분과

 

 0 에서 1로 변화되는 부분에서마 1을 쓰는 방법이 있습니다.

 

 변형되 형태는 다음과 같은 모습이 될것입니다.

 

 

           <변형된 비트맵>

 

         0000 0000 0000 0000   

         0000 1000 0000 1000   

         0001 0000 0000 0100   

         0001 0000 0000 0100   

         0001 0000 0000 0100   

         0000 1000 0000 1000   

         0000 0000 0000 0000   

         0000 0000 0000 0000   

         0000 1000 0000 1000   

         0001 1001 0100 1100   

         0001 1001 0100 1100   

         0001 1001 0100 1100   

         0001 1001 0100 1100   

         0001 1001 0100 1100   

         0000 1000 1000 1000   

         0000 0000 0000 0000   

 

         

 

 위의 데이터는 예시를 위해 조작된 것이기 때문에 확실이 0숫자가 많이 포함

 

 되어있습니다. 그러나 일반적인 데이터는 이보다는 좋지 않은 결과가 나올경우가

 

 더 많다는 것을 알아두셔야 합니다. 또한 FAX 압축을 풀기위한 규칙으로 가장

 

 첫 비트가 1이면 그자리는 1로 표시해야합니다. 그렇지 않으면 나중에 압축

 

 을 풀어나갈때 곤란한 경우가 생기게 됩니다. 우선을 그렇게 알아두시면 됩니다.

 

 여기까지 끝이 나면 다음 단계로 넘어갑니다. 이번에는 데이터를 회전시킵니다.

 

 프로그램상으로 구현할때에는 위에서 아래로 데이터를 읽어서 왼쪽에서 오른쪽

 

 으로 써나가면 됩니다.(이유는 0을 많이 만들기 위함입니다)

 

 재변형된 데이터의 형태는 아래와 같습니다.

 

 

 

             재변형 비트맵      l  16진   l 헤더비트

         ---------------------------------------------

         0000 0000 l 0000 0000  l  00  00 l   00

         0000 0000 l 0000 0000  l  00  00 l   00  

         0000 0000 l 0000 0000  l  00  00 l   00  

         0011 1000 l 0111 1100  l  38  7C l   11

         0100 0100 l 1111 1110  l  44  FE l   11  

         0000 0000 l 0000 0000  l  00  00 l   00  

         0000 0000 l 0000 0000  l  00  00 l   00  

         0000 0000 l 0111 1100  l  00  7C l   01  

         ---------------------------------------------

         0000 0000 l 0000 0000  l  00  00 l   00  

         0000 0000 l 0111 1100  l  00 7C l   01  

         0000 0000 l 0000 0000  l  00  00 l   00  

         0000 0000 l 0000 0000  l  00  00 l   00  

         0100 0100 l 1111 1110  l  44  FE l   11  

         0011 1000 l 0111 1100  l  38  7C l   11  

         0000 0000 l 0000 0000  l  00  00 l   00  

         0000 0000 l 0000 0000  l  00  00 l   00  

 

 

 

 데이터를 입력하기위해서 우선 헤더비트를 쓴후 데이터를 입력하는 방식으로

 

 압축을 해나가는 것입니다. 여기서 헤더 비트란 것은 재변형된 비트맵상에서

 

 1byte를 취하여 그값이 0이면 0 그외의 숫자이면 1을 부여하여 일열로 나열

 

 한 일종의 암호데이터라고 할까요.(위에 세로줄로 나눈것은 byte 단위로 알아

 

 볼수 있도록 한것입니다) 위에 헤더비트를 적은 것을 보면 쉽게 그 의미를

 

 알수 있을 것입니다. 따라서 위의 데이터의 헤더비트는 다음과 같습니다.

 

 

   <헤더비트>

   0000 0011 1100 0001 0001 0000 1111 0000 : 03 C1 10 F0

 

   

 압축된 데이터는 이 헤더비트를 가장 먼저 적고 다음에 자료를 입력하는데

 

 단, 자료가 00일때는 적지 않습니다. 완성된 압축 데이터는 다음과 같습니다.

 

 

   <FAX 압축>

   03 C1 10 F0 38 7C 44 FE 7C 44 FE 38 7C

   ~~~~~~~~~~~

    헤더비트

    

       

 처음에 주어진 32 byte 데이터가 13 byte로 압축되었습니다. (압축률 약60%)

 

 사실 위의 예제는 16 by 16 비트맵을 사용했지만 8 by 8 비트맵을 4번 압축한

 

 것과도 같습니다...따라서 위의 예제를 8 by 8 비트맵으로 바꾸어 네번 같은

 

 계산을 반복해도 하나의 방법으로 생각할수 있습니다.

 

 문제는 얼마나 많은 데이터를 이용하는가와 계산상의 속도문제가 상호작용하

 

 게 되기 때문에 적정선에서 나누는것이 좋습니다. 보통 8 by 8 비트맵이나

 

 16 by 16 비트맵을 사용합니다.

 

 이 FAX 압축을 푸는 방법은 지금까지 해왔던 일련의 작업을 꺼꾸로 수행하는

 

 것입니다. 먼저 헤드를 읽어서...우선은 이 압축이 8 by 8 로 압축되었는지

 

 16 by 16 으로 압축되었는지 알아야 하는것은 당연한것이겠죠...압축한 방법

 

 으로 풀어야 풀리겠죠....어쨌든.. 헤드를 읽어서 데이터중에 00의위치와 0이

 

 아닌 데이터의위치를 파악한후 자료를 순서대로 읽어 해당위치에 넣고

 

 (여기까지는 재변형 비트맵) 회전된 것을 복구하기 위해서 데이터를 왼쪽에서

 

 오른쪽으로 읽어서 위에서 아래로 써 원래의 변형된 비트맵을 만듭니다.

 

 이제는 1과 0의 규칙에 따라서 원래의 자료로 복구를 하는 것입니다.

 

 여기서 앞에서 언급했던 첫비트의 1일때 문제는 이렇습니다. 만일 첫비트가

 

 11100 등으로 시작되었는데도....00010 등으로 쓰였을경우 복구할때...규칙에

 

 의해서 00010 은....00011 로 복구가 되죠....원하는 값이 아닙니다....따라서

 

 위의 경우...즉, 11100 으로 시작하는 데이터의 올바른 변형법은 10010 입니다.

 

 그래야 규칙에 의해서 11100으로 바뀔수가 있기 때문입니다.

 

 이점만 유의 한다면 FAX 압축도 별 어려운 것이 없을것이라고 생각합니다.

 

 참고적으로 말씀드리자면 FAX 방법에 있어서 어떤때에는 오히려 헤더부분때문에

 

 특히 16 by 16 비트맵 방식에서는 무려 4 byte 의 헤더가 이용되면서...압축률

 

 에 있어서 손해를 보게 되는 경우가 많습니다...그래서 보통은 8 by 8 비트맵

 

 의 형태를 사용하는데 그대신 많은 데이터를 한번에 읽어서 속도를 향상시키

 

 기도 합니다. 하지만 16 by 16 의 장점은 8 by 8 보다는 데이터의 압축률에 있

 

 어서 앞선다는 것입니다....그래서 나온것이 16 by 16 비트맵 방식에서...

 

 헤더의 크기를 2 byte 로 줄일수 있는 방법이 있다고 합니다.

 

 음...FAX 압축이 비록 팩시밀리에서 사용되는 방법이긴하지만 자료에 따라서는

 

 예를 들면 실행화일을 압축하는데 있어서는 결코 쓸모있는 것은 못됩니다.

 

 대부분의 경우....10% 내외의 압축률이나..마이너스 압축률이 나오기 쉽상

 

 이라는 점을 알아두시기 바랍니다.

 

---------------------------------------------------------------------------

 

<FAX 보완압축>

 

 보완형이란 다름아닌 위에서 잠시 언급한 헤더를 2byte 로 줄이는 방법입니다.

 

 구현 원리는 FAX 와 같지만 마지막에 헤더를 쓰고 자료를 적는 부분에서만

 

 차이를 보이는 것입니다. FAX 압축의 예제에서 보인것은 헤더를 만들때 8 bit

 

 를 기준으로 해서  03 C1 10 F0  라는 헤더를 얻어냈었습니다... 그러나 여기서

 

 

 는 16 bit 를 기준으로 해서 새로운 헤더를 만들어낼수 있습니다.

 

 즉, 위의 헤더비트의 예에서  

 

 

   <8bit 헤더비트의 예>

   00 00 00 11   11 00 00 01   00 01 00 00   11 11 00 00 : 03 C1 10 F0

 

 

 였던 헤더비트가 16 bit를 기준으로 하면

   

   

   <16bit 헤더비트로의 변형>

    0  0  0  1    1  0  0  1    0  1  0  0    1  1  0  0 : 19 4C

      

    

 으로 변화하게 됩니다. 즉, 헤더가 8bit 일때의 절반으로 감소함으로써 데이터의

 

 압축률이 다소 낮아지더라도 충분한 보상을 갖어오게 된다는 것입니다.

 

---------------------------------------------------------------------------

 

<Lempel-Zip 방식>           

 

 이 방식은 누구나 한번쯤은 생각했보았을만한 방법이면서 근래 많이 이용되는

 

 압축프로그램의 원형이라고 말할수 있는 방식입니다. 크랙용 프로그램인 크랙잭을

 

 보면 크랙을 위한 사전을 가지고 있는것을 볼수 있죠. 이와 비슷한 방식으로

 

 같다고 볼수는 없지만 그런 접근으로 압축을 하는 것이 이방법의 개요입니다.

 

 압축방법이라기 보다는 암호책을 대조하는 식으로 생각하면 이해가 빠를까요?

 

 최고의 효율을 가지고 있는 방식으로 현재 압축효율이 좋은 압축 프로그램들은

 

 모두 이 방식을 사용하거나 그 변형을 이용합니다. 이 방식의 실현은 상당히 어렵지

 

 만 간단하게 생각하면 사전과 같이 자주 사용되는 것을 일종의 테이블로 만들어

 

 압축하는 것입니다. 코드 필드와 서픽스로 나뉘어서 구성되는 테이블의 내용은

 

 다중 패스를 거쳐야 하는 복잡한 알고리즘을 가지고 있지만 여기서 간단히 개념만을

 

 파악한다면 다음과 같이 볼수 있습니다.

 

 

                  INDEX ENCODE 사전

                     ┌─────┐

                 ..  │ .....    │

                 ... │ .....    │

                 ... │ ....     │

                     ├─────┤

                 478 │   IS     │

 RAW DATA            ├─────┤

                 ... │  ....    │

 "THIS IS HOT ->     ├─────┤-> INDEX OUTPUT

  STUFF"         759 │  HOT     │  1295 478 759 3751

                     ├─────┤  (12954787593751)

                 ... │  ...          │

                     ├─────┤

              1295 │  THIS      │

                     ├─────┤

                .... │  ....         │

                     ├─────┤

              3751 │  STUFF     

                     ├─────┤

                .... │ ....          │

                     └─────┘

 

 INDEX ENCODE 사전이라는 것은 압축 프로그램이 규칙에의해 보유하고 있는

 

 일종의 사전이라고 보시면 됩니다. 각각에 번호나 약속된 기호들로 구성되어

 

 그 인덱스 하나가 하나의 단어내지는 기호를 나타내게 되는 것입니다.

 

 압축을 하기위해서는 해당하는 INDEX를 알아야만 가능하겠죠... 일일이 이런

 

 

 사전을 개인이 구축한다는 것은 그리 쉬운 일은 아닐것입니다. 많은 노력과

 

 시간이 들겠죠.. 파싱이라는 기법을 이용해서 인덱스를 자체 생산하는 방법

 

 이 있긴 합니다. 간단한 텍스트 압축기는 충분히 만들수 있을것이라고

 

 생각이 듭니다.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

and

class rrr
{
public:
 void setR(int r) { _rr = r;}
 int getR() {return _rr;}
 int _rr;
};

class mmm
{
public:
 mmm(rrr * rr) : _rr(rr) {}
 void setR(rrr * r) { _rr = r;}
 rrr * getR() {return _rr;}
 rrr * _rr;
};

class sss
{
public:
 sss() : _m(&_r) { _m.setR(&_r); }
 rrr & getR() {return _r;}
 mmm * getM() {return &_m;}
rrr _r;
mmm _m;
};


int main(int argc, char* argv[])
{

 rrr r1;
 sss s2;
 sss * s1 = &s2;

 s1->getR().setR(10);

 cout << s1->getR().getR() << endl;
 cout << s1->getM()->getR()->getR() << endl;

 s1->getR().setR(15);

 cout << s1->getR().getR() << endl;
 cout << s1->getM()->getR()->getR() << endl;


 s1->getM()->getR()->setR(20);

 cout << s1->getR().getR() << endl;
 cout << s1->getM()->getR()->getR() << endl;

 


 

심하게 깔끔해 보이진 않지만... 테스트겸 간략하게 짠 코드니까..ㅋㅋ

결과는뭐 당연하게 잘되지만...

왜 실제 코드에선 버그가 있는거지..

어디서 물고 있는게냐?

and

 오늘은 회사 창립기념일이어서 기분이 좋습니다.^^ 예전에 IOCP에 대해서 공부할려고 작성했던 문서를 찾았습니다. 한번 읽어보세요. 예전에 이 자료 만들때는 IOCP자료 찾기가 많이 힘들었는데 요즈음에는 구글에서 찾으면 좋은 자료가 너무 많아서 찾기가 힘들죠^^;;;

 

----------------------------------------------------------------------------------------

 

1.    목적

 Winsock2 IOCP를 분석한 것입니다. 이 문서는 크게 두 가지를 설명 하고 있습니다. 전자는 일반적인 IOCP에 대해서 설명합니다. 후자는 IOCP란 무엇이고 장단점은 무엇인지 입니다.

 

 2.IOCP란?

 

 


사용자 삽입 이미지

 

위에서 보는 것처럼IOCP의 기본적은 구성은두개의 쓰레드로 만들어 진다. 왼편에 있는 루프는 보통 main() 함수에서 있는 루프고 오른쪽에 있는 루프는 main함수가 루프를 들어가기 전에 생성해야 하는 쓰레드로 보통 Worker쓰레드라고 한다. 권장하는 Worker쓰레드의 수는 하나의 CPU당 두개로(Send/Recv) 되어 있다. 또한 2번에서 3번으로의 데이터 전송은 전역변수를 이용하거나 Worker쓰레드를 생성할 때, 포인터를 전송하여 두 루프가 변수를 공유하는 방법이다. 이에 대해서는 달리 자세히 설명하지는 않겠다.

 

(1)      Wait for client to connect

이 과정에 이전에 이미IOCP 핸들과 소켓 초기화, 클라이언트의 접속을 대기하는 소켓, 접속한 클라이언트들의 정보를 가지는 배열( 물론, 자료구조는 자신의 선택이다. )을 생성해 두어야 한다.여기는 클라이언트의 접속을 대기하는 소켓에 Accept()를 호출하여 클라이언트가 접속하기를 기다리는 과정이다.

 

(2)      Open communication channel for client

1번 과정에서 클라이언트가 접속을 하면 여기서는 올바른 소켓인지 판단하고, 접속한 소켓을 클라이언트 정보를 저장하는 배열에 저장하고, IOCP에 해당 소켓을 등록하고, 소켓에 읽기 작업을 신청한다. ( 읽기를 먼저 신청하는 이유는 대해서는 설명하지 않겠다. ) 이 때 중요한 것은 현재 WSARecv(), ReadFile()함수를 사용하여 읽기 작업을 신청했지만, IOCP는 작업의 완료 시에 읽기 작업을 끝냈는지 쓰기 작업을 끝냈는지 가르쳐 주지 않는다는 것이다. 따라서,OVERLAPPED구조체를 상속( C관점에서는 새로운 구조체를 선언할 때, OVERLAPPED구조체를 제일 첨에 위치하는 멤버로 선언하여 사용할 수 있다.)하여 읽기 작업을 하는 건지 쓰기 작업을 하는 건지에 대한 흔적을 남겨야 한다.

 

(3)      Read Request from client

이 과정에서GetQueuedCompletionStatus() 함수를 사용하여 현재 등록된 소켓들 중에 읽기나 쓰기 작업이 완료된 것이 있는지 확인한다. 이 때,IOCP가 알려주는 정보는 2번 과정에서 등록 할 때, 소켓과 같이 입력했던 KEY와 I/O작업을 신청할 때, 인자로 넘겨주었던 OVERLLAPPED 구조체( 확장을 시켰다면 확장 구조체형으로 캐스팅 해주면 된다.)의 주소이다.

 

(4)      Excute request locally

이제3번 과정에서 받은 key와 OVERLAPPED구조체를 가지고 I/O작업을 신청했을 때, 만약 작업이 끝나면 했었을 작업을 해주면 된다.

 

(5)      Return result to client

이 과정은 사실4번 과정과 같이 포함되는 부분이다. 즉, 채팅을 예로 들면, 어떤 사용자가 메시지를 입력했을 때, 4번과정의 If( pOverlapped->mode == 읽기 ) {} 블록안이 실행될 것이고, 어떤 메시지인지 확인한 후, 접속한 모든 사용자에게 메시지를 보내게 된다.

 

 

 

3.      IOCP 장단점

ü       장점

A.      2번(IOCP)에서 빨간색 문자색으로 써 있는 것 처럼 적은 수의 쓰레드로 윈속2 서버를 구성 할 수 있다. 윈속 2 API중에서 가장 적다.

B.      윈속2 API중에서 CPU 점유율이 가장 낮다. 이 점은 적은 수의 쓰레드를 사용하므로 얻는 이점이다. 쓰레드 숫자가 적으므로 당연히 ThreadContext Switch도 적게 일어난다.

C.      윈속2 API 중에서 가장 확장성과 성능이 뛰어나다.

 

ü       단점

A.      프로그램이 어렵다. 즉, 개념 파악이 어렵다.

B.      플랫폼이 제약이 있다. 윈속2이상과 윈도우 NT이상만 지원한다. 정확하게는 윈도우 2000이상에서 개발 하는게 낫다.

 

   참고 문서

- www.codeproject.com, msdn.Microsoft.com,www.codeguru.com

-  PlatformSDK, Network Programming For Microsoft Windows

 

 

출처: 예전에 다른분 홈페이지에서 그림을 가져왔는데 지금 잘모르겠습니다.^^;;; 나머지는 제가 공부하면서 정리 했습니다.^^;;;

 

and

프로그래밍 :: 오라클 강좌

★ SQL 의 종류

 

1.DDL (Data Definition Language): 데이터와 그 구조를 정의 합니다.

SQL문

내 용

CREATE

데이터베이스 객체를 생성 합니다.

DROP

데이터베이스 객체를 삭제 합니다.

ALTER

기존에 존재하는 데이터베이스 객체를 다시 정의하는역할을 합니다.


2.DML (Data Manipulation Language): 데이터의 검색과 수정등의 처리

SQL문

내 용

INSERT

데이터베이스 객체에 데이터를 입력

DELETE

데이터베이스 객체에 데이터를 삭제

UPDATE

기존에 존재하는 데이터베이스 객체안의 데이터 수정

SELECT

데이터베이스 객체로부터 데이터를 검색


3.DCL (Data Control Language): 데이터베이스 사용자의 권한을 제어

SQL문

내 용

GRANT

데이터베이스 객체에 권한을 부여 합니다.

REVOKE

이미부여된 데이터베이스객체의 권한을 취소합니다.

 

 

 

 

★ 사용자의 생성

 

새로운 USER를 생성하기 위해서는CREATE USER문을 이용하면 됩니다.
 USER를 생성하기 위해서는USER생성 권한이 있는 사용자로 접속해야 합니다.

사용자 생성 문법(Syntax)

사용자 삽입 이미지



 -user_name: 사용자 이름

 -BY password: 사용자가데이터베이스에 의해 인증되도록 지정하며,데이터베이스 유저 로그온시 사용하는 비밀번호 입니다. 

 -EXTERNALLY: 사용자가운영 체제에 의해서 인증되도록 지정합니다.

 -DEFAULT TABLESPACE사용자 스키마를 위한 기본 테이블 스페이스를 지정합니다.

 -TEMPORARY TABLESPACE사용자의 임시 테이블 스페이스를 지정합니다.

 -QUOTA절을 사용하여사용자가 사용할 테이블 스페이스의 영역을 할당합니다.

 -PASSWORD EXPIRE: 사용자가 SQL*PLUS를 사용하여데이터베이스에 로그인할  때 암호를 재설정하도록 합니다.(사용자가  데이터베이스에 의해  인증될 경우에만 적합한 옵션입니다.)

 -ACCOUNT LOCK/UNLOCK:  사용자 계정을 명시적으로 잠그거나 풀 때 사용할 수  있습니다.(UNLOCK이 기본값입니다.)

 -PROFILE:자원 사용을 제어하고 사용자에게 사용되는 암호 제어 처리 방식을 지정하는데 사용됩니다.

※ 여기선 간단한 유저생성에 대해서만 알아보고 자세한 유저관리와 PROFILE 관리는 어드민에서 설명 하겠습니다.
 

※ 참고 1

 -임시 테이블스페이스를 지정해 주지 않으면 시스템 테이블스페이스가 기본으로 지정되지만시스템 테이블스페이스에 단편화가 발생할 수 있으므로사용자를 생성할때 임시테이블스페이스를 따로 지정해 주는 것이 좋습니다.
 
- 또한DEFAULT TABLESPACE도 사용자를 생성할때 지정해 주지 않으면 기본적으로 시스템 테이블스페이스가 지정이 됩니다.하지만사용자를 생성할때 DEFAULT TABLESPACE를 지정을 해서 사용자가 소유한 데이터와 객체들의 저장 공간을 별도로 관리를 해야 합니다.

  시스템 테이블스페이스는 본래의 목적(모든 데이터 사전 정보와, 저장 프로시저, 패키지, 데이터베이스 트리거등을 저장)을 위해서만 사용되어져야 하지 일반사용자의 데이터 저장용으로 사용 되어서는 안됩니다.


※ 참고 2

테이블 스페이스란?

 -오라클 서버가 테이터를 저장하는 논리적인 구조입니다.
 - 테이블스페이스는하나 또는 여러개의 데이터파일로 구성되는 논리적인 데이터 저장 구조입니다.
 
 테이블 스페이스에 대한 자세한 내용는 오라클 어드민의 테이블스페이스 강좌에서 학습하겠습니다.  



사용자 생성 예제

SQL PLUS를 실행시키고 SCOTT/TIGER로 접속을 합니다.
.
SQL>CREATE USERTESTIDENTIFIED BYTEST;

1행에 오류:
ORA-01031: 권한이 불충분합니다

SCOTT USER는 사용자 생성 권한이 없어서 사용자를 생성할 수 없습니다.
 
SQL>CONN SYSTEM/MANAGER       -- DBA Role이 있는 유저로 접속합니다.

SQL>CREATE USERTESTIDENTIFIED BYTEST;    -- USER를 다시 생성합니다.
 사용자가 생성되었습니다.
 


 새로 생성한 USER로 접속해 볼까요..

SQL>
CONN TEST/TEST

ERROR:
ORA-01045: 사용자 TEST는 CREATE SESSION 권한을 가지고있지 않음; 로그온이
거절되었습니다

-  새로 생성한 TEST USER는 권한이 없어서 접근할 수가 없습니다.
-  모든 USER는 권한이 있고 권한에 해당하는 역할만 할 수 있습니다.
-  TEST라는 USER를 사용하기 위해서도 권한을 부여해주어야 합니다.


SQL>CONN SYSTEM/MANAGER
연결되었습니다.

SQL>GRANT connect, resource TO TEST ;
권한이 부여되었습니다.

SQL>CONN TEST/TEST
연결되었습니다.
 
 ※ 권한에 대한 자세한 설명은 권한 설정에서 학습 하겠습니다.

 

 

 

★ User의 변경 및 삭제

 

USER 변경하기 위해서는ALTER USER문을 사용합니다..

● ALTER USER문으로 변경 가능한 옵션

  -  비밀번호
  -  운영체제 인증
  -  디폴트 테이블 스페이스
  -  임시 테이블 스페이스
  -  테이블 스페이스 분배 할당
  -  프로파일 및 디폴트 역할 


사용자 수정 문법(Syntax)

사용자 삽입 이미지


사용자 수정 예제


SQL>CONN SYSTEM/MANAGER       -- SYSTEM USER로 접속합니다.

SQL>ALTER USERscottIDENTIFIED BYlion;    -- scott USER의 비밀번호를 수정합니다.
 사용자가 변경되었습니다.

SQL>conn scott/lion    -- scott USER의 비밀번호가 바낀걸 확인할 수 있습니다.
접속되었습니다.


SQL>conn system/manager
접속되었습니다.

SQL>ALTER USERscottIDENTIFIED BYtiger;    -- scott USER의 비밀번호를 처음처럼 수정합니다.
 사용자가 변경되었습니다.
 


사용자 삭제


문법(Syntax)


사용자 삽입 이미지


 
 ※CASCADE를 사용하게 되면사용자 이름과 관련된 모든 데이터베이스 스키마가 데이터 사전으로부터
     삭제되며 모든 스키마 객체들 또한 물리적으로 삭제 됩니다.


사용자 정보의 확인


데이터베이스에 등록된 사용자를 조회하기 위해서는DBA_USERS라는 데이터사전을 조회하면 됩니다.
 
SQL*Plus를 실행시켜  system/manager로 접속을 합니다.
 
SQL>SELECT username, default_tablespace, temporary_tablespace
        FROMDBA_USERS;
    
USERNAME      DEFAULT_TABLESPACE      TEMPORARY_TABLES
---------------- -------------------        ----------------
SYS                    SYSTEM                       TEMP
SYSTEM             TOOLS                          TEMP
OUTLN                SYSTEM                        SYSTEM
DBSNMP              SYSTEM                       SYSTEM
ORDSYS              SYSTEM                       SYSTEM
ORDPLUGINS       SYSTEM                        SYSTEM
MDSYS               SYSTEM                        SYSTEM
CTXSYS              DRSYS                          DRSYS
SCOTT                SYSTEM                       SYSTEM
TEST                  TEST                            SYSTEM
STORM               STORM                         SYSTEM
KJS                    SYSTEM                        SYSTEM
OEM                   OEM_REPOSITORY         TEMP
 
 위와 같이 유저와 테이블 스페이스에 대한 정보가 화면에 나옵니다.

 

 

 

시스템 권한(System Privileges)

오라클에서 권한(Privilege)은 특정 타입의 SQL문을 실행하거나 데이터베이스나 데이터 베이스
 객체에 접근할 수 있는 권리입니다.


SYSTEM PRIVILEGES

 -
시스템 권한은 사용자가 데이터베이스에서 특정 작업을 수행 할 수 있도록 합니다
 
- 약 126개의 시스템 권한이 있으며 그 수는 계속 증가하고 있습니다.
 - 권한의ANY 키워드는 사용자가 모든 스키마에서 권한을 가짐을 의미 합니다.
 -GRANT명령은 사용자 또는 Role에 대해서 권한을 부여 합니다.
 -REVOKE명령은 권한을 삭제 합니다.


  시스템 권한의 종류 몇가지   

  -  CREATE SESSION :
데이터 베이스를 연결할 수 있는 권한
  -  CREATE ROLE :
오라클 데이터베이스 역할을 생성할 수 있는 권한
  -  CREATE VIEW :
뷰의 생성 권한
  -  ALTER USER :
생성한 사용자의 정의를 변경할 수 있는 권한
  -  DROP USER :
생성한 사용자를 삭제시키는 권한


시스템 권한 부여 문법(Syntax)

사용자 삽입 이미지



 -system_privilege: 부여할시스템 권한의 이름

 -role: 부여할데이터베이스 역할의 이름

 -user, role: 부여할사용자 이름과 다른 데이터 베이스 역할 이름

 -PUBLIC:시스템 권한, 또는 데이터베이스 역할을 모든 사용자에게 부여할 수 있습니다.

 -WITH ADMIN OPTION:권한을 부여 받은 사용자도 부여 받은 권한을 다른 사용자 또는 역할로
           부여할 수 있게 되며,만약 사용자가 WITH ADMIN OPTION과 같이 역할을 부여 받는다면
           부여된 역할은 그 사용자에 의해 변경 또는 삭제 될 수 있습니다.


시스템 권한 부여 예제


SQL>GRANTCREATE USER,ALTER USER,DROP USERTOscott
        WITH  ADMIN  OPTION.

 권한이 부여되었습니다.

*설명 : scott 사용자에게 사용자를생성, 수정, 삭제 할 수 있는 권한을 부여하고,
         scott 사용자도다른 사용자에게 그 권한을 부여 할 수 있습니다.
 


시스템 권한의 박탈

문법(Syntax)

사용자 삽입 이미지


시스템 권한 철회 예제


SQL>REVOKECREATE USER,ALTER USER,DROP USER
        FROMscott
        

 권한이 회수되었습니다.

*설명 : scott 사용자에게 부여한생성, 수정, 삭제 권한을 회수합니다,
           


WITH ADMIN OPTION을 사용하여 시스템 권한 취소


 WITH ADMIN OPTION을 사용하여 시스템 권한을 부여했어도 시스템 권한을 취소 할 때는 연쇄적으로 취소 되지 않습니다.

사용자 삽입 이미지

시나리오

 1. DBA가 STORM에게 WITH ADMIN OPTION을 사용하여 CREATE TABLE 시스템 권한을 부여 합니다.

2. STORM이 테이블을 생성 합니다.

3. STORM이 CREATE TABLE 시스템 권한을 SCOTT에게 부여 합니다.

4. SCOTT가 테이블을 생성 합니다.

5. DBA가 STORM에게 부여한 CREATE TABLE 시스템 권한을 취소 합니다.

사용자 삽입 이미지

결과

 - STORM의 테이블은 여전히 존재하지만 새 테이블을 생성할 수 있는 권한은 없습니다.

 - SCOTT는 여전히 테이블과 새로운 테이블을 생성 할 수 있는 CREATE TABLE권한을 가지고 있습니다.

 

 

 

 

객체 권한(Object Privileges)

 

Object Privileges(객체 권한)


   객체 권한은 유저가 소유하고 있는 특정한 객체를다른 사용자들이 엑세스 하거나 조작 할 수 있게 하기 위해서 생성을 합니다.


  -테이블이나 뷰, 시퀀스, 프로시저, 함수, 또는 패키지 중 지정된 한 오브젝트에 특별한 작업을
    수행 할 수 있게 합니다.
  
  - Object 소유자는 다른 사용자에게 특정 Object Privileges를 부여 할 수 있습니다.

  -PUBLIC으로 권한을 부여하면 회수할 때도 PUBLIC으로 해야 합니다.

  - Object Privileges는 Object Type에 따라서 다릅니다.

  -기본적으로 소유한 오브젝트에 대한 모든 권한이 자동적으로 획득됩니다

  -WITH GRANT OPTION 옵션은 롤에 권한을 부여할 때는 사용할 수 없습니다


 * Object에 따른 Privileges

객체권한

테이블

Sequence

Procedure

  ALTER

 

 

  DELETE

 

 

  EXECUTE

 

 

 

  INDEX

 

 

 

  INSERT

 

 

  REFERENCES

 

 

 

  SELECT

 

  UPDATE

 

 


  위의 표에서
맨 왼쪽에 있는 ALTER, DELETE, EXECUTE.. 등등은object_privilege란에 오면 되고,
맨 윗줄에 있는 테이블, 뷰, 시퀀스, 프로시져 등등은ON다음에 있는object에 입력하면 됩니다.


Object 권한 부여 문법

사용자 삽입 이미지

사용자 삽입 이미지


 -object_privilege: 부여할 객체권한의 이름

 -object: 객체명

 -user, role: 부여할사용자 이름과 다른데이터 베이스 역할 이름

 -PUBLIC: 오브젝 권한, 또는 데이터베이스 역할을모든 사용자에게 부여할 수 있습니다.

 -WITH GRANT OPTION:권한을 부여 받은 사용자도 부여 받은 권한을 다른 사용자 또는 역할로
                      
부여할 수 있게 됩니다.


오브젝 권한 부여 예제


SQL>GRANTSELECT, INSERT
        ONemp
        TOscott
        WITH  GRANT  OPTION.

 권한이 부여되었습니다.

*설명 : scott 사용자에게emp테이블을 SELECT, INSERT할 수 있는권한을 부여했습니다.
          scott 사용자도다른 사용자에게 그 권한을 부여 할 수 있습니다.
 



Object 권한의 박탈

사용자 삽입 이미지

사용자 삽입 이미지


 - 객체 권한의 철회는권한을 부여한 부여자만이 수행할수 있습니다.

 -CASCADE CONSTRAINTS: 이 명령어의 사용으로 REFERENCES객체 권한에서 사용된
               참조 무결성 제한을 같이 삭제 할 수 있습니다.

 -WITH GRANT OPTION으로 객체 권한을 부여한 사용자의 객체 권한을 철회하면,권한을
   부여받은 사용자가 부여한 객체 권한 또한 같이 철회되는 종속철회
발생합니다.



오브젝 권한 철회 예제


SQL>REVOKESELECT, INSERT
         ONemp
         FROMscott


*설명 : scott 사용자에게부여한 emp테이블에 대한 SELECT, INSERT권한이 회수 됩니다..
         만약 scott사용자가 다른 사용자에게 SELECT, INSERT권한을 부여했으면..
         그 권한들도 같이 철회가 됩니다.
 


WITH GRANT OPTION을 사용하여 객체 권한 취소


 WITH GRANT OPTION을 사용하여 부여한 객체 권한을 취소하면 취소 작업이 연쇄적으로 수행 됩니다.

사용자 삽입 이미지

시나리오

 1. SCOTT가 STORM에게 WITH GRANT OPTION을 사용하여 emp테이블의 SELECT 권한을 부여 합니다.

2. STORM이 emp테이블의 SELECT권한을 TEST에게 부여 합니다.

3. SCOTT가 STORM에게 부여한 emp테이블의 SELECT 권한을 취소 합니다.

사용자 삽입 이미지

결과

 - SCOTTt가 STORM에게 부여한 emp테이블에 대한 SELECT 권한을 취소하면 STORM이 부여한 TEST유저가 emp테이블을 SELECT할 수 있는 권한도 자동으로 취소가 됩니다.

 



객체 권한을 위한 일반 사용자용 데이터 사전 뷰
 

데이터 사전 뷰

설명

 USER_TAB_PRIVS

 객체 권한의 소유자, 객체 권한 부여자, 객체 권한 피부여자를 볼수있음

 USER_TAB_PRIVS_MADE

 사용자가 부여모든 객체 권한의 뷰

 USER_TAB_PRIVS_RECD

 사용자가 부여받은모든 객체 권한의 뷰

 USER_COL_PRIVS

 객체 권한의 소유자, 객체 권한 부여자, 객체 권한 피부여자의 컬럼의 객체
 권한 뷰

 USER_COL_PRIVS_MADE

 사용자가 부여객체컬럼에 대한 모든 객체 권한 뷰

 USER_COL_PRIVS_RECD

 사용자가 부여받은객체컬럼에 대한 모든 객체 권한 뷰

 

롤(Role)


 

 ROLE이란사용자에게 허가할 수 있는 권한들의 집합이라고 할 수 있습니다.


  - ROLE을 이용하면권한 부여와 회수를 쉽게 할 수 있습니다.

  - ROLE은Create Role권한을 가진 User에 의해서 생성됩니다.

  - 한 사용자가 여러개의 ROLL을 ACCESS할 수 있고,  여러 사용자에게 같은 ROLE을 부여할 수
    있습니다.

  -시스템 권한을 부여하고, 취소할 때와 동일한 명령을 사용하여 사용자에게 부여하고, 취소합니다.

  - 사용자는ROLE에 ROLE을 부여할 수 있습니다.

  - 오라클 데이터베이스를 설치하면 기본적으로CONNECT, RESOURCE, DBAROLE이 제공  
    됩니다.


   아래의 그림처럼 DBA가 유저들에게 권한을 부여할 때 일일이 권한 하나하나씩을 지정을 한다면 몹시 불편할 것 입니다. DBA가 USER의 역할에 맞도록 Role을 생성하여서 Role만 유저에게 지정을 한다면 보다 효율적으 로 유저들의 권한을 관리 할 수 있습니다.

사용자 삽입 이미지

사용자 삽입 이미지


ROLE의 생성

문법

사용자 삽입 이미지
 


ROLE의  부여 순서
 ①ROLE의 생성 :  CREATE ROLE manager
 ②ROLE에 권한 부여: GRANT create session, create table TO manager
 ③ROLE을 사용자 또는 ROLE에게 부여: GRANT manager TO scott, test;
 

-- role을 생성 합니다.
SQL>
CREATE ROLEmanager

-- role에 권한을 부여 합니다.
SQL>GRANT
create session, create tableTOmanager

-- 권한이 부여된 role을 user나 role에 부여 합니다.
SQL>GRANT
managerTOscott, test;

 

Dictionary 뷰

내      용

  ROLE_SYS_PRIVS

 Role에 부여된 시스템 권한

  ROLE_TAB_PRIVS

 Role에 부여된 테이블 권한

  USER_ROLE_PRIVS

 현재 사용자가 ACCESS할 수 있는 ROLE

  USER_TAB_PRIVS_MADE

 현재 사용자의 객체에 부여객체 권한

  USER_TAB_PRIVS_RECD

 현재 사용자의 객체에 부여객체 권한

  USER_COL_PRIVS_MADE

 현재 사용자 객체의 특정컬럼에 부여객체 권한

  USER_COL_PRIVS_RECD

 현재 사용자 객체의 특정컬럼에 부여객체 권한

 

 

★ 테이블의 생성

 

이번 강좌는 오라클 테이블해 대해서 설명을 하겠습니다.

 테이블은 실제로 데이터들이 저장되는 곳 이라고 생각하면 쉽게 이해 할 수 있습니다.
 CREATE TABLE명령어를 이용해서 테이블을 생성 할 수 있습니다.

 아래의 내용은 테이블에 대한 보충 설명입니다.


테이블 이란?

1. 테이블은 오라클 데이타베이스의기본적인 데이타 저장 단위입니다.

2. 데이타베이스 테이블은 사용자가 접근 가능한 모든 데이타를 보유하며레코드와 컬럼으로 구성 
   
됩니다.
  
 관계형 데이타베이스가 아닌 예전의 데이타 베이스 용어에서는 파일과 테이블이, 필드와 컬럼이,
   그리고 레코드와 행이 동일시 되었습니다.

3. 테이블은 시스템내에서 독립적으로 사용되길 원하는 엔티티를 표현할수 있습니다.   
   예를 들면, 회사에서의 고용자나 제품에 대한 주문은 테이블로 표현 가능합니다.

4. 테이블은 두 엔티티간의 관계를 표현할 수 있습니다.
   즉 테이블은 고용자와 그들의 작업 숙련도 혹은 제품과 주문과의 관계를 표현하는데  사용될 수
   있습니다.

   
테이블내에 있는 외래 키 (ForeIgn Key)는  두 엔티티 사이의 관계를 표현하는데 사용됩니다.

5. 비록 "테이블" 이라는 말이 더 많이 사용되지만 테이블의 형식어는 "릴레이션" 입니다.


컬  럼
  - 
테이블의 각 컬럼은 엔티티의 한 속성을 표현한다

행(ROW, 레코드)
  -
테이블의 데이타는 행에 저장됩니다 



※ 테이블 생성시 제한사항과 고려할점

  - 테이블 이름과 컬럼은 항상 알파벳 문자로 시작해야 하며A~Z까지의 문자, 0~9까지의 숫자,   
     
그리고$,#,_(Under Bar)를 사용할 수 있습니다. (★공백 사용 불가능)

  -테이블의 컬럼 이름은30자를 초과할수 없고,예약어를 사용할수 없읍니다.

  -  오라클 테이블한 계정안에서 테이블 이름은 다른 테이블 이름과 달리 유사해야 합니다.

  - 한 테이블 안에서 컬럼이름은 같을수 없으며 다른 테이블에서의 컬럼이름과는 같을수  있습니다. 


테이블의 생성 문법


[Syntax]

사용자 삽입 이미지



- schema :

테이블의 소유자

- table_name:

테이블 이름

- column:

컬럼의 이름

- datatype:

컬럼의 데이터 유형

- TABLESPACE:

테이블이 데이터를 저장 할 테이블스페이스를 지정합니다.

- PCTFREE :

블럭내에 이미 존재하고 있는 Row에Update가 가능하도록 예약시켜 놓는 블럭의 퍼센트 값을 지정 합니다.

- PCTUSED :

테이블데이터가 저장될 블록의 행 데이터 부분의 크기를 퍼센트지로 지정합니다.
PCTFREE에 의해 지정된 크기만큼 Block이 차면 PCTUSED 값보다 작아져야 새로운 행 삽입이 가능  합니다.

- INITRANS :

하나의 데이터블록에 지정될 초기 트랜잭션의 값을 지정합니다. (기본값은 1)

- MAXTRANS:

하나의 데이터 블록에 지정될 수 있는 트랜잭션 최대 수를 지정 합니다. (기본값은 255)

- STORAGE:

익스텐트 스토리지에 대한 값을 지정 합니다.

- LOGGING:

테이블에 대해 이후의모든 작업이 리두 로그 파일 내에 기록 되도록 지정합니다. (default)

- NOLOGGING:

리두 로그 파일에 테이블의 생성과 특정 유형의 데이터 로드를  기록하지 않도록 지정 합니다.

- CACHE :

전체 테이블 스캔(full table scan)이 수행될 때 읽어 들인 블록이 버퍼 캐쉬 내의 LRU 리스트의 가장 근에 사용된 것의 자리에 위치 하도록 지정 합니다.

- NOCACHE :

전체 테이블 스캔(full table scan)이 수행될때 읽어 들인 블록이 버퍼 캐쉬 내의 LRU 리스트의 가장 최근에 사용 되지 않은 것의 자리에 위치하도록 지정 합니다.


 *  PCTFREE, PCTUSED에 대한 자세한 강좌는 오라클 어드민 강좌의 6. Storage Structure => PCTFREE와 PCTUSED를 참고해 주세요


테이블의 생성 예제

emp2와 dept2테이블을 생성하는 예제입니다.

SQL>CREATE TABLEEMP2(
        EMPNO     NUMBER  CONSTRAINT  emp_pk_empno   PRIMARY KEY,     
     -  (컬럼)         (데이터타입)                            (제약조건)
        ENAME        VARCHAR2(20),
        JOB             VARCHAR2(40),
        MGR             NUMBER,
        HIREDATE     DATE,
        SAL              NUMBER,
        COMM          NUMBER,
        DEPTNO       NUMBER)
        PCTFREE 20
        PCTUSED 50 ;

테이블이 생성되었습니다.


SQL>CREATE TABLEDEPT2(
        DEPTNO NUMBERCONSTRAINTdept_pk_deptnoPRIMARY KEY,
        DNAME      VARCHAR2(40),
        LOC          VARCHAR2(50));

테이블이 생성되었습니다.



테이블 생성시 주의사항

 - 테이블 이름을 지정하고각 컬럼들은 괄호 "()" 로 묶어 지정합니다.

 -컬럼뒤에 데이터 타입은 꼭 지정되어야 합니다.

 -각 컬럼들은 콤마","로 구분되고, 항상 끝은 세미콜론";" 으로 끝납니다.

 -한 테이블 안에서 컬럼이름은 같을수 없으며다른 테이블에서의 컬럼이름과는 같을 수 있습니다.

유저가 소유한 모든 테이블 보기


USER_TABLES데이터사전을 조회 하면유저가 소유한 테이블을 확인 할 수 있습니다.

-- SQL*Plus에서 실행해 보세요..
SQL>SELECT table_name FROM  USER_TABLES;

TABLE_NAME
------------
BONUS
CRETABLE
DEPT
DUMMY
EMP
EMP2
SALGRADE

위와 같이 테이블 목록이 조회 됩니다.
 

 

 

★ 테이블의 제약조건

 

제약조건 (Constraint)

  제약조건이란 테이블에 부적절한 자료가 입력되는 것을 방지하기 위해서 여러 가지 규칙을 적용해 놓는거라 생각하면 됩니다. 간단하게테이블안에서 테이터의 성격을 정의하는 것이 바로 제약조건 입니다.

 ★데이터의 무결성 유지를 위하여 사용자가 지정할 수 있는 성질입니다.

 ★모든 CONSTRAINT는 데이터 사전(DICTIONARY)에 저장됩니다.

 ★ 의미있는 이름을 부여했다면 CONSTRAINT를 쉽게 참조할 수 있습니다.

 ★ 표준 객체 명명법을 따르는 것이 좋습니다.

 ★ 제약조건은 테이블을 생성할 당시에 지정할 수도 있고, 테이블 생성 후 구조변경(ALTER)명령어를
     통해서도 추가가 가능합니다.

 ★ NOT NULL제약조건은 반드시 컬럼 레벨에서만 정의가 가능합니다.


NOT NULL 조건
:컬럼을 필수 필드화 시킬 때 사용합니다.


SQL> CREATE TABLE emp(
        enameVARCHAR2(20)  CONSTRAINTemp_nn_enameNOT NULL);
        이런식으로 하면 ename 컬럼에는 꼭 데이터를 입력해야만 합니다.

        여기서emp_nn_ename은 (테이블이름_제약조건이름_컬럼이름)형식으로
        CONSTRAINT NAME을 정의 합니다.

        CONSTRAINT NAME은 USER_CONSTRAINTS 뷰(VIEW)를 통해서 확인할수 있습니다.

SQL> SELECT CONSTRAINT_NAME
         FROM    USER_CONSTRAINTS
         WHERE  TABLE_NAME ='EMP' ;

          CONSTRAINT_NAME
          -----------------------
          emp_nn_ename           이런 식으로 제약사항의 이름을 확인할수 있습니다.
 



UNIQUE 조건
:
데이터의 유일성을 보장(중복되는 데이터가 존재할수 없습니다.)
자동으로 index가 생성됩니다.    


SQL> ALTER TABLEemp
        ADD CONSTRAINTemp_uk_deptnoUNIQUE (deptno);

테이블이 변경되었습니다.

     이런식으로 하면 deptno 컬럼에 중복된 데이터가 들어갈 수 없습니다.

-- 제약 조건의 삭제

SQL>ALTER TABLEemp
       DROP CONSTRAINTemp_uk_deptno ; 

테이블이 변경되었습니다.
 



CHECK 조건:
컬럼의 값을 어떤특정 범위로 제한할 수 있습니다.


SQL>ALTER TABLEemp
       ADD CONSTRAINTemp_ck_comm
       CHECK(comm >= 10 AND comm <= 100000) ;

테이블이 변경되었습니다.

     comm컬럼은 체크조건에서 제한을 하고 있으므로 1에서 100까지의 값만을 가질수  있습니다.
     
체크 조건에서는 IN 연산자를 사용할수 있습니다.


-- 제약 조건의 삭제

SQL>ALTER TABLEemp
        DROP CONSTRAINTemp_ck_comm ;

테이블이 변경되었습니다.

SQL> ALTER TABLEemp
        ADD CONSTRAINTemp_ck_comm
        CHECK(comm IN (10000,20000,30000,40000,50000));

테이블이 변경되었습니다.

     comm 컬럼은 10000,20000,30000,40000,50000의 값만을 가질수 있습니다.
 



DEFAULT
(컬럼 기본값) 지정 :데이터 입력시에입력을 하지 않아도 지정된 값이 입력될수 있습니다.

SQL>CREATE TABLE emp(   
        hiredateDATEDEFAULT SYSDATE ) ;

     이런식으로 하면 hiredate 컬럼에 INSERT를 하지 않아도 오늘 날짜가 들어갑니다.



PRIMARY KEY 지정
:기본키는 UNIQUE 와 NOT NULL의 결합과 같습니다.

  ※  기본키는 그 데이터 행을 대표하는 컬럼으로서의 역할을 수행하여다른 테이블에서
       외래키들이  참조할 수 있는 키로서의 자격을 가지고 있습니다. 이를 참조 무결성이라 합니다
. 

       UNIQUE 조건과 마찬가지로 기본키를 정의하면 자동으로 인덱스를 생성하며
       그 이름은 기본 키  제약 조건의 이름과 같습니다.


INDEX KEY
:검색 키로서 검색 속도를 향상 시킴니다.
                   (UNIQUE,PRIMARY KEY 생성시 자동적으로 생김니다.)

SQL>CREATE TABLE emp(
        empnoNUMBERCONSTRAINTemp_pk_empnoPRIMARY KEY) ;

     이런식으로 하면 empno 컬럼에 UNIQUE 제약조건과 NOT NULL제약조건을 가지게 됩니다.



 FOREIGN KEY(외래 키)지정
:기본키를 참조하는 컬럼 또는 컬럼들의 집합입니다.

※ 외래키를 가지는 컬럼의 데이터 형은 외뢰키가 참조하는 기본키의 컬럼과 데이터형이
    일치해야 합니다.
    이를 어기면 참조무결성 제약에의해 테이블을 생성할수 없습니다.

외래키에 의해 참조되고 있는 기본 키는 삭제할수 없다.

ON DELETE CASCADE연산자와 함께 정의된 외래키의 데이터는  그 기본키가 삭제 될 때 같이
    삭제됩니다.


SQL>ALTER TABLEempADD CONSTRAINTemp_fk_deptno
        FOREIGN  KEY (deptno) REFERENCESdept(deptno)       

테이블이 변경되었습니다.

 이런식으로 하면 emp 테이블의 deptno 컬럼은 dept 테이블에 deptno 컬럼을 참조하는
 외래키를 가지게 됩
니다.

직접 변경해 보세요..

 


제약 조건의 확인

USER_CONS_COLUMNS: 컬럼에 할당된 제약 조건을 볼 수 있습니다.
USER_CONSTRAINTS: 유저가 소유한 모든 제약 조건을 불 수 있습니다.  
이 두개의 데이터사전을 참조 하면 됩니다.
 
 SQL> SELECT  SUBSTR(A.COLUMN_NAME,1,15) COLUMN_NAME,
               DECODE(B.CONSTRAINT_TYPE,
                                         'P','PRIMARY KEY',
                        'U','UNIQUE KEY',
                      'C','CHECK OR NOT NULL',
                                        'R','FOREIGN KEY') CONSTRAINT_TYPE,
              A.CONSTRAINT_NAME   CONSTRAINT_NAME
        FROMUSER_CONS_COLUMNSA,USER_CONSTRAINTSB
        WHERE  A.TABLE_NAME = UPPER('&table_name')
            AND  A.TABLE_NAME = B.TABLE_NAME
            AND  A.CONSTRAINT_NAME = B.CONSTRAINT_NAME
        ORDER BY 1;

-- 테이블 명을 입력 하면 됩니다.
table_name의 값을 입력하십시오: emp2

 
COLUMN_NAME         CONSTRAINT_TYPE   CONSTRAINT_NAME
------------------------------ ----------------- --------------
DEPTNO                   CHECK OR NOT NULL      SYS_C001362   
                               FOREIGN KEY                EMP2_FK_DEPTNO
EMPNO                     PRIMARY KEY               EMP2_PK_EMPNO
ENAME                     CHECK OR NOT NULL     EMP2_NN_ENAME
MGR                        UNIQUE KEY                  EMP2_UP_MGR

 

 

 

★ 테이블의 관리

 

테이블의 관리는 테이블의 컬럼 관리와 테이블 정보 관리로 나누어서 설명 하겠습니다.


① 테이블 컬럼의 관리

 테이블의 컬럼은 ADD, MODIFY, DROP연산자를 통해서 관리 할 수 있습니다.


ADD연산자 :테이블에 새로운 컬럼을 추가할 때 사용 합니다.

SQL>ALTER TABLE empADD(addr VARCHAR2(50));

VARCHAR2의 데이터 형을 가지는 addr 컬럼이 emp 테이블에 추가 됩니다.



MODIFY연산자 :
테이블의 컬럼을 수정하거나 NOT NULL컬럼으로 변경 할 수 있습니다.  


SQL>ALTER TABLE empMODIFY(ename VARCHAR2(50));
SQL>ALTER TABLE empMODIFY(ename VARCHAR2(50) NOT NULL) ;

ename컬럼이VARCHAR2 50자리로 수정 됩니다.

컬럼이 이미 테이터를 가지고 있을 경우 다른 데이터형으로 변경이 불가능합니다. 



DROP
연산자 :테이블 컬럼을 삭제 하거나, 테이블의 제약 조건을 삭제할 때 사용 합니다. 


컬럼의 삭제 예제

 -- 컬럼의 삭제는 오라클 8i버전 부터 지원을 합니다.
  SQL>
ALTER TABLE table_nameDROP COLUMNcolumn_name


제약 조건의 삭제 예제

  SQL>ALTER TABLE empDROP PRIMARY KEY;


 -- CASCADE 연산자와 함께 사용하면 외래키에 의해 참조되는 기본키도 삭제될수 있습니다.
 SQL>ALTER TABLE empDROP CONSTRAINTemp_pk_empnoCASCADE;
 




② 테이블 정보의 관리

기존 테이블의 복사


 -기존 테이블을 부분, 또는 완전히 복사할 때에 서브쿼리를 가진 CREATE TABLE 명령어
   사용해서 쉽게 테이블을 복사 할 수 있습니다.

 - 하지만제약 조건, 트리거, 그리고 테이블 권한은  새로운 테이블로 복사되지 않습니다. 

 - 제약조건은NOT NULL제약조건만 복사 됩니다.

[Syntax] 

사용자 삽입 이미지



한번 실습해 보세요..

SQL>CREATE TABLE emp2
       AS
       SELECT * FROM emp;
 테이블이 생성되었습니다.



테이블 정보의 변경


 - 보통 테이블의 정보를 변경하는 이유는스토리지 파라미터와 블록 활용파라미터를 변경하기 위해서
   사용 합니다.
 
 -  테이블 정보의 변경시 INITIAL의 값은 변경 할 수 없습니다.

[Syntax]

사용자 삽입 이미지



 STORAGE-CLAUSE에 들어올 수 있는 스토리지 파라미터를 정리하면 아래와 같습니다.
 
  - NEXT
    다음 번 생성될 익스텐트의 크기를 Byte단위로 지정합니다.
    이후의 익스텐트 크기는 PCTINCREASE만큼씩 증가 됩니다.

  - PCTINCREASE
    마지막 생성된 익스텐트의 바로 다음에 생성될 익스텐트의 증가율을 퍼센트지로 지정합니다.

  - MINEXTENTS
    최초 생성되는 익스텐트의 수를 지정합니다.

  - MAXEXTENTS
    생성될 수 있는 최대 익스텐트의 수를 지정합니다.


기타 블록관련 파라미터는 테이블의 생성 강좌를 참고하세요.. 



테이블의 테이블스페이스 변경


Oracle8i이전 버전에서는 export를 해서 다시 import를 해야지만 테이블스페이스를 변경 할 수 있었지만
오라클 8i부터는ALTER TABLE ~MOVE TABLESPACE명령어로 쉽게
테이블의 테이블스페이스를 변경 할 수 있습니다.

[Syntax]

사용자 삽입 이미지


-- 한번 실습해 보세요.
SQLPLUS scott/tiger
 
SQL>ALTER TABLE emp MOVE TABLESPACE test;
테이블이 변경되었습니다 



테이블의 TRUNCATE


 - 테이블을 Truncate하면테이블의 모든 행이 삭제되고 사용된 공간이 해제 됩니다.

 -TRUNCATE TABLE은 DDL명령이므로 롤백 데이터가 생성되지 않습니다.
   DELETE명령으로 데이터를 지우면 롤백명렁어로 복구 할 수 있지만
   TRUNCATE로 데이터를 삭제하면 롤백을 할 수가 없습니다.
 
 -행당 인덱스도 같이 잘려 나갑니다.
 
 -외래키가 참조중인 테이블은 TRUNCATE할 수 없습니다.
 
 -TRUNCATE명령을 사용하면 삭제 트리거가 실행되지 않습니다.

[Syntax]

사용자 삽입 이미지

 



DROP TABLE (테이블을 삭제할 때 사용)


[Syntax]

사용자 삽입 이미지


SQL>DROP TABLEemp ;

SQL>DROP TABLEempCASCADE CONSTRAINT;

CASCADE CONSTRAINT :외래키에 의해 참조되는 기본키를 포함한 테이블일 경우 기본키를 참조하던
                                   외래 키 조건도 같이 삭제 됩니다.

 

 

 

★ 데이터의 삽입, 수정, 삭제

 

▣ INSERT

INSERT명령어는 테이블 안에 데이터를 삽입하는 역할을 합니다. .


사용자 삽입 이미지

사용자 삽입 이미지


 -  
실제 데이터는 VALUES 괄호()안에 입력하고문자열은 단일 따옴표(' ')로 둘러쌉니다.

- 각각의 테이터 구분은 ","로 합니다.

- 테이블 이름 옆에 ()생략시에는 모든 컬럼을 VALUES()안에 입력 시킵니다
 

모든 데이터를 입력할 경우

SQL>INSERT INTOEMP
       VALUES(7369, 'SMITH', 'CLERK', 7902, TO_DATE('80/12/17'),  800, NULL,  20);


원하는 데이터만 입력할 경우

SQL>INSERT INTODEPT (DEPTNO, DNAME)
       VALUES(10, 'ACCOUNTING' );



SELECT 문장을 이용한 INSERT

사용자 삽입 이미지



SQL>INSERT INTODEPT
       SELECT* FROM SCOTT.DEPT ;


직접 데이터를 입력해 봅시다.

오라클을 설치하면 SCOTT/TIGER USER에 기본적으로 EMP, DEPT테이블이 있습니다.
그 데이터를 TEST/TEST USER에 생성한 EMP, DEPT테이블에 INSERT하겠습니다.


SQL>INSERT INTODEPT
        SELECT* FROM SCOTT.DEPT ;

4 개의 행이 만들어졌습니다.

SQL> COMMIT;

커밋이 완료되었습니다.

SQL> INSERT INTO EMP
         SELECT * FROM SCOTT.EMP;

15 개의 행이 만들어졌습니다.

SQL> COMMIT;

커밋이 완료되었습니다.



▣ UPDATE


테이블 안의 데이터를 수정 합니다.

사용자 삽입 이미지

사용자 삽입 이미지

 

SQL>UPDATEEMP
        SETDEPTNO = 30
        WHEREEMPNO = 7902 ;

        사원번호가 7902번인 사람의 부서 번호가 30번으로 수정됨


SQL>UPDATEEMP
        SETSAL = SAL * 1.1
        WHEREDEPTNO = 20 ;

        20부서의 사원들의급여가 10% 인상됨


SQL>UPDATEEMP
        SETHIREDATE = SYSDATE

       모든 사원의 입사일이 오늘로 수정됨



▣ DELETE


사용하지 않는 데이터를 삭제 합니다.

사용자 삽입 이미지

사용자 삽입 이미지


SQL>DELETEFROMEMP
       WHEREEMPNO = 7902 ;
        사원번호가 7902번인 사람의 데이터가 삭제 되었습니다.

SQL>DELETE FROMEMP
        WHERESAL < (SELECT AVG(SAL) FROM EMP) ;
        평균급여보다 적게 받는 사원 삭제

SQL>DELETE FROMEMP ;
        테이블의 모든 행이 삭제 됩니다.

 

 

 

★ Select문 및 연산자

 

SELECT문은데이터베이스로부터 저장되어 있는 데이터를 검색하는데 사용합니다.

[Syntax]

사용자 삽입 이미지


 · DISTINCT : 중복되는 행을 제거하는 옵션입니다.
 · *            :  테이블의모든 column을 출력합니다.
 · alias       :  해당 column에 대해서 다른 이름을 부여할 때 사용합니다.
 · table_name :  질의 대상 테이블명
 · WHERE    :   조건을 만족하는 행들만 검색
 · condition :  column, 표현식, 상수 및 비교 연산자
 · ORDER BY :   질의 결과 정렬을 위한 옵션(ASC:오름차순(Default),DESC내림차순)



 ☞SQL문의 작성 방법

  - SQL 문장은대소문자를 구별하지 않습니다.

  - SQL 문장은한 줄 또는 여러 줄에 입력될 수 있습니다.

  - 일반적으로 키워드는 대문자로 입력합니다.
     다른 모든 단어, 즉 테이블 이름, 열 이름은 소문자로 입력합니다.(권장) 

  -가장 최근의 명령어가 1개가 SQL buffer에 저장됩니다.

  - SQL문 마지막 절의 끝에";"를 기술하여 명령의 끝을 표시합니다.
 

SQL>SELECTempno 사번, ename 성명
       FROM  emp
       WHERE deptno = 10

      사번      성명
---------- ---------------
      7782      CLARK
      7839      KING
      7934      MILLER



empno와 ename 은 각각 사번과 성명이라는 컬럼별칭(alias)으로 만들어 출력했습니다.
alias를 사용할 때 as라는 키워드를 사용해도 되고, 생략할수도 있습니다.


▒ WHERE절에 사용될 수 있는 SQL 연산자

 연산자

 설      명

 BETWEEN a AND b

 a와b사이의 데이터를 출력 합니다.(a, b값 포함)

 IN  (list)

 list의 값 중 어느 하나와 일치하는 데이터를 출력 합니다.

 LIKE

 문자 형태로 일치하는 데이터를 출력 합니다.(%, _사용)

 IS NULL

 NULL값을 가진 데이터를 출력 합니다.

 NOT BETWEEN a AND b

 a와b사이에 있지않은 데이터를 출력 합니다.(a, b값 포함하지 않음)

 NOT IN  (list)

 list의 값과 일치하지 않는 데이터를 출력 합니다.

 NOT LIKE

 문자 형태와 일치하지 않는 데이터를 출력 합니다.

 IS NOT NULL

 NULL값을 갖지 않는 데이터를 출력 합니다.




▣ IN, NOT IN 연산자


IN 연산자

SQL> SELECT empno, ename
         FROM  emp
         WHERE  empnoIN (7900, 7934);

--> 사번이 7900, 7934번인 사원의 사번과 성명 출력

    EMPNO    ENAME
 --------- -------------
     7934      MILLER
     7900      JAMES

2 개의 행이 선택되었습니다.

NOT IN 연산자

SQL> SELECT empno, ename
         FROM  emp
         WHERE  empnoNOT IN (7900, 7934);

--> 사번이 7900, 7934번이 아닌 사원의 사번과 성명 출력

     EMPNO ENAME
-------- --------------
    7369 SMITH
    7499 ALLEN
    7521 WARD
    7566 JONES 
    7654 MARTIN
    7698 BLAKE
    ............................
13 개의 행이 선택되었습니다.



BETWEEN
연산자(AND를 이용해 두 조건을 결합한 검색과 같은 결과값을 보여줍니다.)

BETWEEN 연산자

SQL>  SELECT empno, ename
          FROM  emp
          WHERE  salBETWEEN 3000AND5000 ;

--> 급여가 3000에서 5000사이인 사원만 보여줍니다.

     EMPNO ENAME
   ---------- ------
      7788 SCOTT
      7839 KING
      7902 FORD  
3 개의 행이 선택되었습니다.



LIKE 연산자


 - 검색 STRING 값에 대한 와일드 카드 검색을 위해서 LIKE연산자를 사용 합니다.
 -%: 여러개의 문자열을 나타내는 와일드 카드
 -_:단 하나의 문자를 나타내는 와일드 카드
 -ESCAPE:와일드 카드 문자를 일반문자 처럼 사용하고 싶은 경우에 사용합니다.
   ☞WHERE name LIKE '%a\_y%' ESCAPE '\' ;

구 분

설 명

LIKE 'A%'

컬럼이 'A'로 시작하는 데이터들만 검색됩니다.

LIKE '%A'

컬럼이 'A'로 끝나는 테이터들만 검색됩니다.

LIKE '%KIM%'

컬럼에 'KIM' 문자가 있는 데이터 들만 검색됩니다.

LIKE '%K%I%'

컬럼에 'K' 문자와 'I'문자가 있는 데이터 들만 검색됩니다.

LIKE '_A%'

컬럼에 'A'문자가 두 번째 위치한 데이터 들만 검색됩니다.


- LIKE 연산자는 대소문자를 구분합니다.
- Upper()함수를 이용해 대소문자 구분없이 출력할수 있습니다.


SQL>SELECT empno, ename
        FROM  emp
        WHERE  UPPER(ename)like'%K%';

EMPNO ENAME
------- -----------
   7698 BLAKE
   7782 CLARK
   7839 KING

'K' 문자가 들어있는 사원 정보를 보여줍니다.
upper()라는 함수는 k가 들어가 있는 것도 대문자 'K'로 인식하기 때문에 데이터들을 보여줍니다.



※ '_'를 이용한 LIKE검색

SQL>SELECT empno, ename
        FROM  emp
        WHERE  UPPER(ename)like'_I%'

  EMPNO ENAME
------- ----------
   7839 KING
   7934 MILLER

※ '_'는 한 문자를 나타냅니다.
   'I' 문자가 두 번째 문자에 위치한 사원들의 정보를 보여줍니다.

 



ORDER BY
(ASC[오름차순], DESC[내림차순])
  ORDER BY 절은 데이터의 정렬을 위해 사용합니다.  

SQL> SELECT empno, ename
         FROM  emp
         WHERE  deptno = 30
         ORDER BYenameASC;

   EMPNO ENAME
-------- ---------
    7499 ALLEN
    7698 BLAKE
    7900 JAMES
    7654 MARTIN
    7844 TURNER
    7521 WARD

SQL> SELECT empno, ename
         FROM  emp
         WHERE  deptno = 30
         ORDER BY 2

위 두 개의 쿼리는 동일한 결과를 가져 옵니다.
 

 

 

 

★ 예명(Alias)

 

테이블 예명(Alias)

-테이블 alias로column을 단순, 명확히 할 수 있습니다.

-
현재의 SELECT 문장에 대해서만 유효합니다.

- 테이블 alias는 길이가 30자 까지 가능하나
짧을수록 더욱 좋습니다.

- 테이블alias는 의미가 있어야 합니다

- FROM절에 테이블 alias설정시 해당 테이블 alias는 SELECT문장에서 테이블 이름  대신에
   사용해야 합니다.

 


SQL>
SELECTa.dname,b.cnt
         FROMdept a,(SELECT deptno, COUNT(empno)cntFROM emp GROUP BY deptno)b
         WHEREa.deptno =b.deptno
           ANDb.cnt > 3     


DNAME                                           CNT
----------------------------------- ----------
RESEARCH                                       6
SALES                                             6


사원수가 3명이 넘는 부서의 부서명과 사원수를 보여줍니다.

위 쿼리에선 총 3개의 Alias가 사용됐습니다.
첫 번째로DEPT테이블을 a라는 예명으로
두 번째로부서의 사원수인 COUNT(empno)를 cnt라는 예명으로
세 번째로부서별 사원수를 가져오는 쿼리를 b라는 예명을 주었습니다.

위 예제와 같이 예명은 컬럼에만 주는 것이 아니라. 쿼리 문 및 테이블에도 사용할 수 있습니다.
 

 

 

 

Equi Join, Non_Equi Join, Self Join

 

조인(Join) ?

 둘이상의 테이블을 연결하여 데이터를 검색하는 방법입니다.

 보통 둘 이상의 행들의 공통된 값 Primary Key 및 Foreign Key 값을 사용하여  조인합니다.

 그러므로 두 개의 테이블을 SELECT문장 안에서 조인하려면 적어도 하나의 컬럼이
     그 두 테이블 사이에서 공유 되어야 합니다..


● 조인 방법

- Equijoin(동등 조인, 내부조인)
- Non-equijoin
- Outer join
-
Self join



Cartesian Product(카티션 곱)


검색하고자 했던 데이터뿐 아니라 조인에 사용된 테이블들의 모든 데이터가 Retrun되는 현상



● Cartesian product는 다음과 같은 경우에 발생됩니다.

- 조인 조건을 정의하지 않았을경우

- 조인 조건이 잘못된 경우

- 첫 번째 테이블의 모든 행들이 두 번째 테이블의 모든 행과 조인이 되는 경우

-테이블의 개수가 N이라면 Cartesian product를 피하기 위해서는 적어도 N-1개의 등가
   조건을 SELECT 문안에 포함시켜서 다른 테이블 안에 있는 각 테이블의 컬럼이
   적어도 한번은 참조되도록 해야 합니다.



☞ Equi Join

 -
조건절 EqualityCondition(=)에 의하여 조인이 이루 집니다.

 - Equi join의 성능을 높이기 위해서는 Index 기능을 사용하는 것이 좋습니다.

SQL>SELECT  e.ename, d.dname
         FROM   emp e , dept d
          WHERE
e.deptno = d.deptno;

-
WHERE 절에 조인 조건을 작성하고 column명 앞에 테이블명을 적습니다.



☞ Non-Equijoin


 - Non-equijoin은 테이블의 어떤 column도 join할 테이블의 column에 일치하지 않을 때
    사용하고 조인조건은동등( = )이외의 연산자를 갖습니다.
    (BETWEEN AND, IS NULL, IS NOT NULL, IN, NOT IN)

SQL>SELECT e.ename, d.dname
         FROM emp e, dept d
         WHERE 
e.sal BETWEEN3000AND4000;

ENAME                DNAME
----------------- -----------
SCOTT               ACCOUNTING
FORD                 ACCOUNTING
SCOTT               RESEARCH
FORD                 RESEARCH



☞ Self Join

 -Equi Join과 같으나 하나의 테이블에서 조인이 일어나는 것이 다름니다.

 - 같은 테이블에 대해 두 개의 alias를 작성함으로 FROM절에 두 개의 테이블을 사용
    하는 것과 같이 합니다.

SQL> SELECT concat(a.ename,'  ') ||' : \'|| b.sal  급여
         FROMemp a, emp b
         WHERE a.empno = b.empno

급여
-------------------
SMITH   : \800
ALLEN   : \1600
WARD   : \1250
JONES   : \2975
MARTIN   : \1250
BLAKE   : \2850
CLARK   : \2450
SCOTT   : \3000

이름과 급여를 연결시켜서 보여줍니다.

 

 

 

Outer Join (LEFT, RIGHT, FULL OUTER JOIN)

 

Out(외부) Join

 - equijoin 문장들의 한가지 제약점은 그것들이 조인을 생성하려 하는 두 개의 테이블의 두 개
    컬럼에서 공통된 값이 없다면 테이블로부터 테이터를 Return하지 않는 다는 것입니다.

 - 정상적으로 조인 조건을 만족하지 못하는 행들을 보기위해 outer join을 사용합니다.
    Outer join 연산자 "( + )"입니다.

 -조인시킬 값이 없는 조인측에 "( + )"를 위치 시킵니다.

 - Outer join 연산자는 표현식의 한 편에만 올 수 있습니다.


예제1) 일반 조인의 경우

SQL> SELECT DISTINCT(a.deptno), b.deptno
         FROM emp a, dept b
         WHERE  a.deptno = b.deptno

DEPTNO     DEPTNO
---------- ----------
        10         10
        20         20
        30         30


예제2)out join을 했을 경우

SQL>  SELECT DISTINCT(a.deptno), b.deptno
          FROM emp a, dept b
          WHERE  a.deptno(+) = b.deptno

 DEPTNO     DEPTNO
 -------     ----------
     10         10
     20         20
     30         30
                 40

※ 다음의 쿼리를 한번 잘 보시기 바랍니다.

SQL>  SELECT DISTINCT(a.deptno), b.deptno
          FROM emp a, dept b
          WHERE  a.deptno(+) = b.deptno
               ANDa.ename LIKE '%';

    DEPTNO     DEPTNO
---------- ----------
        10         10
        20         20
        30         30

쿼리 결과를 잘 보면 out조인이 되지 않은 것을 알 수 있습니다.
위 쿼리를 out조인이 되기 위해서는 아래와 같이 고쳐야 합니다
.

SQL> SELECT DISTINCT(a.deptno), b.deptno
         FROM emp a, dept b
         WHERE a.deptno(+) = b.deptno
              ANDa.ename(+) LIKE '%'

    DEPTNO     DEPTNO
---------- ----------
        10         10
        20         20
        30         30
                    40

OUT조인 조건이 걸려있는 테이블에는 다른 조건절이 들어와도
똑같이 OUT조인 연산자인 (+)를 해주어야 합니다.  



Oracle9i부터는 ANSI/ISO SQL표준인LEFT OUTER JOIN,RIGHT OUTER JOIN,FULL OUTER JOIN를 지원 합니다.


LEFT OUTER JOIN
 왼쪽 테이블에 조인시킬 컬럽의 값이 없는 경우 사용합니다.
 
SQL>SELECT DISTINCT(e.deptno), d.deptno
    FROM dept dLEFT OUTER JOINemp e
    ONd.deptno = e.deptno;
 
 
RIGHT OUTER JOIN
 - 오른쪽에 테이블에 조인시킬 컬럽의 값이 없는 경우 사용합니다.
 
SQL>SELECT DISTINCT(a.deptno), b.deptno
    FROM emp aRIGHT OUTER JOINdept b
    ONa.deptno = b.deptno;
 
 
FULL OUTER JOIN
양쪽 테이블에 다 outer join을 거는것을 TWO-WAY OUTER JOIN 또는 FULL OUTER JOIN이라 합니다.
 
SQL>SELECT DISTINCT(a.deptno), b.deptno
    FROM emp aFULL OUTER JOINdept b
    ONa.deptno = b.deptno;
 
-- 위 세 문장의 결과는 아래와 같습니다.
    DEPTNO     DEPTNO
---------- ----------
        10         10
        20         20
        30         30
                   40
 
LEFT OUTER JOIN과 RIGHT OUTER JOIN의 테이블 순서를 바꾸어 가면서 테스트를 하시면 쉽게 이해를 하실 수 있습니다.

 

 

 

Commit과 Rollback 예제

 

Commit 과 Rollback

  
이전의 커밋(COMMIT)이 일어난 뒤부터 다음의 커밋(COMMIT) 전까지의 작업이 하나의 트랜
잭션 이며
, 커밋과 롤백(ROLLBACK)은 이러한 트랜잭션 단위로 데이터 베이스에서 발생한
작업을 저장, 삭제하는 일입니다.

 
- Automatic commit:DDL(Create, Alter, Drop), DCL(Grant, Revoke)

 
- Automatic Rollback:비정상적인 종료, system failure 
 
커밋과 롤백 예제입니다.


SQL>DELETE FROM  emp WHERE empno = 7521 ;
       한 개의 행이 삭제 되었습니다.

SQL>COMMIT;
      커밋이 완료 되었습니다
 
  한 개의 행을 삭제하고, COMMIT 문으로 데이터를 영구히 저장했습니다. 이 것은하나의 트랜잭션이 여기서 종료되고 새로운 트랜잭션이 발생하는 것을 말합니다.

SQL>SELECT empno FROM EMP WHERE empno = 7521;
       선택된 레코드가 없습니다.



SQL>INSERT INTO emp(empno, ename, hiredate) VALUES(9000, 'test', sysdate );
     한 개의 행이 작성되었습니다.

SQL>COMMIT;
     커밋이 완료 되었습니다.

SQL>DELETE FROM emp WHERE empno = 9000;
     한 개의 행이 삭제 되었습니다.

SQL>SELECT empno FROM emp WHERE empno = 9000 ;
       선택된 레코드가 없습니다.  


의 예제를 보면은 empno가 9000번인 데이터를 Insert한 후 commit으로 데이터를 저장한 다음에
데이터를 다시 삭제한 후 Select를 해보면 데이터가 검색되지 않는 것을 알 수 있습니다.

하지만다른 유저에서는 커밋이나 롤백을 하기 전까지 이전에 Insert한 empno가 9000번인 데이터를
조회하면 데이터가 검색 됩니다.

데이터베이스에서의 이런 기능을 읽기 일관성이라고 합니다.


SQL>ROLLBACK;
     롤백이 완료되었습니다.

(이전에 트랜잭션(커밋)이 발생하고나서 지금 발생한 ROLLBACK 문 전까지의 작업의 취소를 말합니다. )


검색을 해보면 커밋이 완료된 시점의 레코드 하나가 검색 됩니다.
SQL>SELECT  empno FROM  emp WHERE empno = 9000 ;

   EMPNO
----------
      9000
     한 개의 행이 선택되었습니다.



SAVEPOINT 와 ROLLBACK TO

  SAVEPOINT
는사용자가 트랜잭션의 작업을 여러개의 세그먼트로 분할할 수 있도록 하는 특별한
 작업입니다.
 SAVEPOINT는부분적인 롤백을 가능하게 하기 위해 트랜잭션에 대한 중간점을 정의 합니다.
 

SQL>INSERT INTO emp(empno, ename, hiredate) VALUES(10000, 'test2', sysdate );
       한 개의 행이 작성되었습니다.

SQL>SAVEPOINT A;
       저장점이 생성되었습니다.(여기서 SAVEPOINT를 생성했습니다.)

SQL>INSERT INTO emp(empno, ename, hiredate) VALUES(10001, 'test3', sysdate );
     
  한 개의 행이 작성되었습니다.

SQL>INSERT INTO emp(empno, ename, hiredate) VALUES(10002, 'test4', sysdate );
   
    한 개의 행이 작성되었습니다.

SQL>DELETE FROM emp WHERE empno IN(10000, 10001, 10002);
       세 개의 행이 삭제 되었습니다.

SQL>SELECT empno, ename FROM emp WHERE empno IN(10000, 10001, 10002);
    
   선택된 행이 없습니다.

SQL>ROLLBACK TO A;
        롤백이 완료되었습니다.(SAVEPOINT까지만 롤백이 시행됩니다.)

SQL>SELECT empno , ename FROM emp WHERE empno IN(10000, 10001, 10002);
        한 개의 행이 선택되었습니다.

     EMPNO ENAME
--------- ---------------
    10000 test2

  SAVEPOINT까지만 롤백이 실행되었습니다. 그 결과 첫 번재 데이터는 그대로 남고,
 SAVEPOINT 후에 실행된 데이터 입력은 삭제되었습니다.

 

 

 

숫자함수(Number Functions)

 

 

숫자함수(Number Functions)



ABS(n)


ABS함수는 절대값을 계산하는 함수입니다.

SQL>SELECTABS(-10)Absolute FROM dual ;

Absolute
--------
       10



CEIL(n)


CEIL함수는 주어진 값보다는 크지만 가장 근접하는 최소값을 구하는 함수입니다.

SQL>SELECTCEIL(10.1)TEST FROM dual ;

  TEST
-------
      11

SQL>SELECTCEIL(-10.1)TEST FROM dual ;

   TEST
-------
     -10



EXP(n)


EXP함수는 주어진 값의 e의 승수를 나타냅니다.
e는 2.171828183..입니다.



FLOOR(n)

FLOOR함수는 주어진 값보다 작거나 같은 최대 정수값을 구하는 함수입니다.
CEIL 함수와 비교해 보세요.

SQL>SELECTFLOOR(10.1)TEST FROM dual ;

    TEST
 -------
       10

SQL>SELECTFLOOR(-10.1)TEST FROM dual ;
   
    TEST
-------
      -11



LN(n)


LN함수는 주어진 값의 자연로그 값을 반환합니다.



MOD(m, n)


MOD함수는 m을 n으로 나누어 남은 값을 반환한다. n이 0일 경우 m을 반환합니다.

SQL>SELECTMOD(9, 4)TEST FROM dual ;

    TEST
  -------
         1



POWER(m, n)


POWER함수는 m의 n승 값을 계산합니다.

SQL>SELECTPOWER(4, 2)TEST FROM dual ;
       
      TEST
   -------
         16



ROUND(n, [m])


ROUND함수는 n값의 반올림을 하는 함수로 m은 소숫점 아래 자릿수를 나타낸다.

SQL>SELECTROUND(192.123, 1)TEST FROM dual ;

      TEST
   -------
      192.1

SQL>SELECTROUND(192.123, -1)TEST FROM dual ;

     TEST
   -------
       190



SIGN(n)


SIGN함수는 n<0일 경우 -1DFM N=0일 경우 0을 N>0일 경우 1을 반환합니다.



SQRT(n)


SQRT함수는 n값의 루트값을 계산한다. n은 양수여야 합니다.



TRUNC(n, m)


 TRUNC함수는 n값을 m 소숫점 자리로 반내림한 값을 반환합니다.
 ROUND 함수와 비교해 보세요..

SQL>SELECTTRUNC(7.5597, 2)TEST FROM dual ;

    TEST
 -------
     7.55

SQL>SELECTTRUNC(5254.26, -2 )TEST FROM dual ;

    TEST
 -------
     5200



Oracle9i Number Functions
CEIL
COS
COSH
EXP
FLOOR
LN
LOG
MOD
POWER
ROUND (number)
SIGN
SIN
SINH
SQRT
TAN
TANH
TRUNC (number)
WIDTH_BUCKET

 

 

문자열 처리 함수(Character Functions)

 

문자열 처리 함수(Character Functions)


CONCAT(char1, char2)

CONCAT 함수는 Concatenation의 약자로 두 문자를 결합하는 역할을 합니다.
"
||" 연산자와 같은 역할을 합니다.

SQL>SELECTCONCAT('Oracle', ' Korea')NAME FROM dual ;

                NAME
   -------------
   Oracle Korea



INITCAP(char)


주어진 문자열의 첫 번째 문자를 대문자로 변환시켜 줍니다.

SQL>SELECTINITCAP('kim jung sick')NAME FROM dual ;

             NAME
 -------------
  Kim jung sick



LOWER(char)


문자열을 소문자로 변환 시켜 줍니다.


UPPER(char)

문자열을 대문자로 변환 시켜 줍니다.

SQL>SELECTLOWER('KIM JUNG SICK')NAME FROM dual ;

            NAME
-------------
  kim jung sick

SQL>SELECTUPPER('kim jung sick')NAME FROM dual ;

            NAME
--------------
KIM JUNG SICK



LPAD(char1, n [,char2])


  왼쪽에 문자열을 끼어 놓는 역할을 합니다. n은 반환되는 문자열의 전체 길이를 나타내며, char1의 문자열이 n보다 클 경우 char1을 n개 문자열 만큼 반환합니다.

SQL>SELECTLPAD('JUNG-SICK', 10, '*')NAME FROM dual ;

          NAME
------------
 *JUNG-SICK



RPAD(char1, n [,char2])


LPAD와 반대로 오른쪽에 문자열을 끼어 놓는 역할을 합니다.

SQL>SELECTRPAD('JUNG-SICK', 10, '*')NAME FROM dual ;

          NAME
------------
  JUNG-SICK*



SUBSTR(char, m ,[n])


  SUBSTR함수를 이용하여 m 번째 자리부터 길이가 n개인 문자열을 반환한 합니다. m이 음수일 경우에는 뒤에서 M번째 문자부터 반대 방향으로 n개의 문자를 반환합니다.

SQL>SELECTSUBSTR('JUNG-SICK', 3, 3)NAME FROM dual ;

          NAME
-----------
            NG-

-- 뒤에서부터 자를
SQL>SELECTSUBSTR('JUNG-SICK', -3, 3)NAME FROM dual ;

        NAME  
-----------
          ICK



LENGTH(char1)


문자열의 길이를 리턴 합니다.

SQL>SELECTLENGTH('JUNG-SICK') TESTFROM dual ;

      TEST
   ----------
           9



REPLACE(char1, str1, str2)


REPLACE는 문자열의 특정 문자를 다른 문자로 변환 합니다.


SQL> SELECTREPLACE('JACK and JUE','J','BL')"Changes" FROM DUAL;
 
Changes
--------------
BLACK and BLUE
 
 
 
SQL> SELECTREPLACE('JACK and JUE','JA','BL')"Changes" FROM DUAL
 
Changes
------------
BLCK and JUE
 
 
-- 대소문자를 구분한다는 것을 알수 있습니다.
SQL>SELECTREPLACE('JACK and JUE','j','BL')"Changes" FROM DUAL
 
Changes
------------
JACK and JUE



INSTR

 -문자열이 포함되어 있는지를 조사하여 문자열의 위치를 반환합니다.
 -지정한 문자열이 발견되지 않으면 0이 반환 됩니다.
 


-- 지정한 문자 OK가 발견되지 않아서 0이 반환 됩니다.
SQL>SELECTINSTR('CORPORATE FLOOR','OK') "Instring" FROM DUAL
 
  Instring
----------
         0


-- OR이 있는 위치 2를 반환 합니다. 왼쪽부터 비교를 한다는 것을 알 수 있습니다.
SQL>SELECTINSTR('CORPORATE FLOOR','OR') "Instring" FROM DUAL
 
  Instring
----------
         2
 

-- 왼쪽에서 3번째부터 시작을 해서 비교를 합니다. 2번째 OR의 위치가 반환 됩니다.
SQL>SELECTINSTR('CORPORATE FLOOR','OR',3) "Instring" FROM DUAL 
 
  Instring
----------
         5


-- 왼쪽에서3번째부터 시작을 해서 비교를 하는데  OR이두 번째 검색되는 지점의 위치를 반환 합니다.
SQL> SELECTINSTR('CORPORATE FLOOR','OR',3, 2) "Instring" FROM DUAL;
 
  Instring
----------
       14
 



TRIM


 -특정한 문자를 제거 합니다.  
 -제거할 문자를 입력하지 않으면 기본적으로 공백이 제거 됩니다.
 - 리턴값의 데이터타입은 VARCHAR2 입니다.
 


-- 0을 제거 합니다.
SQL>SELECTTRIM(0FROM0009872348900)  "TRIM Example" FROM DUAL;
 
TRIM Example
------------
98723489
 
 
-- 어떤 문자도 입력하지 않으면 기본적으로 공백이 제거 됩니다.  
-- TRIM을 사용한 위에 예제와 사용하지 않은 아래 예제의 결과 값이 다르게 나오는 것을 알 수 있습니다.

SQL>SELECTNVL(TRIM('  '),'공백') "TRIM Example"  FROM DUAL
 
TRIM Example
------------
공백
 
 
SQL>SELECTNVL('  ','공백') "TRIM Example" FROM DUAL
 
TRIM Example
------------
 


 



LTRIM

SQL>SELECTLTRIM('xyxXxyLAST WORD','xy') "LTRIM example"  FROM DUAL;
 
LTRIM example
------------
XxyLAST WORD
 
 
RTRIM

SQL>SELECTRTRIM('BROWNINGyxXxy','xy') "RTRIM example"     FROM DUAL;

RTRIM examp
-----------
BROWNINGyxX

Character Functions
CHR
CONCAT
INITCAP
LOWER
LPAD
LTRIM
NLS_INITCAP
NLS_LOWER
NLSSORT
NLS_UPPER
REPLACE
RPAD
RTRIM
SOUNDEX
SUBSTR
TRANSLATE
TREAT
TRIM
UPPER
ASCII
INSTR
LENGTH

날짜 처리 함수(Date Functions)

 

LAST_DAY(d)

LAST_DAY함수는 달의 마지막 날의 날짜를 반환합니다

SQL>SELECT SYSDATE TODAY,LAST_DAY(SYSDATE) LASTDAYFROM dual ;

         TODAY             LASTDAY
-----------------------------
05-JUN-2000       30-JUN-2000        

 오늘이 6월 5일이니깐요 6월달의 마지막 날30일을 반환합니다.



ADD_MONTHS(a, b)


ADD_MONTHS 함수는 a의 날짜에 b의 달을 더한 값을 반환 합니다.

SQL>SELECT TO_CAHR(ADD_MONTHS(SYSDATE,3),'RRRR/MM/DD' LASTDAY)  "date"
        FROM dual ;

      date
------------
  2000/09/05       오늘이 6월5일 이니깐요. 3개월이 더해진 9월 5일이 반환됩니다.



MONTH_BETWEEN(a1, a2)


MONTH_BETWEEN은 a1과 a2 사이의 달의 수를NUMBER형 타입으로 반환합니다.

SQL>SELECTMONTHS_BETWEEN(TO_DATE('2000/06/05') , TO_DATE('2000/09/23'))  "Date"   
        FROM dual ;

            Date
  ----------------
         -3.880635           달사이의 간격을 숫자형으로 반환합니다.



ROUND(d[,F])


ROUND 함수는 F에 지정된 단위로 반올림 합니다, F가 연도라면 연도 단위로 반올림 합니다.

SQL>SELECTROUND(TO_DATE('1998/09/11'), 'YEAR')  FROM dual ;

    ROUND(TO_
--------------
       99-01-01


SQL>SELECTROUND(TO_DATE('1998/04/11'), 'MONTH') FROM dual ;

    ROUND(TO_
---------------
       98-04-01

SQL>SELECTROUND(TO_DATE('1998/04/11'), 'DAY')  FROM dual ;

    ROUND(TO_
 ---------------
       98-04-11     


 ☞ 날짜에 대한 산술 연산

연  산

결과치

사  용  목  적

날짜 + 숫자

날짜

  특정한 날로부터 며칠 후의 날짜 계산

날짜 - 숫자

날짜

  특정한 날로부터 며칠 전의 날짜 계산

날짜 - 날짜

숫자

  두 날짜 사이의 차이를 숫자로 계산

    Datetime Functions

    ADD_MONTHS
    CURRENT_DATE
    CURRENT_TIMESTAMP
    DBTIMEZONE
    EXTRACT (datetime)
    FROM_TZ
    LAST_DAY
    LOCALTIMESTAMP
    MONTHS_BETWEEN
    NEW_TIME
    NEXT_DAY
    NUMTODSINTERVAL
    NUMTOYMINTERVAL
    ROUND (date)
    SESSIONTIMEZONE
    SYS_EXTRACT_UTC
    SYSDATE
    SYSTIMESTAMP
    TO_DSINTERVAL
    TO_TIMESTAMP
    TO_TIMESTAMP_TZ
    TO_YMINTERVAL
    TRUNC (date)
    TZ_OFFSET

     


     

    ★ 변환 함수(Conversion Functions)

     

    TO_CHAR

    TO_CHAR함수는 DATE형, NUMBER형을 VARCHAR2형으로 바꺼 줍니다.

    SQL>SELECTTO_CHAR(SYSDATE, 'MONTH') CHARTESTFROM dual ;

           CHARTEST
     --------------
                 JUNE

    오늘이 6월 10일 이니깐요.. 오늘의 달인 6월이 찍힘니다.

    SQL>SELECTTO_CHAR(SYSDATE) CHARTESTFROM dual ;

           CHARTEST
     --------------
              00/06/10

    오늘이 6월 10일 이니깐요.. 오늘의 날짜가 문자형으로 찍힙니다.



    TO_DATE


    TO_DATE함수는 CHAR, VARCHAR2형을 DATE 타입으로 변환합니다.

    SQL>SELECTTO_DATE('2000/06/16','RRRR/MM/DD')FROM dual ;

           TO_DATE(
       ------------  
          2000/06/16

    '2000/06/16'문자열이 날짜형으로 변합니다



    TO_NUMBER


    TO_NUMBER함수는 CHAR, VARCHAR2의 데이터 타입을 숫자형식으로 변환합니다.

    SQL>SELECTTO_NUMBER('1210616')FROM dual ;

        TO_NUMBER(
        --------------
                 1210616
     
    '1210616'문자열이 숫자형으로 변합니다

    Conversion Functions
    ASCIISTR
    BIN_TO_NUM
    CAST
    CHARTOROWID
    COMPOSE
    CONVERT
    DECOMPOSE
    HEXTORAW
    NUMTODSINTERVAL
    NUMTOYMINTERVAL
    RAWTOHEX
    RAWTONHEX
    ROWIDTOCHAR
    ROWIDTONCHAR
    TO_CHAR (character)
    TO_CHAR (datetime)
    TO_CHAR (number)
    TO_CLOB
    TO_DATE
    TO_DSINTERVAL
    TO_LOB
    TO_MULTI_BYTE
    TO_NCHAR (character)
    TO_NCHAR (datetime)
    TO_NCHAR (number)
    TO_NCLOB
    TO_NUMBER
    TO_SINGLE_BYTE
    TO_YMINTERVAL
    TRANSLATE ... USING
    UNISTR

     

     

     

    General Functions

     

    NVL

    -NVL 함수는NULL값을 다른 값으로 바꿀 때쓰입니다.
    -
    모든 데이터 타입에 적용가능합니다.
    - 전환되는 값의 데이터 타입을 일치시켜야 합니다.

    SQL>SELECT empno,NVL(comm, 0) 
            FROM  emp  
            WHERE deptno = 30;

             EMPNO  NVL(COMM,0)
           ----------     -----------
              7499              300
              7521              500
              7654             1400
              7698                0
              7844                0
              7900                0

    Commsion이 없는 사원에 대해 0으로 바꾸어서 출력합니다.


    DECODE


    DECODE 함수는 데이터 들을 다른 값으로 바꾸어 줍니다.
    형식 DECODE(VALUE, IF1, THEN1, IF2, THEN2...)
    VALUE 값이 IF1일경우에 THEN1값으로 바꾸어 주고 VALUE값이 IF2일경우에는 THEN2값으로 바꾸어 줍니다.

     

     

    SQL> SELECT deptno,
                        DECODE(deptno,10, 'ACCOUNTING' ,
                                                 20, 'RESEARCH' ,
                                                 30, 'SALES' ,
                                                 40, 'OPERATIONS')
              FROM emp ;

         DEPTNO  DECODE(DEP
         ---------- ----------
            20        RESEARCH
            30        SALES
            30        SALES
            20        RESEARCH
            30        SALES
            30        SALES
            10        ACCOUNTING
            20        RESEARCH

    부서가 10번이면 'ACCOUNTING'를 20번이면 'RESEARCH'를
    30번이면 'SALES'를 40번이면 'OPERATIONS'를 출력하는 예제 입니다.

    기타 함수들

     

    DUMP: DUMP는 바이트 크기와 해당 데이터 타입 코드를 반환합니다..

    SQL>SELECT ename,DUMP(ename, 16) "16진수"
            FROM emp
            WHERE ename = 'ALLEN'

    ename   16진수
    ------  ------------------------------
    ALLEN   Typ=1 Len=5: 41,4c,4c,45,4e

    만약에 16대신 8을 넣으면 8진수로, 10를 넣으면 10진수로 변환이 됩니다..
    16, 10, 8, 17이 올수 있는데요 17은 단일 문자열을 리턴한데용..
    한번 테스트 해보세용
    Len은 ename의 해당 byte수고요..  
    Typ은 1만 나오던데..무엇을 의미하는지 잘 모르겠네용


    GREATEST: GREATEST함수는 검색값 중에서 가장 큰 값을 반환 합니당..

    SQL>SELECTGREATEST(10, 100, 5, -7) FROM DUAL;

    GREATEST(10,100,5,-7)
    ---------------------
                      100        --가장 큰 수는 100이겠죠..



    LEAST
    : LEAST함수는 GREATEST함수와 반대로 가장 작은 값을 반환합니다.  

    SQL>SELECTLEAST(10, 100, 5, -7) FROM DUAL;  

    LEAST(10,100,5,-7)
    ------------------
                    -7



    UID: 현재 사용자의 유일한 ID번호를 리턴합니다.
    USER: 현재 오라클을 사용하는 사용자를 VARCHAR2형식으로 리턴합니다.

    SQL> SELECTUSER, UIDFROM DUAL;

    USER          UID
    ------------- ------
    SCOTT         32



    USERENV: USERENV 함수는 현재 세션의 환경 정보를 반환합니다.
      -
    ENTRYID: 사용 가능한 Auditing entry Identifier를 반환합니다.
      -
    LABEL: 현재 세션의 Label을 반환합니다.
      -
    LANGUAGE: 현재 세션에서 사용중인 언어와 테리토리 값을 반환합니다.
      -
    SESSIONID: Auditing(감사) Session ID를 반환 합니다.
      -
    TERMINAL: 현재 세션 터미널의 OS ID를 반환 합니다.  

    SQL> SELECTUSERENV('LANGUAGE') FROM DUAL;

    USERENV('LANGUAGE')
    ------------------------
    KOREAN_KOREA.KO16KSC5601



    VSIZE: 해당 문자의 BYTE수를 반환 합니다.
                 해당 문자가 NULL이면 NULL값이 반환 됩니다.

    SQL> SELECTVSIZE(ename), ename
              FROM emp
              WHERE deptno = 30;

    VSIZE(ENAME) ENAME
    ------------ ----------
               5            ALLEN
               4            WARD
               6            MARTIN
               5            BLAKE


    Miscellaneous Single-Row Functions
    BFILENAME
    COALESCE
    DECODE
    DEPTH
    DUMP
    EMPTY_BLOB, EMPTY_CLOB
    EXISTSNODE
    EXTRACT (XML)
    EXTRACTVALUE
    GREATEST
    LEAST
    NLS_CHARSET_DECL_LEN
    NLS_CHARSET_ID
    NLS_CHARSET_NAME
    NULLIF
    NVL
    NVL2
    PATH
    SYS_CONNECT_BY_PATH
    SYS_CONTEXT
    SYS_DBURIGEN
    SYS_EXTRACT_UTC
    SYS_GUID
    SYS_TYPEID
    SYS_XMLAGG
    SYS_XMLGEN
    UID
    UPDATEXML
    USER
    USERENV
    VSIZE
    XMLAGG
    XMLCOLATTVAL
    XMLCONCAT
    XMLFOREST
    XMLSEQUENCE
    XMLTRANSFORM

     

    Group Function의 종류

     

    ☞ 그룹함수란 ?

     - 그룹 함수란여러 행 또는 테이블 전체의 행에 대해 함수가 적용되어 하나의 결과값을 가져오는
       함수를 말합니다..
     
     -GROUP BY절을 이용하여그룹 당 하나의 결과가 주어지도록 그룹화 할 수 있습니다.
     
     -HAVING절을 사용하여그룹 함수를 가지고 조건비교를 할 수 있습니다.

     -COUNT(*)를 제외한 모든 그룹함수는 NULL값을 고려하지 않습니다.

     -MIN, MAX그룹함수는모든 자료형에 대해서 사용 할 수 있습니다.



    그룹 함수의 종류

    COUNT

    COUNT 함수는 검색된 행의 수를 반환합니다.

    SQL>SELECTCOUNT(deptno) FROM DEPT ;

         COUNT(DEPTNO)
                 -------------
                            4          
    검색된 행의 총 수 4개를 반환합니다. 즉 4개의 부서가 존재합니다.


    MAX


    MAX 함수는 컬럼중의 최대값을 반환합니다.

    SQL>SELECTMAX(sal)  salary FROM  emp ;

            SALARY
           ----------
                 5000          sal컬럼중에서 제일 큰값을 반환합니다. 즉 가장 큰 급여를 반환합니다.


    MIN


    MIN 함수는 컬럼중의 최소값을 반환합니다.

    SQL>SELECTMIN(sal) salary FROM  emp ;

                 SALARY
                ----------
                        800          sal컬럼중에서 가장 작은 값 반환합니다. 즉 가장 적은 급여를 반환합니다


    AVG


    AVG 함수는 평균값을 반환합니다.

    SQL>SELECTROUND(AVG(sal),1)  salary FROM  emp WHERE deptno = 30

                SALARY
               ----------
                    1566.7           30부서 사원의 평균 급여를 소수점 1자리 이하에서 반올림해서 보여줍니다.


    SUM


    SUM 함수는 검색된 컬럼의 합을 반환합니다.

    SQL>SELECTSUM(sal)salary FROM  emp WHERE deptno = 30;

             SALARY
           ----------
                  9400              30부서 사원의 급여 합계를 보여줍니다.


    STDDEV


    STDDEV 함수는 표준편차를 반환합니다.

    SQL> SELECTROUND(STDDEV(sal),3)salary FROM  emp WHERE deptno = 30 ;

                SALARY
              ----------
                  668.331          30부서 사원의 급여 표준편차를 반환합니다.

     

     

     

    Group By절과 Having절

     

    GROUP BY

     -  특정한 컬럼의 테이터 들을 다른 데이터들과 비교해유일한 값에 따라 무리를 짓습니다.

     -GROUP BY절을 사용하여한 테이블의 행들을 원하는 그룹으로 나눕니다.

     - Column명을 GROUP함수와 SELECT절에 사용하고자 하는 경우 GROUP BY뒤에 Column명을 
       추가 합니다.
     


    SQL>SELECTb.deptno, COUNT(a.empno)
           FROM emp a, dept b
           WHERE a.deptno = b.deptno
          GROUP BY
    b.deptno

    DEPTNO   COUNT(*)
    -------      ----------
         10          3
         20          5
         30          6

    부서별로 그룹을 지은 검색 결과 값이며
    부서별로 사원수를 보여줍니다. .


    ☞ Group By 예제

    scott/tiger유저로 접속해서 실행하세요..

    예제1) 부서별로 그룹하여  부서번호, 인원수, 급여의 평균, 급여의 합을 구하여 출력 하여라.
     
    SQL>SELECT deptno,COUNT(*),ROUND(AVG(sal)) "급여평균", ROUND(SUM(sal)) "급여합계"
            FROM emp
            GROUP BYdeptno;
     
     
       DEPTNO   COUNT(*)   급여평균   급여합계
    --------- ---------- ---------- ----------
           10             3             2998         8995
           20             5             2175        10875
           30             6             1567         9400



    예제2)업무별로 그룹하여  업무, 인원수,  평균 급여액, 최고 급여액, 최저 급여액 및 합계를 출력하라.
     
    SQL>SELECT job, COUNT(empno) "인원수", AVG(sal) "평균급여액",
                       MAX(sal) "최고급여액", MIN(sal) "최저급여액", SUM(sal) "급여합계"
            FROM emp
            GROUP BYjob
     
    JOB           인원수 평균급여액 최고급여액 최저급여액   급여합계
    --------- ---------- ---------- ---------- ---------- ----------
    ANALYST            2        3000        3000         3000       6000
    CLERK                4      1037.5        1300          800       4150
    MANAGER           3        2840        2975         2695       8520
    PRESIDENT         1        5000        5000         5000       5000
    SALESMAN          4        1400        1600         1250       5600

     



    GROUP BY의 HAVING 절

     -  WHERE절에 GROUP Function을 사용할 수 없습니다.

     -  HAVING절은 GRUOP 함수를 가지고 조건비교를 할 때 사용합니다.

     -  WHERE → GRUOP BY → HAVING → ORDER BY순으로  쿼리문이 와야 됩니다.
     

    HAVING절 예제


    예제1) 사원수가 5명이 넘는 부서의 부서명과 사원수를 출력해라

    SQL>SELECT b.dname, COUNT(a.empno)
            FROM emp a, dept b
           WHEREa.deptno = b.deptno
           GROUPBY dname
            
    HAVINGCOUNT(a.empno) > 5

    DNAME                                    COUNT(A.EMPNO)
    -------------------------------      --------------
    RESEARCH                                                6
    SALES                                                      6


    예제2)
    전체 월급이 5000을 초과하는 각 업무에 대해서 업무와 월급여 합계를 출력하여라.
             단 판매원은 제외하고 월 급여 합계로 내림차순 정렬 하여라.
     
    SQL>SELECT job, SUM(sal) "급여합계"    -- 업무와 급여 합계를 출력
            FROM emp  
            WHERE job NOT IN ('SALES')          -- 판매원은 제외
            GROUP BY job                             -- 업무별로 Group By 
            HAVING SUM(sal) > 5000               -- 전체 월급이 5000을 초과하는
            ORDER BY SUM(sal) DESC;            -- 월급여 합계로 내림차순 정렬
     
     
    JOB         급여합계
    --------- ----------
    MANAGER        8520
    ANALYST         6000
    SALESMAN       5600

     

     

     

     

    인덱스(Index)

     


    ※ 인덱스란?


      인덱스는 테이블이나 클러스트에서 쓰여지는 선택적인 객체로서,오라클 데이터베이스 테이블내의
    원하는 레코드를 빠르게 찾아갈 수 있도록 만들어진 데이터 구조
    입니다.  

    자동 인덱스:프라이머리 키또는uinque 제한 규칙에 의해자동적으로 생성되는 인덱스입니다.

    수동 인덱스:CREATE INDEX명령을 실행해서 만드는 인덱스들 입니다.  

    ※  Index를 생성하는 것이 좋은 Column

    WHERE절이나 join조건 안에서 자주 사용되는 컬럼
    null 값이 많이 포함되어 있는 컬럼
    WHERE절이나 join조건에서 자주 사용되는 두 개이상의 컬럼들


    ※  다음과 같은 경우에는 index 생성이 불필요 합니다.

    table이 작을 때
    테이블이 자주 갱신될 때

    ※  오라클 인덱스는B-tree(binary search tree)에 대한 원리를 기반으로 하고 있습니다.

      B-tree인덱스는 컬럼안에 독특한 데이터가 많을 때 가장 좋은 효과를 냅니다.

    이 알고리즘 원리는

     ① 주어진 값을 리스트의 중간점에 있는 값과 비교합니다.     
         만약 그 값이 더 크면 리스트의 아래쪽 반을 버립니다.
         만약 그 값이 더 작다면 위쪽 반을 버립니다.

     ② 하나의 값이 발견될 때 까지 또는 리스트가 끝날 때까지 그와 같은 작업을 다른 반쪽에도
         반복합니다.



     ※  인덱스는 B-tree 구조를 가지며 크게 다음 네 가지로 분류될수 있습니다.


    Bitmap 인덱스

      비트맵 인덱스는 각 컬럼에 대해적은 개수의 독특한 값이 있을 경우에 가장 잘 작동합니다.
      그러므로 비트맵 인덱스는 B-tree 인덱스가 사용되지 않을 경우에서 성능을 향상 시킵니다.
      테이블이 매우 크거나 수정/변경이 잘 일어나지 않는 경우에 사용할수 있습니다.

    SQL>CREATE BITMAP INDEXemp_deptno_indx
            ONemp(deptno);


    Unique 인덱스

      Unique 인덱스는 인덱스를 사용한 컬럼의 중복값들을 포함하지 않고 사용할 수 있는 장점이 있습니다.
      프라이머리키 와 Unique 제약 조건시 생성되는 인덱스는 Unique 인덱스입니다.

    SQL>CREATE UNIQUE INDEXemp_ename_indx
            ON emp(ename);


    Non-Unique 인덱스

       Non-Unique 인덱스는 인덱스를 사용한 컬럼에 중복 데이터 값을 가질수 있습니다.

    SQL>CREATE INDEX dept_dname_indx
            ON dept(dname);


    결합 (Concatenated(=Composite)) 인덱스

       복수개의 컬럼에 생성할 수 있으며 복수키 인덱스가 가질수 있는 최대 컬럼값은 16개입니다

    SQL>CREATE UNIQUE INDEXemp_empno_ename_indx
            ON emp(empno, ename);


    ※  인덱스의 삭제

      
     - 인덱스의 구조는 테이블과 독립적이므로인덱스의 삭제는 테이블의 데이터에는 아무런 영향도 미치지
        
    않습니다.

     - 인덱스를 삭제하려면INDEX의 소유자이거나 DROP ANY INDEX권한을 가지고 있어야 합니다.

     -INDEX는 ALTER를 할 수 없습니다.

    SQL>DROP INDEXemp_empno_ename_indx ;


    ※  인덱스에 대한 정보는USER_INDEXES뷰 또는USER_IND_COLUMNS뷰를 통해 검색할 수
          있습니다.

    SQL> SELECTindex_name , index_type
            FROMUSER_INDEXES
            WHEREtable_name='EMP';

    INDEX_NAME                        INDEX_TYPE
    ---------------------------     -----------
    EMP_DEPTNO_INDX                BITMAP
    EMP_PK_EMPNO                    NORMAL

     

     

    ★ VIEW 테이블

     

     

    뷰란?

     ◈ 뷰는하나의 가상 테이블라 생각 하시면 됩니다.

     ◈ 뷰는 실제 데이터가 저장 되는 것은 아니지만뷰를 통해 데이터를 관리할수 있습니다.

     ◈ 뷰는 복잡한query를 통해 얻을 수 있는 결과를 간단한 query를 써서 구할 수 있게 합니다.

     ◈ 한개의 뷰로 여러 테이블에 대한 데이터를 검색할 수 있습니다.

     ◈ 특정 평가기준에 따른 사용자 별로 다른 데이터를 액세스할 수 있도록 합니다.



    뷰의 제한 조건.


     ◈ 테이블에NOT NULL로만든 컬럼들이.뷰에 다 포함이 되 있어야 됩니다.

     ◈ 그리고ROWID, ROWNUM, NEXTVAL, CURRVAL등과 같은 가상컬럼에 대한 참조를
         포함하고 있는 뷰에는어떤 데이터도 Insert할 수 없습니다.

     ◈ WITH READ ONLY옵션을 설정한 뷰도데이터를 갱신할수 없습니다.

     ◈ WITH CHECK OPTION을 설정한 뷰는뷰의 조건에 해당되는 데이터만 삽입, 삭제,
        
    수정을 할수 있습니다.



      

    사용자 삽입 이미지

      
    사용자 삽입 이미지

     
      -FORCE:기본 테이블 유무에 관계없이 VIEW를 생성

      -WITH CHECK OPTION:VIEW에 의해 엑세스될 수 있는 행만이 입력되거나 변경될 수 있음을
                                           지정 합니다.

      -WITH READ ONLY:SELECT만 가능한 VIEW의 생성

      - VIEW를 정의하는 질의어에는ORDER BY절을 사용 할 수 없습니다.

      -함수를 사용한 컬럼은 반드시 ALIAS를 지정해야 합니다.

     

    SQL> CREATE OR REPLACE VIEWName_Query
            AS
               SELECT a.ename, b.dname
               FROM  emp a, dept b
               WHERE a.deptno = b.deptno
                    AND b.deptno = 20


    view created.

    이렇게 뷰를 생성해 놓고 뷰를 통해 검색을 하면 됩니다.

    SQL>SELECT * FROMName_Query;

    ENAME                DNAME
    -------------------- ----------
    SMITH                RESEARCH
    JONES                RESEARCH
    SCOTT               RESEARCH
    ADAMS               RESEARCH
    FORD                 RESEARCH



    WITH CHECK OPTION


    view 의 조건식을 만족하는 데이터만 INSERT 또는 UPDATE가 가능하도록 하는 옵션입니다.


    SQL> CREATE OR REPLACE VIEWCheck_Option
            AS
               SELECT empno, ename, deptno
               FROM  emp
              WHERE deptno = 10
            WITH CHECK OPTION

    view created.

    SQL> INSERT INTO Check_Option(empno, ename, deptno)
            VALUES (10005, 'jain',30);

    INSERT INTO Check_Option(empno, ename, deptno)
                *
    1행에 오류:
    ORA-01402: 뷰의 WITH CHECK OPTION의 조건에 위배 됩니다
    부서 번호가 10인 사원만 INSERT, UPDATE할 수 있습니다.
     



    WITH READ ONLY


    SELECT만 가능한 VIEW를 생성합니다.

    SQL> CREATE OR REPLACE VIEWRead_Only
            AS
               SELECT empno, ename, deptno
               FROM  emp
               WHERE deptno = 10
           WITH READ ONLY

    view created.

    단순히 읽기 만 할수 있고 데이터는 입력하지 못합니다.



    VIEW에 대한 DML문 사용 규칙


      VIEW가 다음 사항을 포함하는 경우행의 삭제 불가
       - JOIN조건, 그룹함수, GROUP BY절, DISTINCT명령

     
     VIEW가 다음 사항을 포함하는 경우데이터 수정 불가
       - JOIN조건, 그룹함수, GROUP BY절, DISTINCT명령, 식으로 정의된 컬럼(EX SAL * 0.1)

     
     VIEW가 다음 사항을 포함하는 경우데이터 추가 불가
       - JOIN조건, 그룹함수, GROUP BY절, DISTINCT명령, 식으로 정의된 컬럼,
         VIEW에 선택되지 않는 NOT NULL컬럼
     


    뷰의 정보 조회

    USER_VIEWS데이터 사전을 통해서 뷰에 대한 정보를 조회 할 수 있습니다.

    SQL>SELECT view_name , text
           FROM  USER_VIEWS;


    뷰의 삭제

    SQL>DROP VIEWRead_Only;

          view dropped.

     

     

    SEQUENCE(시퀀스)

     


     시퀀스란?


    유일(UNIQUE)한 값을 생성해주는 오라클 객체입니다.

    ◈ 시퀀스를 생성하면기본키와 같이 순차적으로 증가하는 컬럼을 자동적으로 생성할수 있습니다.

    ◈ 보통 primary key 값을 생성하기 위해 사용합니다.

    ◈ 메모리에 Cache되었을 때 Sequence 값의 액세스 효율이 증가 합니다.

    ◈ Sequence는 테이블과는 독립적으로 저장되고 생성됩니다. 따라서 하나의 sequence를
        여러 테이블에서 쓸 수 있습니다.
     



    시퀀스 생성


    사용자 삽입 이미지

    사용자 삽입 이미지


    START WITH:시퀀스의 시작 값을 지정합니다. n을 1로 지정하면 1부터 순차적으로
                         시퀀스번호가 증가 합니다.

    INCREMENT BY:시퀀스의 증가 값을 말합니다. n을 2로 하면 2씩 증가합니다.
                            START WITH를 1로 하고 INCREMENT BY를 2으로 하면 1, 3, 5,7,.. 이렇게
                           시퀀스  번호가 증가하게 됩니다.

    MAXVALUE n | NOMAXVALUE : MAXVALUE는시퀀스가 증가할수 있는 최대값을 말합니다.                                             NOMAXVALUE는 시퀀스의 값을 무한대로 지정합니다.

    MINVALUE n | NOMINVALUE : MINVALUE는시퀀스의 최소값을 지정합니다.
                                          기본값은 1이며, NOMINVALUE를 지정할 경우 최소값은 무한대가 됩니다

     


     SQL>CREATE SEQUENCEemp_seq
            START WITH1
            INCREMENT BY1
            MAXVALUE100000 ;

          sequence created.

         시작 값이 1일고 1씩 증가하고, 최대값이 100000만이 되는 시퀀스를 생성했습니다.


     SQL>INSERT INTO emp(empno, ename, hiredate ) VALUES(emp_seq.NEXTVAL, 'julia' , sysdate);

        empno는 컬럼값을 입력할 때 일일이 다음 값을 기억하지 않아도NEXTVAL을 사용하여
        자동으로 입력할 수 있습니다.

      CURRVAL:현재 값을 반환 합니다. .
       NEXTVAL:현재 시퀀스값의 다음 값을 반환 합니다.


     SQL>SELECTemp_seq.CURRVALFROM DUAL ;

            CURRVAL
            ---------
                      1

     SQL>SELECTemp_seq.NEXTVALFROM DUAL ;

           NEXTVAL
         ---------
                     2
     



    사용규칙 


      ◈NEXTVAL, CURRVAL을 사용할 수있는경우
        - subquery가 아닌 select문
        - insert문의 select절
        - insert문의 value절
        - update문의 set절


      ◈NEXTVAL, CURRVAL을 사용할 수없는경우
        - view의 select절
        - distinct 키워드가 있는 select문
        - group by, having, order by절이 있는 select문
        - select, delete, update의 subquery
        - create table, alter table 명령의 default값


    시퀀스의 수정 및 삭제


    사용자 삽입 이미지

    사용자 삽입 이미지


    START WITH는 수정할수 없습니다.
    START WITH 절이 없다는 점을 빼고는 CREATE SEQUENCE와 같습니다.
     


     SQL>ALTER SEQUENCEemp_seq
             INCREMENT BY2
             CYCLE;

          sequence altered.

          2씩 증가하고, 최대값을 넘으면 다시 처음부터 순환하도록 수정하였습니다.


          DROP 문을로 필요하지 않은 시퀀스는 삭제 할수 있습니다.

     SQL>DROP SEQUENCEPRD_SEQ;
            sequence dropped.

     

     

     

    SYNONYM(동의어)

     

    시노님은 오라클 객체(테이블, 뷰, 시퀀스, 프로시저)에 대한 대체이름(Alias)를 말합니다.
     
    Synonym은 실질적으로 그 자체가 Object가 아니라 Object에 대한 직접적인 참조 입니다.
     
    시노님을 사용하는 이유는..
     
    데이터베이스의 투명성을 제공하기 위해서 사용 한다고 생각하면 됩니다.
        시노님은 다른 유저의 객체를 참조할 때 많이 사용을 합니다.
     
    ② 만약에 실무에서 다른 유저의 객체를 참조할 경우가 있을 때 시노님을 생성해서 사용을 하면은
        추후에 참조하고 있는 오프젝트가 이름을 바꾸거나 이동할 경우 객체를 사용하는 SQL문을 모두
        다시 고치는 것이 아니라 시노님만 다시 정의하면 되기 때문에 매우 편리 합니다.
     
    객체의 긴 이름을 사용하기 편한 짧은 이름으로 해서  SQL코딩을 단순화 시킬 수 있습니다.
     
    또한 객체를 참조하는 사용자의 오브젝트를 감추 수 있기 때문에 이에 대한 보안을 유지할 수
        있습니다
    .  
       시노님을 사용하는 유저는 참조하고 있는 객체를에 대한 사용자의 object의 소유자, 이름, 서버이름을  모르고 시노님 이름만 알아도 사용 할 수 있습니다.



    Synonyms을 사용하는 경우

     -오브젝트의 실제 이름과 소유자 그리고 위치를 감춤으로써 database 보안을 개선하는데 사용됩니다
     - Object에의 Public Access를 제공 합니다.
     -Remote Database의 Table, View, Program Unit를 위해 투명성을 제공합니다.
     -Database 사용자를 위해 SQL 문을 단순화 할 수 있습니다.


    시노님에는 두가지 종류가 있습니다.  

    Private Synonym 
       - 전용 시노님은특정 사용자만  이용할수 있습니다.
     
    Public Synonym
      - 공용 시노님은 공용 사용자 그룹이 소유하며 그Database에 있는 모든 사용자가 공유 합니다.


     시노님 생성 문법(Syntax)

    사용자 삽입 이미지

    사용자 삽입 이미지


     - PUBLIC : 모든 사용자가 접근 가능한 시노님을 생성 합니다.
                    PUBLIC  시노님의 생성 및 삭제는 DBA만이 할 수 있습니다.


     ※ scott USER의 emp테이블을 test USER가 사용 하는 예제.


     1. 먼저 scott/tiger USER로 접속해서 test USER에게 emp테이블을 조작할 권한을 부여합니다.
     
     SQL>GRANTALLON empTO test;
             권한이 부여되었습니다.

             test user에 대하여 scott의 emp테이블을 조작할 수 있는권한을 부여합니다.
             권한이 있어야 select하거나 update, insert할수 있습니다.



     2. test USER로 접속해 동의어를 생성합니다.

     SQL> connect test/test

     SQL>CREATE SYNONYM scott_empFOR scott.emp ;
             시노님이 생성되었습니다.

              scott USER가 소유하고 있는 emp 테이블에 대해scott_emp라는 일반시노님을 생성했습니다.
              scott 사용자의 emp테이블을test 사용자가 scott_emp라는 동의어로 사용 합니다..

      -- 시노님을 이용한 쿼리
     SQL> SELECT empno,  ename FROM  scott_emp;

     -- 일반 테이블을 쿼리
     SQL> SELECT empno,  ename FROM  scott.emp;
              이 두 쿼리의 결과는 같습니다.

       EMPNO ENAME
    -------- ---------
        7369 SMITH
        7499 ALLEN
        7521 WARD
        7566 JONES
        7654 MARTIN
        7698 BLAKE
              15 개의 행이 선택되었습니다.


     동의어 삭제

     SQL> DROP SYNONYM   scott_emp;
             시노님이삭제되었습니다.

     SQL> SELECT empno,  ename FROM  scott_emp;
             라인 1 에 오류:
             ORA-00942: 테이블 또는 뷰가 존재하지 않습니다

    and
    Oracle 10g에 들어와서 FLASHBACK TABLE이라는 기능이 생겼는데 기존에 drop table로 엉뚱한 테이블을 날려서 가슴졸인 개발자가 많았나보다(실제로 그런일로 고생하는 사람을 보기도 했다.).

    유용한 기능이지만 이런 기능이 있는지 모르는 사람의 경우 table을 drop할때마다 이상한 이름의 테이블이 하나씩 생겨서 당황할 수 도 있을것같다.

    table을 drop하면 'BIN$' 로 시작하는 이상한 이름의 테이블이 생기는데 이 테이블을 drop해보면 다음과같은 메시지를 만나게 된다.

    ORA-38301: can not perform DDL/DML over objects in Recycle Bin


    오라클에 Recycle Bin이 있었나 하고 찾아봤더니 이게 바로 새로생긴 FLASHBACK TABLE이라는 기능이란다.

    show recyclebin명령으로 확인할수가 있는데

    SQL> show recyclebin
    ORIGINAL NAME    RECYCLEBIN NAME                OBJECT TYPE  DROP TIME
    ---------------- ------------------------------ ------------ -------------------
    MEMBER           BIN$7ibiCGZXF4PgMOabUJ0qBQ==$0 TABLE        2005-01-21:11:48:19
    MEMBER           BIN$7hq6upeqF+TgMOabUJ0hlg==$0 TABLE        2005-01-20:21:18:20
    PICTURES         BIN$7ibiCGZLF4PgMOabUJ0qBQ==$0 TABLE        2005-01-21:11:48:18

    MEMBER테이블이 2번 drop되어있고 PICTURES 테이블이 1번 drop되어 있다. 여기서 PICTURES 테이블을 다시 살리고 싶으면

    SQL> FLASHBACK TABLE PICTURES TO BEFORE DROP;
    FLASHBACK COMPLETE. 


    휴지통을 완전히 비우고 싶으면

    SQL> purge recyclebin;

    Recyclebin purged.


    그리고 다음과 같이하면 휴지통에 가지 않고 바로 삭제된다.

    SQL> drop table PICTURES purge;


    좀더 자세한 내용을 원하면여기로....
    and
    리눅스설치및 기초활용1



    기본적인 명령어
    #ls (-l,-a):각 루트상에서 디렉토리 및 파일을 출력한다. 도스의 dir과 같은 명령..
    #pwd 현재 디렉토리경로
    #df :리눅스파티션을 보고자할 때 사용.
    #cd ..상위디렉토리로 이동
    #cd 폴더/해당디렉토리로 이동
    #vi 편집명령어
    #cat 내용출력
    #du -sh 남은 용량확인법
    #chmod 권한설정
    #tar :압축명령(옵션)
    #gzip :이중압축명령(옵션)

    디렉토리 이동명령

    일반적으로 디렉토리나 파일이 많을 경우 자신이 어디에 위치에 있는지 그리고 직접적으로 디렉토리로 다이렉트로 이동해야 하는경우가 많아진다... 디렉토리 이동명령을 통해 바로이동할수있는 것이 숙제
    예) # cd /home 홈디렉토리로 바로이동하기.....
    # ls -l 홈디렉토리 내용살피기
    # cd master1 마스터1의 디렉토리안으로 이동하기...

    목록보기

    목록보기에는 대부분 ls를 사용하는데 여기에도 다양한 옵션으로 다양한 결과물을 볼수가 있다....가장많이 쓰는 명령이니만큼 다양한 특징을 안다면 작업하는데 굉장히 편리할 것이다.

    #ls -l 세로배열로 결과물을 출력해준다....
    #ls -al 가능모든 파일을 결과물로 통해 세로배열로 보여준다.
    #ls -al |more:파일의 내용이 많을 때 한단계씩 보여준다(dos:dir/p)와 같은 효과이다.
    스페이스바를 누르면 다음결과물을 보여주고 Q를 누르면 빠져나간다.
    #ls -l /etc/group:특정파일을 다음과 같은 명령으로 찾아볼 수 있다.
    #ls -F :이명령은 실일파일여부를 확인하는 명령이다. 실행파일일 경우 *이붙어서 나온다
    그밖에 많은 옵션이 있지만 생략한다.(#ls --help)를 보면 여러 가지 옵션을 볼 수 있다.

    디렉토리생성과 삭제

    디렉토리를 생성과 또 삭제하는데 필요한 명령을 알아보자
    대체적으로 생성하는 명령은 mkdir명령을 쓴다.
    특정디렉토리에서 #mkdir kkk라치면 그특정디렉토리하위에 kkk라는 디렉토리가 생성이 된다. ls로 확인을 하여보자.
    또한 특정한 곳에 디렉토리를 생성하고싶은면 이렇게 하면된다.
    #mkdir /home/webmaster/kkk라치면 홈밑에 웹마스터란 방밑에 kkk를 생성한다는 뜻이다.
    디렉토리를 삭제하는 명령또한 동일하다.
    홈디렉토리밑에 kkk란 디렉토리가 있다면 이디렉토리를 삭제하는 방법이다.
    #rmdir kkk라치면 kkk란 디렉토리가 삭제된다.
    #rmdir /home/webmaster/kkk라치면 홈밑에 웹마스터란 방밑에 kkk를 삭제한다는 뜻이다.
    하지만 하위디렉토리에 내용이나 또다른 디렉토리가 있다면 삭제가 되질않는다...
    이때는 rm이란 명령으로 삭제를 한다....옵션 또한 여러 가지가 있지만....
    가장많이 쓰는 명령만 간단히 소개한다.
    #rm -r kkk라치면 먼저 하위디렉토리로 들어가서 지울지여부를 물어본다....삭제하고자한다면 y(yes)를치면 그해당파일은 삭제가 된다.
    하지만 이과정을 모두 생략하기를 원한다면 다음과 같이 입력하면 삭제가 된다.
    #rm -rf kkk이렇게 치면 깨끗이 삭제가 된다....
    하지만 지우면 복귀할수 없으므로 정말 신중에 신중을 기하여 삭제하길 바란다.


    복사명령과 이동명령

    리눅스에서 도 파일을 복사하는 명령이 있다.....통상적으로 도스에서는 copy,diskcopy명령으로 복사를 했지만 리눅스에서는 cp로 사용한다...별반 다를게 없으므로 작업을 해보면 쉽게 이해할수 있다...
    임의의 디렉토리를 하나 생성한다. 여기서는 webmaster밑에 webm01이란 디렉토리를 예로 한다.
    #cd ~webm01이라 입력을 하면 바로 특정디렉토리로 이동을 할 수 있다.
    만약 이동을 하지않는다면 webm01이란 방이 없거나 경로가 잘못되어서 그러므로 경로를 바꾸어주면 된다.... 경로바꾸는 것은 위에서 설명하였으므로 생략한다.
    #cd _webm01로 이동
    #touch test1:테스트1이란 빈파일을 만든다는 뜻이다(touch:빈파일만들기)
    #vi test1:vi 편집기를 통해 test1에 임의의 내용을 입력하고 저장하고 나온다.
    #cp test1 test2:test1을 test2란 파일로 복사한다는 뜻이다.
    #vi test2:이파일을 열어 test1안에 적힌 내용과 같은지 확인한다.(같다면 성공이다.)
    이번엔 test란 디렉토리를 만들어 방법만든 test1,2파일을 디렉토리에 복사하여 넣어보자..
    #mkdir test란 디렉토리생성한다.
    #cp test1 test2 test/라 입력하면 test1,test2파일이 test디렉토리에 복사된다.확인하여보자(ls)
    다음은 하위디렉토리에서 특정디렉토리로 복사하는 법을 알아보자
    여기서는 하위디렉토리에서 홈디렉토리로 복사하는법을 설명한다.
    #cp -r test /home:여기서 -r은 디렉토리째로 복사한다는 뜻이다. test란 디렉토리를 home에 복사를 한다. 확인하여보자.....

    다음은 동시에 여러개의 빈파일을 만드는 방법이다.
    #touch aaa bbb ccc ddd eee fff:여기서 나온 파일을 동시에 만든다는뜻이다. 당연히 더많이도 생성가능하다..... 파일이 만들어졌는지 확인하여보자.
    다음은 특정파일만 삭제
    #rm -r a*:이말은 a로 시작하는 모든 파일을 삭제한다는 뜻이다.

    다음은 이동명령 mv를 알아보자 이명령은 디렉토리나 파일을 이동할때사용하면 파일의이름을 변경할때는 적용이된다.
    #mv test test2:이말은 옮긴다는 뜻이아니라 test test2로 명명한다는 뜻이다.
    #mv test /home/webmster:이말은 test란 디렉토리를 홈밑에 웹마스터방밑에 이동한다는 뜻이다. 자 한번 실습해보기 바란다.

    일정한 자료찾기 명령
    #find / -name skell -> 일정한 자료찾기를 할 수 있다.


    간단한 vi편집기명령알기
    (cat)동일

    cat의 경우 수정,변경,저장할 수는 없다 단지출력명령.
    vi 명령을 쓰면 일정텍스트상의 내용을 수정 변경 저장할 수 있다.
    일반적인 명령을 예로 들어보자
    예)
    #vi /etc/group ->etc밑에 그룹의 내용을 보거나 수정한다는 내용이다.
    텍스트가 출력이 되면 수정하고자하는 부분이 있을 경우 insert키를 눌려 수정하고자하는 셀로 이동을 한다.... 만약수정하였으면 esc키를 눌려 insert키를 해제시키고 콜론이누른다.(shift+:)그러면 하위에 콜론이 생성이되는데....저장하고자 한다면 qw(종료저장),저장하지않고 그냥종료시킨다면, q!를 누르면 된다...자 이제 활용을 해보자.


    리눅스 설치에서 파티션나누기...

    리눅스는 일반 윈도우와는 달리 각각에 대한 루트계정을 만들어 주어야 한다.
    윈도우즈의 경우는 포맷과 운영체제설치와 동시에 모든 디렉토리생성 및 응용프로그램설치를 아무곳에서나 가능하나 리눅스는 이와는 다른다....
    /:최상위 디렉토리로 운영자가 직접관리 및 운용할수있는공간
    /boot:
    /usr : 현재 시스템에서 사용하는 응용프로그램을 이곳에 설치를 한다.윈도우즈의 경우 programs files디렉토리에 설치를 하듯이곳에 리눅스 패키지가 설치된다.
    /home : 이곳엔 일반인에게 계정을 부여하고 일정의 공간을 할당해주는 역할을 한다.
    웹호스팅을 사용해본 유저라면 쉽게 이해하리라 생각이 든다.
    /swap : 일반적으로 swap이란 가상메모리를 뜻하는데 리눅스에서 이렇게 램이 아닌 가상메모리지원해 줌으로써 램이 적더라도 swap메모리를 할당해주어 램과 같은 역할을 하여준다.
    swap메모리를 활용을 하면 최상의 시스템구축이 가능하다. 일반적으로 자신의 램의 2배를 지정해주는 것이 좋다고 한다.

    가상콘솔(ctrl+alt_f1) x-window에 들어가지 않고 바로 가상콘솔로접속
    [root@note/root}#:#를 bash sell이라 함...
    콘솔과 터미널:콘솔 :서버앞에서 직접작업을 하는 것을 콘솔이라하며, 터미널이란 멀리서 원격으로 접속을 하여 작업을 하는 것. 또한 가상콘솔작업은 root계정으로 작업을 하면 이것은 보안문제 때문에 다른계정으로 작업을 많이한다. 터미널의 경우 root작업은 치명적인 보안문제 때문에 일반계정으로 접속하여 작업을 많이함.....
    단축키명령
    (ctrl+alt_f1):가상콘솔 작업
    (ctrl+alt_f2)
    (ctrl+alt_f3):초기화 로그인
    (ctrl+alt_f7):x-windows로 들어가기
    콘솔상의 작업종료:exit,logout명령이 있으면 shutdown의 경우 시스템을 종료할 때 사용한다.
    옵션명령 : -r 재부팅 -h 시스템종료 -c shutdown명령을 취소
    시간타임 : now지금 즉시 지정된 shutdown명령실행
    +m m분후에 지정된 shutdown명령을 실행
    hh:mm hh시 mm분에 지정된 shutdown명령을 실행
    메세지 :현재 접속되어 있는 로그인 사용자들에게 언제쯤 종료를 한다고 알리는 메시지 기능을 제공(중요사항)

    예)shutdown -r now지금 즉시종료시행 shutdown +5 now 5분후 종료....



    사용자 추가명령

    새로운 사용자를 추가(계정)을 부여하기 위해 사용한다.
    일반적으로 adduser/useradd 명령을 사용한다.(사용법은 완전히 동일하다.)
    예)# adduser master1
    # passwd master1
    # 패스워드 입력
    # 재입력.......
    (패스워드의 경우 숫자와 일반글자를 조합하는 것이 좋으며 나쁜패스는 시스템에서 받아 들이지 않는다....)
    등록을 성공하면 successfully메세지가 나온다....이메세지가 나오면 성공....
    자 /home디렉토리로 이동을 하면 새롭게 추가된 계정을 확인할수 있다. 자 (ls -l)
    (사용자이름을 생략하고 passwd를 실행하면 현재 로그인한 사용자의 패스워드를 변경할 수 있다.



    패스

    #vi /etc/passwd를 실행하면 리스트가 출력이 된다.
    리스트중에 다음의 글이있을 것이다.
    root : x : 0 : 0 : root: /root: /bin /bash(bash)란쉘을 뜻함.
    root:사용자명
    x:비밀번호
    0:uid
    0:gid(그룹아디)
    root:선명(전화)comment
    root:홈디렉토리


    shadow
    :특정계정을 추가한후 패스파일을 암호화한 파일을 말한다.

    #useradd mask1
    #passwd mask1
    암호를 준후
    #vi /etc/passwd확인
    #vi /etc/passwd확인후 암호화(shadow)를 확인.


    일반계정부여와 함께 자동 홈페이지방 만들기...

    리눅스상에서 방을 부여하면 홈페이지를 만들수 있는 방이 필요하다...
    이것이 public_html이란것인데 이것을 계정부여와 동시에 만드는 방법을 배워본다.
    #cd /etc/skel
    #ls -l
    #pwd
    #mkdir mail
    #mkdir public_html
    #ls -l
    이렇게해주면 계정부여와 동시에 자동으로 sand mail과 public_html이 자동으로 만들어진다.


    그룹생성명령(group)

    그룹이란 일정한 시스템에서 여러사람이 그사용자성격상 비슷한사람들이 그룹으로 나우어 관리를 하는 경우 사용한다. 그룹을 잘이용하면 여러모로 전문적성격을 지닌 시스템으로 활용을 할 수 있다.
    예) 그룹생성과 일반계정으로 그룹에 등록시키는 내용
    #groupadd wm --->그룹명을 wm으로 지정을 하였다.
    #vi /etc/group --->vi편집기를 통해 group내용을 확인변경할수 있다.
    #useradd --help -->옵션을 활용할 때 이렇게하면 옵션사항을 출력하여 볼 수 있다.


    그룹에 등록시키는법

    #useradd -g wm web1 : web1이란 아이디를 wm이란 그룹에 등록한다는 내용이다
    #useradd -g wm web1 : web2역시 wm이란 그룹에 등록
    #vi /etc/passwd --> 등록이 잘되었는지 확인할 수 있다.


    모드설정변경

    리눅스에서 모드설정이란 text모드 x-windows등등 이있는데 이기본모드를 수정할 때 사용한다.
    먼저 #cat /etc/inittab : $more를 출력하면 리스트가 출력이 되는데...
    출력에 보면 id (숫자):initdefault란곳에 숫자를 바꾸어주면 된다.
    x-windows:5번
    single :1번
    text : 3번으로 구성이 되어있다.


    특정그룹추가하기

    일반계정을 그룹화하여 같은 폴더에서 관리하면 관리하기도 좋고 여러모로 편하다.
    그러나 그룹추가는 추상적이기 때문에 폴더개념과는 다르다.
    이점을 유의하기바란다. 그룹명을 지정해주고 그룹명과 같은 폴더를 만들어줄 때
    비로서 그룹화 된다고 보면된다.
    #groupadd (그룹명) :그룹은 만들어지었으나 폴더는 만들어지지않았다.
    #mkdir 폴더(일반적으로 그룹명과 동일하면 좋다):그룹과 폴더가 모두만들어지었다
    자 일반계정을 추가하여 방금만들어진 그룹에 추가하여보자
    #useradd -D -b /home/wm:초기 디렉토리의 경로를 지정해준다.
    #useradd -g wm wm01:-g는 그룹에 추가한다는 옵션명이고,wm은 그룹명이다
    그리고 wm01은 일반계정자이다..즉 wm01은 wm에소속되도록 -g(그룹화)하여 준다는 뜻이다.
    #passwd wm01 :이제 wm01의 패스워드를 추가하면 된다.


    userdel(유저삭제명령)

    일반계정을 추가하고 나면 나중에 삭제또한 하게 된다. 싶게 하위디렉토리까지 삭제하는법을 알아보자.
    #userdel (지울계정명):이렇게 지정하면 모두삭제된다.
    하위에 디렉토리가 없을 경우
    #rm -rf 계정명:으로 깨끗이 삭제할 수가 있다.


    usermod(일반생성 계정에 대한 편집명령),groupmod(그룹에 대한 편집명령)

    적용예(uid,향,comment,home,shell)
    #usermod -c bbb web02: (web02를 bbb로 바꾼다는 것이다. (단 폴더가 바뀌는 것이 아니라 .comment가 바뀐다는 것이다. 명령에 -c는 comment란 뜻이다.
    확인할려면, vi /etc/passwd로 확인을 해보라....

    #usermod -d /home/wm
    #vi /etc/passwd

    #usermod -n webm web:(web이란 그룹을 webm으로 변경하라...
    #vi /etc/group:이곳으로 가면 바뀐내용을 확인할수 있다.
    su명령의 아름다운반란(사용자 대체)
    su란 여러 계정을 오고가며 작업을 하는 것이다.
    리눅스의 묘미를 맛볼수 있는 것이기도 하다...또한 root가 어느정도로 막강한지를 쉽게 알수가 있다... 자 이제 실행하여보자

    보통 터미널로 작업을 할때에는 root로 로그인이 불가능하는 하지만 su를 통해 가능하여진다 먼저 일반계정으로 접속을 하여 #su root로 변환하여주면 가능하다...
    하지만 일반계정에서#su root를 실행하면 root의 패스워드를 묻게된다.패스를 모르면 끝장이다. 그냥 집에가야 될듯......흐흐흐
    패스를알고있다면 입력. 성공메세지가 출력되고 root로 작업환경이 변환된다.
    이번엔 root권한으로 일반계정으로 변환하여 작업을해보자
    #su webm01이렇게 하면 패스워드를 묻지않고 바로작업에 들어갈수가 있다....요것이 root만의 권한.....

    이번엔 일반계정에서 일반계정으로 변경작업하여보자
    #su webm02라실행하면 역시 패스워드를 묻는다....모르면 찌그러지고 알면 들어가서 작업하면된다.
    즉 정의하자면 root는 su명령을 통해 어떠 계정에도 접속하여 작업을 할수있으나 일반작업자의 경우 root로 작업을변환할 때 패스워드를 알아야 하며,역쉬 일반계정끼리의 작업또한 패스워드를 알아야 작업이 가능하다는 것이다. 이권한을 chmod로 뚫을수있을까...

    에러발생시 대책법

    윈도우즈의 경우 에러가 발생하면 강제종료를 시키면 scandisk가 바로잡아준다.
    리눅스의 경우도 그러하지만 이건 바람직하지가 않다. 에러가 발생하면 나름대로 에러를
    잡는 법을 알아보자.
    먼저 에러가 발생을 하면 read읽기 기능만으로 자동으로 변환이 된다.
    이를 바꾸기위해선 다음과 같은 명령을 수행하면 된다.
    먼저 readolny가 나오면 이건 읽기기능만이 수행된다는 뜻이다.
    lilo에서 ctrl+x로 text모드로 들어간다. 아이디와 패스를 입력하고
    #mount -n -0 remount , rw(읽고쓰기로 변환한다는 뜻이다.) /dev/hda5(리눅스가 깔린장치명)입력하면된다.

    초기부팅화면 설정변경

    멀티부팅시 dos모드나 linux모드중 어느것을 먼저택할건지 지정해주는 것이다.
    역시 명령어는 다음과 같다.
    #cat /etc/lilo.conf 엔터를 치면 리스트출력 하면 수정부분이 눈에 들어온다.
    단 cat명령어는 출력명령어 이므로 vi로 바꾸어 출력을 하면된다. 역시 수정하고 저장하고 나오면 된다.)


    로그인 패스워드변경법

    lilo화면에서 ctrl+x키로 누르면 된다.
    먼저 linux 1이나 single로 입력을 한후
    passwd를 입력한다...암호를 임의로지정을 하고 반복암포를 누르고 빠져나온다.
    자한번 테스트해보자.


    한템창에서의 멀티작업시 에러메세지....

    통상적으로 리눅스에서는 여러개의 한텀창을 띄어놓고 작업을한다.
    하지만 열어본작업을 닫지않고 다른창에서 또같은 작업을 병행하면 swap메모리를 먹기 때문에 좋지않다...또한 여러 가지 메시지를 동반하므로 귀찮기 짝이없다.
    한번쯤 이런 경험을 해보셨을거라 믿는다.....
    참고로 편집도중 ctrl+z를 사용하면 꼬옥 창이 닫힌것처럼 결과가 나오는데...
    이건 창이 완전히 닫힌게 아니라 잠시 숨겨두는 것이다.
    ctrl+z를 누른후 #jobs라 쳐보자 그러면 작업중인게 한 개가 있다는 메시지가 나온다.
    완전히 해제시킬려면 #kill %1이라 치면 완전 종료된다.
    아니면 첨부터 윈도창에서 닫임단추를 누르면 종료된다.

    and
    prev Prev : [1] : [2] : [3] : [4] : [5] : Next next