제2의 비엔지니어 인생관을 꿈꾸며

Posted
Filed under MSSQL
프로그래밍의 전유물 Try ~ Catch 를 MSSQL 에서도 꽤 오래전(MSSQL 2005 부터 지원)부터 사용 할 수 있게 되었다. 과연 DB 프로그래밍에서, Try ~ Catch 가 필요할까? 잠깐 살펴보자면, 어플리케이션용 프로그래밍언어와 DB용 프로그래밍언어는 목적이 좀 다르다. (구지 딴지를 걸면 할말은 없지만 본인 생각이다)

▶ DB는 CRUD (Insert,Select,Update,Delete) 에 집중된 처리를 할 수 있게해주어야한다.
▶ 그러므로, DB에 호출되어저, 넘어오는데이터는 사실 Validation 이 대부분 끝난 데이터 들이어야 한다.
(예를들면, 뭐,.. Type , Length , 유효성 등등  필드 조건 / 업무에 맞는 Spec )

하지만, 제어에 따라 DB단(DB 프로그래밍)에서 뭔가 다시한번  데이터를 체크하거나, 제어 처리해야 수월한 경우가 발생한다. 그러므로 MSSQL 에서의  Try ~ Catch 를 비롯한 기타 오류처리 변수 및 함수에 대한 지원은 반갑지 아니 할 수 없다.(반갑다.--)

● Try ~ Catch (Begin Try ~ End Try Begin Catch  ~ End Catch)
Begin Try
    // 오류 발생의 여지가 있거나, 예외가 날 가능성이 있는 코드
End Try
Begin Catch
   // 오류가 났을때 처리
End Catch

일반 어플리케이션 언어와 구문과 비슷한 문법을 가지고 있다.
물론 Exception 객체나 finally 그리고 예외 구분에 따른 catch  구문을 다중적으로 가질수 없는 축약식 느낌이긴하다.

여기서 중요한 점은 모든 오류를 Try ~ Catch가 잡아내지 못한다는 점이다.
MSSQL 의 Try ~ Catch 가 인지 할 수 있는 오류 심각도는 10 이상이고. 연결을 끊는,또는 강제 중단의 오류를 예외처리 Catch 하지 못한다. 

이번엔, Try ~ catch 를 활용하여 , 오류 처리 및 예외처리를 위해 필요한 함수에 대해 알아보자

● 오류 상태 체크 함수 
select @@Error -- 오류 코드를 출력한다.
select Error_Number()       -- 오류 코드 출력 = @@Error 과 같다.
select Error_Line()             -- 오류난 소스의 라인을 출력한다.
select Error_Message()     -- 오류 메세지를  출력한다.
select Error_Procedure()   -- 오류난 프로시져명을 출력한다.
select Error_Severity()      -- 오류의 심각도를 출력하한다.

select Error_State()           -- 오류의 상태를 출력한다.

위의 상태값을 눈으로 확인하기위해 , 아래 프로시져를 작성해 보자

[예제] 

Create proc sp_Test
as
Begin Try  
     EXECUTE SP_Nothing;   // SP_Nothing 는 없는 프로시저 이다.
End Try  
Begin Catch
    SELECT   
        @@Error as Error ,
        Error_Number()  as Number,
        Error_Line() as Line,
        Error_Message() as [Message],
        Error_Procedure() as [Procedure],
        Error_Severity() as severity,
        Error_State() as state  
End Catch


  Exec sp_Test  -- 실행해보자  
일단 오류 오류번호 와 심각도 , 상태 숫자는 우린 뭔지 모르겟지만,
그것을 제외하고도 ( getdate() 만 추가한다면,) 언제 , 어디서 , 어떤 오류가 , 몇 라인에 났는지 쉽게알 수 있다.


참고로 Error 함수들을 다 외우지 않아도 된다.(역쉬 편리한, 인텔리센스 ㅠ_)


이제 try  ~ catch 구문이 편리하게 오류 예외처리를 해주므로 너무 편리해졌지만, 안타깝게도 모든 오류를 처리해주지 않는다. 위에서 잠껀 언급한대로,  오류 심각도는 10 이상이고. 연결을 끊는,또는 강제 중단의 오류를 예외처리 Catch 하지 못한다. 예를들면 실행중 연결이 끊기거나, 실행중인 프로시져를, Kill 하거나, 하면 Catch 를 타지 못한다.

더 아이러니한건 어떤게 오류 레벨이 어떻고 어떤지, 오류 레벨로 기억하기란, 개발자 입장에서는, 다 알고 있기도 난해하다.
아래 샘플로 감을 한번 잡아보자.


● Try ~ Catch 예제

원래 예제도 되도록 복사해서  테스트 해볼수 있도록 Text 로 작성하려고 노력하지만, 이번엔 빠른 작성을  스크린샷으로 대신하고, 아래 샘플 쿼리를 첨부해 놓도록 하겠다.



----------------------------------------------------------------------------------------------------------------------------------------------
# 조건 1 : 존재하지 않는 프로시셔 -   예외처리 성공(ㅇ) 

※ 존재하지 않는 프로시져 호출시 정상적으로 예외처리를 한다. 이번에 테이블로  해보자!


----------------------------------------------------------------------------------------------------------------------------------------------
# 조건 2 : 존재하지 않는 테이블 -
  예외처리 오류(X) 
※ 존재하지 않는 테이블 쿼리시 예외처리를 못한다.ㅠ  그럼 함수를 호출해 보자 해보자


----------------------------------------------------------------------------------------------------------------------------------------------
#조건 3 : 존재하지않는 함수 - 
 예외처리 오류(X) 

※ 역시 안된다. 없는 개체의 호출은 프로시져 호츨만 성공하고, 나머지 테이블 


----------------------------------------------------------------------------------------------------------------------------------------------
# 조건 4 : 존재하지 하지만 사용할 수 없는 동의어(Synonym)
 -   예외처리 오류(X) 

※ 시놈님(동의어) 도 역시 안된다.


결국 없는 개체의 예외처리는
테이블,  함수, 동의어(시놈님) 모두 오류 , 프로시져만 성공 , 존재 하지도 않는 개체를 쿼리에작성할 일은 없지만 어쨋던 프로시져만 성공했다. 그럼 논리적인 오류를 작성 해보자.


자. 그럼 이제, 논리 오류에 대해 예외를 확인해보자.


----------------------------------------------------------------------------------------------------------------------------------------------# 조건 5 :  예제로 잘나오는 몫 0 으로 나누기 :
  예외처리 성공(ㅇ) 

----------------------------------------------------------------------------------------------------------------------------------------------
# 조건 6 :  유니크 컬럼에 중복 값 넣기:
  예외처리 성공(ㅇ) 




----------------------------------------------------------------------------------------------------------------------------------------------
# 조건 7 :  타입 다르게 넣기 :  
 예외처리 성공(ㅇ)  → idx 가 int 형인데 'b' 문자열 값을 넣어봤다.

※ 생각보다 논리적인 오류 처리는 잘 된다? 그렇타면 ,,

----------------------------------------------------------------------------------------------------------------------------------------------# 조건 8 : 우리가 흔히하는 실수,  테이블 제공 컬럼수와 다르게 데이터 입력 -   예외처리 오류(X) 

----------------------------------------------------------------------------------------------------------------------------------------------
# 조건 9 : 우리가 흔히하는 실수,  명령어 오타-   예외처리 오류(X) 
→ 눈에 띄게하기위해 values 부분을 valueInsert 로 해 보았다.
※ 역시 안된다 , 생각보다 많은걸 오류 처리를 못하는거 같이 보인다. 이외에도 쿼리 문법이 아닌 if 문 이나 case 등의
명령어 문법에 대해서도 예외처리가 안된다.

예제를 가만히 생각해 보자, 아 뭐지? 처리되는게 예외처리하는게 생각보다 얼마 없네? 라고 생각이 들 수 도있다.


자 그럼 이제 어플 개발언어로 돌아와서 생각해보자.


프로그램의 작성은 코딩 → 컴파일 → 실행 과정을 거친다. 물론 내부적으로  작성한 코딩이 맞는 문법 및 명령어 체크작업, 객체 및 변수의 존재 유무 및 초기화 문제 등등 , 기타 여러가지 문제점을 "코딩 → 컴파일" 과정에서 모두 소화 & 체크해서 개발자로 하게끔 수정을 한다.(컴파일 언어인 경우다) 

하지만 인터프리터나 , SQL 처럼 컴파일따로  실행따로 구분되어진 언어가 아닌, 실행과 동시에 컴파일과 문법 파싱작업이 동시에 이루어지는 스크립트 언어들은, 아무래도 개발에 특화된 언어에 비해 개발환경이 뛰어나지는 않타. 지극히 정상적일수도있다.

정리하자면, 만약 프로시져를 작성한다고 가정했을때, 어차피 위에서  예외처리가 안되는 상황의 쿼리 작성문들을, 프로시저에 작성하여, 생성 & 수정 한다면, 그 과정에서 최소한의 문법파싱 같은 작업이 이루어 지므로 없는 테이블을 작성하거나,  없는 함수를 쓰거나 하는 오류를 범 할 확률이 거의 없겟다. (반대로 예외처리가 되는 예제들은, 런타임시 값들에 의해 오류가 날 확률이 높다는 반증이다)

결론은, 객체 관련 오류보다 (심각도가 10 보다 높은오류) 논리적인 오류, 그러니까 값에 의해 발생되는 예외를 처리하도록 만들어지는게 사실상 맞다는 말이다.

역으로 생각해보면 , 없는 프로시져가 예외처리가 된다는게 오히려 의외의 결과 일수가 있다.
(하지만 프로시저 경우 작성시 try 안에 없는 프로시져 쿼리를 작성하면  프로시저는 만들어지지만, 아래와 같은 문구가 출력되면서 만들어진다.)

" 모듈 '생성되는 프로시저명'은(는) 누락된 개체 '호출될프로시져(없는프로시져)'에 종속되어 있습니다. 이 모듈은 그래도 만들어지지만 해당 개체가 있어야 실행될 수 있습니다.  "
2018/04/19 10:34 2018/04/19 10:34
Posted
Filed under jQuery
# 이벤트 호출로 $scope 간의 데이터 전달관련 포스팅을 추가로 해봤다.
지난 #1편 의 포스팅은 단순히 메소드의 사용법에 대해 알아봤다면, 이번에는 각 스코프 간의 연결을 을 통해 모든관계를 정확히 이해하고 가자.
 부모 - 자식 ,  자식 - 자식 ,  부모 - 자식의 자식  ,  자식 - 자식의자식  관례를 이해할 수 있다.

(부모 - 자식 관계는, 사실 자식 - 자식의 자식의 관계와 같다 자식의 자식의 부모는 자식 이므로 .. @.@ 예제를 보자)

<!DOCTYPE html>
<html>
<head>
    <!-- https://cdnjs.com/libraries/angular.js/ -->
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular-cookies.min.js"></script>    
</head>    
<body ng-app="myApp">

          <div ng-controller="NParent">

                   <div> 부모 #0 : <span ng-bind="name"></span>
                    <div ng-bind="parentname"></div>
                    <button ng-click="fnSetValue()">값 설정</button>
                    </div>

                     <div ng-controller="NChild1">
                        자식 #1 : <span ng-bind="name"></span>
                                  / 자식 #1 에 자식 #0 :
                                  <span ng-controller="NChild11">
                                        <span ng-bind="name"></span>
                                         <!--  NChild11 에는 fnWhoami() 함수가 없어 부모인 NChild1 로 찾아가서 호출한다.
                                                만약 NChild1 에도 없으면  최상위 부모인 NParent 를 찾아간다 -->
                                        <button ng-click="fnWhoami()">나는 누구?</button>
                                  </span>
                     </div>
                     <div ng-controller="NChild2">
                          자식 #2 : <span ng-bind="name"></span>          
                          <button ng-click="fnNC2SetValue()">내 이름 {{name}} 으로 모든 값 설정</button>
                     </div>
          
        </div>
  
        <script type="text/javascript">
                var m = angular.module("myApp" , []);    

               // DOM 구조상 부모 $scope 
                m.controller("NParent" , function($scope)
                {        
                    // 자식의 모든 name 변수에 영향을 받음
                    $scope.name = "pluginn"; 

                    // 자식의 모든 
parentname 변수에 영향을 받으나, 본인만 있으므로 본인만 받음
                    $scope.parentname = "pluginn parent"; 
                    $scope.fnSetValue = function()
                    {     
                       // 자식 $scope 의 setValue $on 이벤트 함수 호출               
                        $scope.$broadcast("setValue" , "");
                    }

                    // 자식 $scope 로 부터 호출 당해질 이벤트 함수 등록
                    $scope.$on("brSetValue" , function(e,d)
                   {
                       // 자식 $scope에 $on 으로 등록된 setValue 이벤트 함수 모두 콜
                       $scope.$broadcast("setValue" , d);
                    });
                });
                
                m.controller("NChild1" , function($scope)
                {
                   //  부모로부터  불려질 이벤트 함수 setValue 등록
                  $scope.$on("setValue" , function(e , d)
                  {
                        if (d == "") d = " ++  자식1_이름 SET ++ ";
                        $scope.name = d;                        
                  });

                  $scope.fnWhoami = function()
                  {
                           alert("NChild1");
                   }
                });
                m.controller("NChild11" , function($scope)
                {
                    //  부모로부터  불려질 이벤트 함수 setValue 등록
                    $scope.$on("setValue" , function(e,d)
                    {
                        if (d == "") d = " ++ 자식1의 자식1이름 SET ++";
                        $scope.name = d;                      
                    });
                });
                
                m.controller("NChild2" , function($scope)
                {
                    //  부모로부터  불려질 이벤트 함수 setValue 등록
                   $scope.$on("setValue" , function (e ,d)
                   {
                      
                        if (d == "") d = " ++ 자식2_이름 SET ++";                  
                        $scope.name = d; 
                    });

                    $scope.fnNC2SetValue = function()
                    {
                       // 본인 한테 
parentname 가 없기때문에,  부모한테 있는 parentname 값을 호출함,
                       alert($scope.parentname); // 부모의 parentname

                       //  parentname에 값을 셋팅 하면 (부모 자원인 읽기만 가능, 변경음 못함)
                       // 부모의 parentname 가 아닌, 본인스코프에 없었기때문에 새로은 parentname 생성
                       $scope.parentname = "xxx"; 

                       // 부모 $scope 로가서 값을 호출해보면 xxx 가  아님을 알 수 있다.
                       /// 결국 함수, 변수는 본인 $scope없을경우 부모 $scope 로 타고가면서 찾아감

                       alert($scope.parentname); // NChild2의 parentname

                       // $emit 로 부모의 brSetValue 이벤트 함수 호출 , 값으로는 name 전달
                       $scope.$emit("brSetValue" , $scope.name);
                    }
             
                });
        </script>
</body>
</html>
2018/04/05 16:39 2018/04/05 16:39
Posted
Filed under jQuery

ng-bind 는 angular 의 변수 또는 model 과 연결되는 M-V 의 연결역할을 하는 Directive 이다. 또는, 인터폴레션으로 {{ }} 작성해도 같은 효과를 본다. 근데 공부를 하다보니 , 네임설정에 있어. period 가 들어간 네임이 작동하거나 , 안하는 경우가 있어, 정리해 두기로 했다.

# ng-bind 네임설정  #1  "일반적인 영문 / 영+숫자" 
<body ng-app="myApp">
        <div ng-controller="myCtrl">
            <div>name : <span ng-bind="name"></span></div>            
            <div>name : <span ng-bind="name12"></span></div>            
        </div>
          
        <script type="text/javascript">
                var m = angular.module("myApp" , []);    
                m.controller("myCtrl" , function($scope)
                {                    
                    $scope.name = "pluginn";     // 정상 작동
                    $scope.name12 = "pluginn12"  // 정상 작동
                });
        </script>
</body>
단,네임설정에있어, 숫자만으로 이루어진 명칭 또는 영문+숫자 혼용이 아닌 숫자+영문 인 경우 , 프로그램의 기초와 같은 개념을 갖고있어, 작동되지 않는다. (예, 1111,2342 , 11name  ,11price  모두 오류)


# ng-bind 네임설정  #2   "period 를 붙인 네임 name.nickname "
<body ng-app="myApp">
        <div ng-controller="myCtrl">      
            <div>name.nickname : <span ng-bind="name.nickname"></span></div>            
        </div>
          
        <script type="text/javascript">
                var m = angular.module("myApp" , []);    
                m.controller("myCtrl" , function($scope)
                {                    
                    $scope.name.nickname = "plug~ plug~"; // 오류발생 작동하지 않음
                });
        </script>
</body>
으잉 안된다 이상하네, 아래를 보자.

# ng-bind 네임설정  #3   "period 를 붙인 네임 name.nickname "  by ng-model
<body ng-app="myApp">
        <div ng-controller="myCtrl">      
           <input  type="text" ng-model="name.nickname"/>
            <div>name.nickname:<span ng-bind="name.nickname"></span></div><!-- 정상작동 -->
            <div>{{name.nickname}}</div> <!-- 정상작동(인터폴레이션)-->
        </div>
          
        <script type="text/javascript">
                var m = angular.module("myApp" , []);    
                m.controller("myCtrl" , function($scope)
                {                    
                   //  angluar 가 제어할수있도록, 컨트롤 등록만 해준다
                });
        </script>
</body>
음, ng-model 로 설정된 이름이는 객체처럼 접근이되는 네임이 가능하다. 그럼 예제를 하나더 들어보자


# ng-bind 네임설정  #3   "period 를 붙인 네임 name.nickname "  by Array
<body ng-app="myApp">
        <div ng-controller="myCtrl">     
            <div>name.nickname:<span ng-bind="name.nickname"></span></div> <!-- 정상작동-->
            <div>{{name.nickname}}</div> <!-- 정상작동(인터폴레이션)-->
        </div>
        <script type="text/javascript">
                var m = angular.module("myApp" , []); 

                m.controller("myCtrl" , function($scope)
                { 
                          var name = { nickname : "pluginn" };
                          $scope.name = name;               
                });
        </script>
</body>
작동된다. 결국 period(.) 의 의미는 프로그래밍에서와 마찬가지로 객체의 속성접근으로 봐야한다.
네임에는 . 를 사용하지 말자 , 

ng-Model (예, ng-model="name.first") 또는 배열과같은 객체명의 속성 성격의 period 네이밍은 가능하나, 변수명  자체로서의 period 사용은 자제하기로 하자. 일반적인 프로그래밍에서이 사용방법과 딱히 다를것이
없다.
2018/04/05 13:21 2018/04/05 13:21
Posted
Filed under jQuery
# ng-if
 ng-if  구문안의 조건이 맞으면 본인을 show 틀리면 hide
<body ng-app="myApp">
                <input type="text" ng-model="sbtxt" value="">
                <div ng-if="sbtxt == 'red' ">빨강색</div>
          
        </div>
       <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>
        <script type="text/javascript">
                var myApp = angular.module('myApp', []);
        </script>
</body>


# ng-switch on ~ ng-switch-when 문

 ng-switch on 에 연결된 ng-model 의 value 에 따라 ng-switch-when 조건에 설정된
 블럭들이 show/hide 됨 , 아래 예제
<body ng-app="myApp">

                <select id="sb" ng-model="sbcolor">
                    <option value="">선택</option>
                    <option value="1">red</option>
                    <option value="2">green</option>
                    <option value="3">blue</option>                                        
                </select>

                <div ng-switch  id="aa" on="sbcolor">                 
                  <div ng-switch-when="1" class="box red"></div>
                  <div ng-switch-when="2" class="box green"></div>
                  <div ng-switch-when="3" class="box blue"></div>
                  <div ng-switch-default class="box black"></div>
                </div>
          
        </div>
       <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>
        <script type="text/javascript">

                var myApp = angular.module('myApp', []);
        </script>
</body>


# ng-show , ng-hide
ng-show 구문 안의 조건이 맞으면 자신을 show 틀리면 hide 한다.
ng-hide   구문안의 조건이 맞으면 자신을 hide 하고 틀리면 show 한다.
<body ng-app="myApp">

                <input type="text" ng-model="sbtxt" value="">

                <div ng-show="sbtxt=='red' ">빨강색 O</div> <!-- 참이면 보임  -->
                <div ng-hide="sbtxt=='red' ">  빨강색 X</div>  <!-- 참이면 숨김 -->
          
        </div>
       <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>
        <script type="text/javascript">
                var myApp = angular.module('myApp', []);
        </script>
</body>


# ng-class
ng-class 구문안에 조건에 만족하면 선언한 클래스가 블럭에 적용된다.
ng-class = "{클래스명 : 조건 , 클래스명 : 조건 , 클래스명 : 조건.......}"
<style type="text/css">
    .red {color:#F00}
    .green {color:#0F0}
    .blue {color:#00F}
</style>
<body ng-app="myApp">
       <input type="text" ng-model="sbtxt" value="">
       <div ng-class="{red : sbtxt == 'red' , blue : sbtxt == 'blue' }">안녕하세요</div>          
        </div>
       <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>
        <script type="text/javascript">
                var myApp = angular.module('myApp', []);
        </script>
</body>
2018/04/04 14:03 2018/04/04 14:03
Posted
Filed under MSSQL
MSSQL 프로그래밍에세  꽤나 많은 부분을 CRUD 구현하는데, 많은 문장을 작성해 나간다.
WITH 가 Select 에 최적화되어 있다면 MERGE 조인된 테이블의 Insert / Update /Delete 를 구현하는데 최적화 되어있다고 보면 좋겠다.

# MERGE 의 기본 문법 및 의미
MERGE  [Target_Table]  AS TT   -- TT 는 [Target_Table] 의 alias
USING  [Source_Table]  AS TS   -- TS 는 [Source_Table]의 alias
ON ( TT.Column1 = TS.Column1 )  

WHEN MATCHED 
          THEN  [Target_Table]에 대한 처리

WHEN NOT MATCHED BY TARGET   AND  TS.RegDate > '2018-01-01'
           THEN 
[Source_Table] 에 있고 , [Target_Table] 에 없으면, [Target_Table] 에  Insert / Update

WHEN 
NOT MATCHED  BY SOURCE  AND  TT.RegDate < '2018-01-01'
          
THEN  [Source_Table] 에 없고,  [Target_Table] 에 있으면,   [Target_Table]  꺼 처리  Delete / Update

OUTPUT   $action , inserted.* , deleted.*  ;   //  로그보기  MERGE문의 종료는  반디스 세미콜론을  해주어야 한다.
(inserted 는 insert / update 둘다의 의미를 가지고 있으므로 , 따로 updated는 없다.)


2개의 연관된 테이블의 데이터가 "NOT MATCHED" 이긴한데 명시적으로 아래와같이 이용때
  BY TARGET   :  Source 에는 있고, Target 에 없으면
  BY SOURCE  :  Source 에는 없고, Target 에 있을때

 주의  :  WHEN MATCHED 를 제외하고  WHEN NOT MATCHED BY TARGET  처리시  WHEN NOT MATCHED  BY SOURCE 조건도 만족한다면 2개처리한다.   (WHEN MATCHED 를 제외)
1개의 WHEN 조건을 처리하고 종료하는 구조가 아님 , TARGET 과 SOURCE를 2개다 처리하게된다.

예를 들어 BY TARGET 처리 후 BY SOURCE 조건도 만족한다면 SOURCE 조건도 처리함 (코드의 순서와 관계없음)




# 테스트 테이블 및 데이터 만들기
-- 테이블 생성
create table #tbl1 (
 idx tinyint ,  name varchar(20) )
create table #tbl2 ( idx tinyint ,  name varchar(20) )


-- 더미 INSERT
insert #tbl1 values( 1 , 'aaa')
insert #tbl1 values( 2 , 'bbb')

insert #tbl2 values( 3 , 'ccc')
insert #tbl2 values( 4 , 'ddd')
insert #tbl2 values( 5 , 'eee')

-- 데이터 확인
select * From #tbl1
go
select * From #tbl2


# 간략하게 MERGE 이용
MERGE #tbl2 As TT -- Target
USING #tbl1 As TS -- Source
ON (TT.idx = TS.idx)
-- Source 에는 있고 Target 에 있으면, Source 참조로 UPDATE
WHEN MATCHED 
THEN UPDATE SET TT.NAME = TS.NAME
WHEN NOT MATCHED -- BY TARGET 생략시  NOT MATCHED BY TARGET  과 동일
THEN INSERT (idx ,name ) values(TS.idx , TS.name)




# BY TARGET  ,BY SOURCE 를 이용하여, 명시적으로처리
MERGE #tbl2 TT -- Target
USING #tbl1 TS -- Source
ON (TT.idx = TS.idx)
-- Source 에는 있고 Target 에 있으면, Source 참조로 UPDATE
WHEN MATCHED 
THEN UPDATE SET TT.NAME = TS.NAME

-- Source 에는 있고 Target 에 없으면, Source 참조로 Target 에INSERT
WHEN NOT MATCHED BY TARGET  -- AND TS.idx = 5  조건 추가 할 수 있음
THEN INSERT (idx ,name ) values(TS.idx , TS.name)

-- Source 에는 없고, Target 에 있으면 Target 에 Delete or Update
WHEN NOT MATCHED BY SOURCE -- AND TT.idx  >= 2 조건 추가 할 수있음
THEN Delete   -- or THEN UPDATESet idx = 1000 
OUTPUT   $action , inserted.* ,   deleted.*;   -- 로그사용

위 쿼리 실행 


[#tbl1 과 #tbl2 원본 Select]



[위의 Merge 실행후 Log]



[최종결과]
빨강네모 -  NOT MATCHED BY TARGET   - Insert
파랑네모 - NOT MATCHED BY SOURCE  - Delete




[최종결과]

빨강네모 -  NOT MATCHED BY TARGET   를 통해 Insert 만하고 종료하지 않고 ,
파랑네모 - NOT MATCHED BY SOURCE  조건도 만족하는것을 감지하는순간 Delete 도 동시에 처리한다.

정리하자면,
일단 Merge ~ Using ~ On 조건을 통해 Not Matched 조건이 발생하면 1개의 Not Matched(BY TARGET) 의 조건만
처리하지 않고, 
처리 후 다른 Not Matched(BY SOURCE) 조건에 만족하면 연속해서 발생한다.
( 위에 2조건을 만족하게되면 MATCHED 도 만족하게 되지만,  MATCHED 는 일어나지 않음 )
2018/04/02 18:27 2018/04/02 18:27