반응형
반응형
다음과 같이 lookuptable이라는 1000만건 데이터에 대해 facttable 이라는 3만건 데이터가 조회 작업을 수행하는 환경을 구현해 보았습니다.

 

다음은 SQL 2000 DTS에서 구성한 작업입니다.

 

 

위의 작업을 수행한 후 프로필러로 수행 상태를 확인하면 다음과 같습니다.

 

 

, 입력된 행에 대해 조회 쿼리를 날려서 결과를 받아내는 방식이지요..

 

 

SQL 2005 SSIS에서도 동일한 DB(OLE DB 연결)에 대해 조회 작업을 수행하였습니다.

 

 

고급 탭에서 우선 메모리 제한 사용을 체크 하지 않고 수행하면 다음과 같습니다.

 

 

CPU 난리나고 메모리도 난리나지요~~^^

 

프로필러에서는 다음과 같은 조회 쿼리가 수행되어 1000만건을 다 메모리에 올립니다.

 

 

만약 메모리 제한 옵션을 준다면, 메모리 만큼 올리겠지요..

 

 

그럼 고급 탭의 아래에 있는 SQL 문 수정을 체크한다면??

 

 

정상적으로 별 부하 없이 빨리 수행됩니다. SQL 2000에서와 같이~~

 

 

 

 

결론은??

 

1. 조회할 테이블이 얼마 안될 때에는 캐싱을 사용하거나 일부 캐싱을 사용해서 하는 것이 좋습니다.

2. 조회할 테이블이 위와 같이 많은 경우에는, 반드시 SQL 쿼리 수정 옵션을 이용하여 입력되는 데이터에 대해서만 캐싱을 하도록, 그리고 입력될 때에만 로딩 하도록 설정합니다. 성능은 SQL 2000 보다 좋거나 같습니다. 왜냐면~? SQL 2000 DTS에서는 ActiveX를 이용하여 결과를 받아야 했으며, ActiveX를 이용한 작업은 컴파일이 안된 상태로 처리되기 때문에 느립니다~^^

 

조회 변환과 관련해서는 아래의 강좌 참고하세요~..

 

[ 좌 33]

 

 

 
 




------------------------------------
작성일자 : 2006-11-16 오후 2:41:00
------------------------------------
안녕하세요. sql 초보 오순근이라고 합니다.
제가 아직 잘 모르기 때문에..또 난관에 부딪쳤습니다.
2000->2005 마이그레이션 하는 도중....약 데이터 흐름에서 일정량의 많아봤자 10000개의 레코드셋에 약 2000만개의 데이터를 [조회] 항목을 사용하여 합쳤습니다.
근데 엄청난 캐쉬만 무지하게 읽더니..1800만정도에서 오류가 뜨네요.... C드라이브의 하드가 7기가 인데....2기가 남았다가 1.1기가 정도로 하드 용량이 계속 줄면서 1800만 정도 캐쉬에서 오류가 납니다..ㅠㅠ
 
위와 같은 항목이 나와서 [조회] 항목의 속성에서 메모리 제한을 걸고 하면...
 
 
근데 OLE DB 원본의 데이터가 0행이면 오류가 생기지 않습니다 ㅠㅠ..
2000에서는 아무 이상없었는데...조회 필드에서 그러네요..ㅠㅠ...
간단하게 조회에서 usr_id를 비교해서 조회 레코드의 index를 가져오는것인데..이부분에서 계속 에러가....
하드가 용량이 부족해서 그런건지..(2000에서는 이상이 없습니다 ㅠㅠ) 캐쉬 및 메모리 제한의 문제인지....
궁금합니다...
오늘 하루도 좋은 하루 보내세요..^^
반응형
반응형

안녕하세요 SQL 프론티어 강성욱입니다.

이번 포스팅은 저처럼 SSIS를 잘모른시는 분들을 위하여 작성하였습니다.

이번 포스팅에 많은 도움을 주신  BI전문가인 BASH(김상수) 형님 감사합니다.

앞으로도 많은 지도 편달 부탁드립니다.

 

필자는 근래 들어 대량의 데이터를 수집하는데 있어서 어떻게 하면 효율적으로 수집할 수 있을까

많은 고민을 하고 있습니다.

더군다나 해외 서비스 중인 퍼블리셔에도 배포를 해야 하기 때문에 그동안은 쿼리를 사용하여  JOB 에이젼트를 이용하였습니다. (정말 무식하게 job 단계가 98단계에 이릅니다.)

하지만 워낙에 많은 데이터를 수집하고 집계하는데 작업단계가 너무 복잡하고 처리 순서에 대한 유연성이 아쉬웠습니다.

그래서 MS에서 제공하는  SSIS를 이용하여 데이터를 수집하는 방법으로 변경하는 방안을 검토 중입니다.

 

오늘 포스팅은 단순하게 데이터를 가져오는 방법과 변수를 이용하여 테이블을 가져오는 방법 과변수를 이용하여 특정 테이블 가져오기 입니다..

 

테이블 테이블 데이터 복사하기.

 

1.     우선 테스트 테이블을 생성 합니다.

1.png

 

원본테이블  : tbl_20110630

대상테이블 : tbl_20110701

원본 테이블에 데이터를 입력 합니다.

2.     SSBID 를 실행합니다..

2.png

 

3.     새프로젝트에서 [Integration Service 프로젝트]를 선택 합니다.

3.png

4.     메뉴바에서  [SSIS] – [변수]를 선택합니다.

3_1.png

 

5.     [제어흐름] 탭을 선택하고 [도구상자]에서 [데이터 흐름 태스크]를 마우스로 끌어다 놓습니다. [속성]에서 [Name] [Log수집] 이라고 수정합니다.

4.png

 

6.     [데이터흐름] 탭으로 이동하여 [OLE DB원본] [OLE DB 대상] 을 끌어 놓습니다.

5.png

 

7.     [OLE DB원본] 에서 마우스 오른쪽 [편집] 을 선택 하여 [데이터액세스 모드][테이블 또는 뷰] 로 선택하고  [테이블 또는 뷰이름]에서는 [dbo].[tbl_20110630]을 선택 합니다.

6.png

 

8.     [OLE DB대상] 에서 마우스 오른쪽 클릭 [편집]을 선택하여 [데이터 액세스 모드][테이블 또는 뷰 빠른 로드] 를 선택 합니다. [테이블 또는 뷰 이름] 에서는 [dbo].[tbl_20110701]을 선택합니다.

7.png

 

9.      녹색 선을 연결하고실행을 선택 합니다. 원본테이블에서 대상테이블로 데이터가 복사된 것을 확인 할 수 있습니다.

8.png

 

변수를 이용하여 특정 테이블 복사하기

1.     앞의 실습까지 따라 하였으면 다시 [제어흐름] 탭으로 이동합니다. 그리고 [도구 상자]에서 [스크립트 태스크]를 마우스로 끌어다 놓습니다. [편집]을 선택합니다.

9.png

 

2.     사용할 변수명을 적고 변수선택 버튼을 클릭하면 어떤 형식의 변수를 사용할건지 선택합니다.

10.png

 

3.     변수선택이 끝났으면 [스크립트 편집] 버튼을 클릭합니다.

11.png

 

4.     스크립트 편집을 클릭하면 새로운 SSIS창이 나타납니다. 여기서 프로그램을 입력합니다.

아래의 그림처럼 따라서 입력합니다. 그리고 저장. 창을 닫습니다.

12.png

 

5.     [제어흐름] 탭에서  [OLE DB원본] 에서 [편집]을 선택 합니다. [데이터 액세스 모드] 에서 [테이블 이름 또는 뷰 이름 변수]를 선택 합니다. 그리고 변수이름을 지정합니다

13.png

 

6.     이미 대상 테이블에 데이터가 있다면 테이터를 삭제한 후 SSIS 패키지를 실행하여 데이터가 정상적으로 입력되었는지 확인 합니다.

14.png

 

위의 방법은 일자별또는 테이블 이름이 바뀌는 데이터를 가져올 때 특정 변수를 입력하여 해당 테이블을 가져올 때 매우 유용할 듯 합니다. 필자는 실제로 날짜로 테이블명이 생성되는 테이블테 가져올 때 유용하게 사용하고 있습니다.

 

위의 방법 둘다 로그를 쌓지 않고 가져오기 때문에 매우 빠른 속도로 데이터를 가져오는 것을 확인 할 수 있습니다.

많이 활용 하시길 바랍니다.
반응형
반응형

Default Value 지정된 테이블에 Attunity Provider 데이터 입력할 경우

Microsoft Premier Field Engineer

한대성

 

Attunity Provider SQL Server 2008 Enterprise Edition 사용할 경우에 무료로 제공되는 3rd party Provider이다. 기존의 OLE DB 또는 .NET 대상에 비해 Bulk Insert 처리를 있다는 장점이 있다. 실제 고객 사례에서 기존의 OLE DB 대상을 사용했을 때에 비해 Attunity Provider 사용했을 때가 수십 빠른 속도를 보인 적도 있다. (OLE DB 대상 – 22 소요, Attunity 대상 – 27 소요)

하지만, Oracle 대상 테이블에 Default 열이 지정되어 있는 경우에는 고려해야 사항이 있다.

 

 

테스트 환경

다음과 같이 Oracle Default Value 지정된 테이블을 준비한다.

 

BIDS에서 데이터 흐름 작업을 추가한 , 다음과 같이 간단한 예제 데이터 원본을 생성한다.




 

TEST 1 – Oracle Attunity 대상을 사용하고 Fast Load 옵션을 사용한 경우




 

실행 결과


è 
Default 값이 설정된 Not Null 열에 데이터를 입력하려고 경우, 아래와 같은 에러가 발생함

[Oracle 대상 [91]] Error: 로드 또는 종료 단계에서 빠른 로드 오류가 발생했습니다. Class:       Logical

Status:    0              Code:     0

Note:     

At:           ORAOPRdrpthEngine.c:1128

Text:       Conversion error on column '"DEFAULTCOL"'.              ORA-01400: NULL (DEFAULTCOL) 안에 삽입할 없습니다

 

 

TEST 2 – Oracle Attunity 대상을 사용하고 Fast Load 옵션을 사용하지 않는 경우




è 
동일한 에러 발생 – Attunity Provider 사용하는 경우, Fast Load 사용 여부와 상관없이 Not Null 열에 대한 검사 작업을 먼저 수행하기 때문에 이와 같은 에러가 발생함

 

 

TEST 3 – OraOledb.Oracle 이용한 OLE DB 대상을 사용한 경우


è 
정상 처리됨. Attunity Provider와는 달리, 단위 처리 방식으로 수행됨



 

 

해결 방법

1.       파생열 변환을 이용한 Default 추가

- 방법의 경우, Default Column 대해 열을 지정해줘야 하는 단점은 있지만 Attunity Provider 이용한 Bulk Insert 작업을 수행할 있다는 장점이 있다.

a.        파생열 변환(Derived Column) 추가한 , 데이터 원본과 연결한다.

b.       파생열 변환 속성을 다음, 아래와 같이 Default 입력할 값을 설정한다. , 데이터 타입을 맞추는 것이 필요하다. (Type Casts 문을 이용)


c.        다음과 같이, Default Column 대해서도 매핑을 설정한다.

 



 

 

2.       임시 테이블 사용

-          MSSQL에서 Oracle 임시 테이블에 Bulk Insert 처리한 , Oracle DB 내에서 테이블로 이관하는 방식. 임시 테이블 공간을 차지하지만, 처리 성능이 좋은 방법이다.

a.        Oracle Default Value 지정되지 않은 임시 테이블을 생성

b.       MSSQL에서 Attunity Provider 이용해서 Bulk Insert 처리

c.        SSIS에서 SQL 실행 작업을 이용해서 Oracle 임시 테이블에서 테이블로 Insert하는 SQL 쿼리를 실행

 

3.       Attunity Provider 대신 OLE DB Provider(MSDAORA or OraOLEDB) 사용해서 처리

-          추가적인 테이블 생성이나 변경 없이 기존 테이블을 그대로 사용할 있다는 장점은 있지만, 데이터 양이 많을 경우 처리 속도가 늦을 있다.

 

권장 방식은 1 또는 2번임

--
반응형
반응형

데이터 원본에 저장 프로시저 사용하기

 

Microsoft Premier Field Engineer

한대성

 

모처럼 오랜만에 글을 올리네요. 우연찮게 좋은 방법을 알게 되어 공유하고자 올립니다.

 

SSIS에서 데이터 흐름 작업을 사용할 때 여러 제약 사항들 때문에 사용하기가 까다로운 경우가 있었을 것입니다. 다음과 같은 형태의 저장 프로시저를 예로 들어보겠습니다.

CREATE PROC TestProc

AS

        CREATE TABLE #RESULT

        (

               SEQ INT,

               COL1 INT,

               COL2 INT

        )

 

        INSERT #RESULT VALUES(1,2,3)

        INSERT #RESULT VALUES(4,5,6)

 

        SELECT * FROM #RESULT

GO

 

EXEC dbo.TestProc

/*

SEQ         COL1        COL2

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

1           2           3

4           5           6

*/


지극히(?) 정상적인 프로시저처럼 보입니다. 이러한 형태로 프로시저를 만들어서 SSIS의 데이터 원본에서 막 쓸려고 하면,



이와 같은 에러 메시지가 나타나면서 열 정보를 설정할 수가 없습니다. 어떻게든 열 정보가 나와야 매핑을 설정할 수 있을 것인데 열 정보가 나타나지 않으니 더 이상 쓸 수가 없습니다.

 

1. SET FMTONLY OFF 구문을 추가

우선, 다음과 같이 저장 프로시저에 SET FMTONLY OFF 구문을 추가하고 실행해 봅시다.

ALTER PROC TestProc

AS

 

SET FMTONLY OFF

 

        CREATE TABLE #RESULT

        (

               SEQ INT,

               COL1 INT,

               COL2 INT

        )

 

        INSERT #RESULT VALUES(1,2,3)

        INSERT #RESULT VALUES(4,5,6)

 

        SELECT * FROM #RESULT

GO



열 정보가 잘 나타납니다. ~!

이렇게 처리되는 이유를 간략히 설명하자면 다음과 같습니다.

A.     SSIS에서 열 정보를 읽어올 때에는 자동으로 SET FMTONLY ON 옵션을 켠 상태에서 저장 프로시저의 열 정보를 읽어오게 됩니다. SET FMTONLY ON 옵션은 클라이언트의 메타 정보만 반환합니다. 쿼리를 실제로 실행하지 않고 응답 형식을 테스트하는 데 사용할 수 있습니다.”로 도움말에 설명되어 있습니다.

B.     문제는 SET FMTONLY ON 옵션으로는 임시 테이블이 생성되지 않는다는 점입니다. SET FMTONLY ON 옵션을 켠 상태에서 프로시저를 실행하니깐 임시 테이블이 안 만들어지고, 임시테이블이 없으니깐 열 정보를 몰라서 열 매핑이 실패하는 것입니다.

C.     프로시저 내에 강제로 SET FMTONLY OFF 명령을 넣어버렸습니다. 이렇게 하면 SSIS에서 열 정보를 읽어갈 때 SET FMTONLY ON 명령을 켜서 들어왔더라도 OFF 시켜서 임시 테이블을 만들고 이에 대한 정보를 읽어갈 수 있게 됩니다.

복잡하면 통과.. 하지만, 여기서 끝은 아닙니다. 이제 패키지를 대충 구성해서 실행시켜 봅니다.





[OLE DB Source [1]]
오류: A rowset based on the SQL command was not returned by the OLE DB provider.

이해하기 쉽지 않은 에러 메시지가 출력됩니다. 미리보기 해도 잘 나오고 열 정보도 잘 나오는데 뭐가 문제란 말인가.

 

2. SET NOCOUNT ON 구문을 추가

이번에도, 다음과 같이 저장 프로시저에 SET NOCOUNT ON 구문을 추가하고 실행해 봅시다.

ALTER PROC TestProc

AS

 

SET FMTONLY OFF

SET NOCOUNT ON

 

        CREATE TABLE #RESULT

        (

               SEQ INT,

               COL1 INT,

               COL2 INT

        )

 

        INSERT #RESULT VALUES(1,2,3)

        INSERT #RESULT VALUES(4,5,6)

 

        SELECT * FROM #RESULT

GO

 


~~수행됩니다.

SET NOCOUNT ON은 대충 어떤 기능을 하는지 아실 것입니다.

A.     SET NOCOUNT ON 옵션을 넣지 않은 상태에서 저장 프로시저를 실행 시키면 다음과 같이 처리 단계에서 실행된 결과를 반환합니다.

B.     SET NOCOUNT ON 옵션을 넣으면 다음과 같이 결과만 출력됩니다.

C.     SSIS의 데이터 흐름에서는 몇 개 행이 처리되었습니다.”라는 메시지도 결과값으로 인식해서 처리하게 됩니다. 이미 열 정보를 이용해서 세 개의 열이 출력될 것이다라고 설정해 놨는데 이상한(?) 문자열(1 rows(s) affected)이 먼저 나타나니깐 에러를 발생시킨 것입니다.

D.    SET NOCOUNT ON 옵션으로 저런 정보 메시지를 나타내지 않도록 한 것입니다. 자연히 미리 정한 열 정보 모양대로 출력되기 때문에 정상적으로 패키지가 실행됩니다.

 

 

SSIS Beta 버전부터 해왔지만 조금 전까지도 "SSIS에서는 이건 안 되는 기능이야.”라고 단정하고 있었던 내용입니다. 조금 더 깊이 살펴봤다면 좀 더 일찍 알 수도 있었을 수도 있었는데. 프로젝트 할 때 이것이 안되서 다른 방식으로 고생 고생해서 처리했던 생각이 나네요~~^^

 

반응형
반응형

마스터 패키지로 여러 패키지들의 연결 정보 관리하기

 

Microsoft Premier Field Engineer

한대성

 

다음과 같은 형태의 단순한 자식 패키지를 하나 만듭니다.

a.     Servername 이라는 String 형 변수를 추가합니다.

b.     ChildDBConn이라는 OLE DB 연결을 설정합니다. 본 예제에서는localhost\ss2005 서버를 가리키는 연결을 만듭니다.

c.     이 외에 여러 형태의 연결을 만듭니다. (옵션 사항임.)

d.     SQL 실행 작업을 추가한 후, 다음과 같이 설정합니다.



 

e.     스크립트 작업을 추가한 후, SQL 실행 작업과 연결하고, 속성의 ReadOnlyVariables 부분에 Servername을 입력한 후, 스크립트 편집기를 열어 다음과 같은 간단한 스크립트를 입력합니다.

Imports System

Imports System.Data

Imports System.Math

Imports Microsoft.SqlServer.Dts.Runtime

 

Public Class ScriptMain

 

            Public Sub Main()

                       

                        MsgBox(Dts.Variables("Servername").Value.ToString)

 

                        Dts.TaskResult = Dts.Results.Success

            End Sub

 

End Class

 

f.      완성된 자식 패키지 모습입니다.

 

g.     패키지를 실행하면 다음과 같이 기본으로 설정된 OLE DB의 서버 명이 출력됩니다.

 

 

다음과 같은 상황을 생각해 봅시다.

1.     위와 같은 형태의 패키지가 아주 많다.

2.     대부분 OLE DB 연결 명은 비슷하거나 동일하다.

3.     패키지를 실행 시킬 때, 다른 DB 서버 연결을 지정하고 싶다. , 위의 예에서 ChildDBConn이라는 연결이 localhost\SS2005로 지정되어 있지만, localhost DB 서버에서 실행되도록 하고 싶다.

4.     SQL Agent나 패키지를 실행시킬 때 Connection 탭에서 지정해주면 되겠지만, 패키지들이 많아서 번거롭다.

5.     또한, DB 서버를 일괄적으로 바꿀 수 있다. 그러면 다시 모든 패키지의 연결 정보를 (Agent 작업이든, 패키지 실행 스크립트이든, SSIS 패키지 자체이든) 바꿔줘야 한다.

6.     자식 패키지들이 많아서 일일이 어떤 기능을 추가하는 것도 어렵다.

 

이런 경우가 가끔씩 있습니다. 제 개인적인 경험도 수백 개의 패키지의 연결 정보를 관리해야 할 때가 있었습니다.

 

몇 가지 운영 방법들이 있겠지만, 다음과 같은 조건을 가지면서 할 수 있는 방법을 생각해 봤습니다.

1.     자식 패키지(=기존 패키지)를 수정하지 않았으면 좋겠다.

2.     연결 정보가 변경되더라도 최소한의 작업으로 이를 반영할 수 있었으면 좋겠다.

 

제가 생각해 본 방법은 일명 『마스터 패키지』라는 패키지 실행을 담당하는 부모 패키지를 이용하는 것입니다.

직접 AAA.dtsx라는 패키지를 실행하는 대신, Master.dtsx라는 마스터 패키지에 AAA.dtsx라는 패키지 이름을 던져주면(외부에서 변수 값을 지정하는 방식으로) 마스터 패키지에서는 연결 정보를 바꿔치기 한 후 이 패키지를 실행하는 방법입니다.

 

 

다음과 같은 형태로 마스터 패키지를 만들어 봅시다.

a.     PackageNameStr이라는 String형 변수를 추가하고, 기본값으로 자식 패키지의 경로를 입력합니다.

b.     ChildDBConn 이라는 String형 변수를 추가하고 다음과 같이 OLE DB의 연결 문자열을 입력합니다. 이 때의 문자열은 자식 패키지의 ChildDBConn 연결의 연결 문자열과는 다르게 지정합니다. 본 예에서는 localhost 서버를 가리키는 DB 연결 문자열을 설정합니다.



c.     스크립트 작업을 하나 추가한 후, 편집기의 ReadOnlyVariables 속성에 PackageNameStr,ChildDBConn을 입력합니다.

 

d.     스크립트 편집기를 연 후, 다음과 같은 스크립트를 입력합니다.

Imports System

Imports System.Data

Imports Microsoft.SqlServer.Dts.Runtime

 

Public Class ScriptMain

 

    Public Sub Main()

 

        Dim pkg As String

        pkg = Dts.Variables("PackageNameStr").Value.ToString

 

        Dim app As Application = New Application()

        Dim p As Package = app.LoadPackage(pkg, Nothing) ' 패키지 개체를 생성

 

        Dim con As ConnectionManager

 

        For Each con In p.Connections  ' 패키지 내의 연결들을 조사

 

            If con.AcquireConnection(Dts.Transaction).GetType.ToString = "System.__ComObject" Then ' OLEDB 연결일 경우

                If con.Name = "ChildDBConn" Then  ' 연결 이름이 ChildDBConn일 경우, 변수값으로 대체

                    con.ConnectionString = Dts.Variables("ChildDBConn").Value.ToString

                End If

            End If

 

        Next

 

        p.Execute() ' 패키지 실행

 

 

          Dim pkgError As DtsError

 

        If (p.Errors.Count > 0) Then ' 자식 패키지에서 에러가 발생한 경우, 이 정보를 전파

            p.Dispose()

            For Each pkgError In p.Errors

                Dts.Events.FireError(pkgError.ErrorCode, pkgError.SubComponent, pkgError.Description, pkgError.HelpFile, pkgError.HelpContext)

            Next

 

            Dts.TaskResult = Dts.Results.Failure

        Else

            p.Dispose()

            Dts.TaskResult = Dts.Results.Success

        End If

    End Sub

 

End Class

 

 

에러 전파 부분을 잠시 설명하겠습니다.

패키지 개체를 만들어 자식 패키지를 실행할 경우, 자식 패키지가 에러가 나더라도 이 정보가 전달이 안됩니다. , 무조건 성공으로 보이지요. 따라서 이를 개선하고자 추가한 부분입니다.

자식 패키지를 실행한 후, Error Count 0보다 크다면 에러 정보를 현재 패키지에 전달(FireError)하는 것입니다.

e.     패키지를 실행시켜 봅시다.

 

f.      SQL Agent에 패키지를 등록할 경우, 다음과 같이 설정합니다.






값 설정 탭에서

            \Package.Variables[사용자::PackageNameStr].Properties[Value] 라는 속성을 입력하고 값 부분에는

실행 시킬 패키지 명(경로 포함)을 입력함.
             
     

 

 

본 예제에서는 단순히 마스터 패키지에 자식 패키지에서 사용할 연결 정보(ChildDBConn)를 변수에다가 저장하는 식으로 구현했지만, 연결 정보가 많거나 연결 정보들을 별도의 파일이나 테이블 등에 관리할 경우, Recordset을 이용하여 ADO 개체에 저장하고 스크립트 작업을 조금 변경해서 매핑 & 변경 되도록 설정하면 되겠지요.

(글로 적으려니까 무지하게 길어지고 무슨 말인지 잘 모르겠네요.@.@)

 

반응형
반응형

TEXT 형이 포함된 Excel 데이터 가져오기 문제 - Registry 수정


 

Microsoft Premier Field Engineer

한대성

 


 

Excel à SQL Table 로 처리하는 패키지로 설명드리겠습니다.

 

다음과 같이 원본 엑셀 파일(원본 - stuanswer.xls)에 있는 데이터를 저장할 테이블(stuanswer)를 만듭니다.

USE tempdb

GO

 

CREATE TABLE STUANSWER

(

       UserID VARCHAR(20),

       TestID INT,

       QID INT,

       Answer TEXT,

       FeedBack TEXT,

       MyScore INT,

       IsEval_Commit CHAR(1)

)

GO

 

데이터 가져오기/내보내기 기능을 이용하여 패키지를 만들어도 되고, BIDS에서 직접 패키지를 만들어도 됩니다. 본 예제에서는 데이터 가져오기/내보내기 기능을 이용하여 패키지를 만들겠습니다.

 

다른 일반 문자열들은 자동으로 변환이 되어지는데 텍스트 유형의 열은 자동으로 변환이 이루어지지 않습니다. (Answer )

그래서, 다음과 같이 데이터 변환에서 Answer 열에 대해 직접 변환을 설정해 준 후,


데이터 대상에서 이 열로 매핑을 변경해줘야 합니다.

 

 

그럼 되느냐.. 에러가 발생합니다.


 

[Source - stuanswer$ [1]] 오류: The "output column "Answer" (24)" failed because truncation occurred, and the truncation row disposition on "output column "Answer" (24)" specifies failure on truncation. A truncation error occurred on the specified object of the specified component.

 

첫 단계인 엑셀 파일에서 SSIS의 데이터 원본으로 데이터를 가져오는 부분에서부터 에러가 나네요. 에러 메시지를 보아하니, 데이터가 짤리거나 코드가 안맞다라고 하는데, 엑셀이니깐 유니코드라 데이터 코드가 존재하지 않기 때문에 코드가 안맞다는 것은 아닐테고..데이터가 짤린다고 합니다.

Source-stuanswer$과 데이터 변환(Data Conversion 1) 사이의 녹색 라인을 더블 클릭해서 메타데이터를 확인해 봅시다.



Answer
255자리로 들어오네요. 그럼 데이터 중에 255자리가 넘는것이 있다라는 것인데..

확인을 위해 다음과 같이 구성해 봅시다.

1.     멀티캐스트 변환을 추가하고, 데이터 원본에서 빨간색 라인을 연결시킵니다. 멀티캐스트 변환은 아무것도 안하는 Dummy 대상으로 사용할 놈입니다.

2.     빨간색 라인을 연결시키면 다음과 같이 창이 뜨는데 여기서 아래와 같이 구성합시다.


Answer
열에서 잘림이 발생했을 때 오류로 처리하지 말고 이 쪽 길(빨간 색)로 에러나는 데이터를 보내라는 것입니다.

 

3.     빨간 색 라인을 더블클릭해서 나타나는 속성 창 중, 데이터 뷰에 부분에서 추가를 눌러 표를 추가합니다.

 

 

 

그런 다음 패키지를 실행시켜 봅시다.


또 에러가 발생하긴 했지만, 첫 번째 단계는 넘어섰네요.

위에서 보는 것과 같이 세 개의 데이터가 255자리를 넘는 놈들입니다.

그럼 엑셀의 255자리가 넘는 데이터는 SQL로 못 가져온단 말인가요? 물론 아닙니다.

 

다음 KB의 내용에 원인이 설명되어 있습니다.

http://msdn.microsoft.com/ko-kr/library/ms141683.aspx

Ÿ   잘린 텍스트. Excel 열에 텍스트 데이터가 포함되어 있음이 확인되면 드라이버는 샘플링하는 값 중 가장 긴 값을 기준으로 데이터 형식(문자열 또는 메모)을 선택합니다. 샘플링하는 행에서 255자보다 긴 값이 검색되지 않으면 이 드라이버는 해당 열을 메모 열이 아닌 255자 문자열 열로 처리합니다. 따라서 255자보다 긴 값은 잘릴 수 있습니다. 메모 열에서 데이터를 가져올 때 데이터가 잘리지 않도록 하려면 샘플링된 행 중 하나 이상의 행에 있는 메모 열에 255자보다 긴 값을 포함시키거나 드라이버가 샘플링하는 행 수를 늘려 이러한 행을 포함하도록 합니다. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Excel 레지스트리 키에서 TypeGuessRows 값을 늘려 샘플링할 행 수를 늘릴 수 있습니다. 자세한 내용은 PRB: Jet 4.0LEDB 원본에서 데이터를 전송하면 버퍼 오버플로 오류가 발생하면서 실패한다를 참조하십시오.

 

패키지를 실행시킬 서버(or PC)의 레지스트리의 값을 기본값인 8에서 0으로 변경합시다. 참고로 0 16384개의 행을 이용하여 유형을 정한다는 의미입니다.

 

그러고선 다시 데이터 가져오기/내보내기로 패키지를 만들어서 확인해 봅시다.


바꼈지요?

 

이제 패키지를 실행시켜봅시다.


 

 

참고 글

http://www.sqlleader.com/mboard.asp?exec=view&strBoardID=SS2005SSIS&strSearchWord=eXCEL&intSeq=1121

http://www.sqlleader.com/mboard.asp?exec=view&strBoardID=SS2005SSIS&strSearchWord=eXCEL&intSeq=1219
반응형
반응형

DelayValidation 속성을 이용하여 패키지 빨리 열기

 

Microsoft Premier Field Engineer

한대성

 

 

SSIS 패키지를 열 때, 가끔 시간이 아주 오래 걸리는 경우가 있습니다.

 

 

이 때 뭔가를 하려고 하면 아래쪽에는 다음과 같은 화나게 만드는 도움말이 나타납니다.

 

Visual Studio가 바쁜 건 알겠는데 나도 바쁘다고~!

 

이렇게 시간이 오래 걸리는 이유는 바로 유효성 검사 (Validation Check) 때문입니다. 유효성 검사는 질문들이나 강좌 글에서 몇 번 설명한 적이 있지만 다시 정리하는 차원에서 설명 드리겠습니다.

 

우선 이렇게 느린 원인부터 설명하면, 패키지를 열 때, SSIS는 자동으로 패키지 내부에 있는 각 작업들의 설정이 정확한 지를 체크합니다. 예를 들어 데이터 흐름 작업에서 특정 테이블로 데이터를 로딩하도록 해 놨는데, 해당 테이블이 존재를 하는지, DB 연결이 제대로 되는지 등 입니다.

 

만약 서버에서만 DB에 연결할 수 있는 상황에서, 서버에 있는 패키지를 로컬 PC로 복사해 와서 열어 볼 때 이와 같은 지연 현상을 자주 겪을 수 있습니다.

각 작업들에 대해 연결 정보가 정확한지 등을 체크하는데, 각 작업 별로 타임아웃이 발생할 때까지 기다리기 때문입니다. 타임아웃이 발생하면 BIDS에서는 사용자에게 친절하게도 다음과 같은 경고 메시지를 줍니다.


 

작업 개체들이 제법 많다면 패키지 열어보다가 쓰러질 수도 있습니다. (답답해서)

 

왜 저런 짓을 꼭 해야 하는 걸까요?

이유는 실컷 작업 돌리다가 에러를 발생하느니 시도하기도 전에 미리 경고를 주겠다는 목적입니다.

 

[작업 1] – [작업 2] – [작업 3] – [작업 4]

 

 이렇게 작업들이 연결되어 있는데, [작업 3]에서 사용하는 테이블이 없습니다. 이전 버전(DTS) 같은 경우는 작업 1 2가 끝나고 3이 되어서야 실패가 나는 걸 알 수 있습니다. 만약 작업 1 2가 시간이 엄청 오래 걸리는 작업이었다면? 다시 돌리든지, 아니면 작업 3부터 돌리도록 해야겠지요.

 

이런 수고(?)를 막기 위해 유효성 검사(Validation Check)라는 기능을 넣은 것입니다.

 

그럼 언제 검사를 하느냐?

 

1.     BIDS에서 패키지를 열 때

2.     패키지가 시작될 때

3.     해당 작업 개체가 시작될 때

입니다.

 

그럼 다음과 같은 경우는 어떨까요?

             [작업 1 – 임시 테이블 생성]

à [작업 2 - 데이터 흐름 작업 임시 테이블에 데이터 적재]

à [작업 3 – 임시 테이블 삭제]

 

작업 1이 시작되어야 테이블이 생성되고, 테이블이 생성되어야 작업 2인 데이터 흐름 작업이 수행된다고 할 때, 패키지를 열 때와 패키지가 시작되는 시점에서는 임시 테이블이 없기 때문에 작업 2에서 임시 테이블이 없다라고 유효성 검사 실패를 발생시킬 것이며, 이로 인해 패키지는 절대 수행이 안되게 됩니다.

 

그럼 어떻게 해야 하느냐? 작업 2의 유효성 검사를 미루어라. 언제까지? 해당 작업 개체, 즉 작업 2가 시작될 때까지.

그 속성이 바로 DelayValidation 옵션입니다.

작업 개체를 선택하고서 속성에 보면 기본값으로 False로 되어 있습니다. 이 속성을 True로 바꾸는 것이지요.



 

그러면 검사하는 3가지 경우 중, 1,2에 대해서는 검사를 하지 않게 됩니다.

 

이 속성은 패키지의 모든 개체뿐만 아니라 패키지 자체에 대해서도 설정이 됩니다.

패키지 자체, 즉 제어영역을 선택하고선 속성 중 DelayValidation True로 바꾸면 모든 개체들이 영향을 받을까요? 아닙니다. 그냥 제어 흐름 영역 자체에 대해서만 설정할 뿐 작업 개체나 연결 정보 등에는 영향을 미치지 않습니다.

 

그럼 패키지 내의 모든 개체들의 속성을 다 바꿔주고 싶은데?

원시적으로(^^) 일일이 개체들을 찍고선 속성을 바꿔주면 됩니다. 하지만 개체들이 엄청 많을 경우에는 힘들겠죠.

전 이렇게 합니다.

 

패키지 파일을 열기 전에 다음과 같이 View Code로 패키지를 엽니다. 이렇게 하면 패키지가 XML 파일 형태로 열립니다.

 

그런 다음, 찾아 바꾸기 메뉴를 이용해서

"DelayValidation">0</DTS:Property>   값을

"DelayValidation">-1</DTS:Property> 로 바꿉니다.



 

저장한 후, 열어보면 느끼실 수 있을 겁니다.

 

이러한 설정이 패키지 실행에 영향을 미치는 것은 아닌가 우려 되시나요?

패키지가 정상적으로 잘 돌아갔던 놈이라면 문제없습니다. , 앞에서 설명한 것과 같이 작업 3에서 테이블이 없는 경우, 패키지가 시작될 때 실패로 처리되는 것이 아니라 작업 3까지 와서야 실패가 된다는 차이는 있습니다.

 

 

반응형
반응형

이벤트 로그에서 패키지 실행 기록 분리하기

 

한대성

Microsoft Premier Field Engineer

 

 

SSIS 패키지가 수행되면 기본적으로 이벤트 로그의 어플리케이션 로그 부분에 수행 시작 및 종료 이벤트를 발생시킵니다.



 

만약 30초마다 수행되는 패키지가 있다면 2 * 30 * 120 * 24 = 86400 즉 하루에 172800 개의 이벤트 로그가 찍히게 됩니다. 이 정도의 이벤트 로그라면 로그로써의 기능을 상실했다라고 볼 수 있겠지요.^^

 

SQL 2005에서는 이러한 로그를 기록하는 기능을 비활성화 시킬 수는 없습니다.

 

http://technet.microsoft.com/ko-kr/library/cc966389(en-us).aspx

Custom Log Provider

To facilitate operations management, SSIS packages always write some basic logging information to the Windows event log, even for packages that do not incorporate logging. SSIS packages write events for package initiation and package completion and they can be identified using either the SQLISPackage or SQLISService event sources.

 

 

SQL 2008 SSIS 패키지에서는 다음과 같이 기본적으로 SSIS 패키지가 실행될 때 이벤트 로그를 발생시키지 않도록 설정되었으며, 레지스트리 값을 변경함으로써 로그를 남기도록 설정할 수 있습니다.

http://msdn.microsoft.com/en-us/library/ms143731.aspx

By default, in a new installation, Integration Services is configured not to log events that are related to the running of packages to the Application event log. This setting prevents too many event log entries when you use the Data Collector feature of SQL Server 2008. The events that are not logged are EventID 12288, "Package started," and EventID 12289, "Package finished successfully." To log these events to the Application event log, open the registry for editing. Then, in the registry, locate the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\SSIS node, and change the DWORD value of the LogPackageExecutionToEventLog setting from 0 to 1.

 

 

그럼 SQL 2005 SSIS 패키지는 절대 불가능한 것일까요?

 

다음과 같은 방법이 있습니다.

 

[주의] 아래에 설명드릴 방법은 Microsoft에서 권장하는 공식적인 방안은 아니며, 제 개인적인 의견으로 설명 드리는 것입니다. 기본적으로 설정된 시스템 레지스트리의 항목을 변경하고 시스템을 재시작 해야 하는 단계가 필요하기 때문에 적용 전에 반드시 충분히 검토하시기 바랍니다.

 

 

1.     실행 à regedit 를 실행시켜 레지스트리 편집기를 엽니다.

2.     HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog 키를 엽니다.

 

3.     EventLog 항목에서 마우스 오른쪽 버튼을 눌러 새로 만들기 Key를 선택한 후, 다음과 같이 이름을 SSIS로 바꿉니다.

 

4.     SSIS 아래에 SQLISPackage 라는 Key를 추가합니다.

 

5.     이제 확인할 것이 있습니다. EventLog 항목 아래에 Application 항목 아래에 보면 SQLISPackage 부분이 있습니다. Key를 선택한 후, 오른쪽 부분을 보면 EventMessageFile이라는 항목이 있습니다. 이 값을 더블 클릭해서 Data 부분의 값을 메모장 같은 곳에 복사합니다.

 


 

6.     SQLISPackage를 선택한 후, 오른쪽의 창에서 새로 만들기를 선택한 후 문자열 값(String Value)를 선택하고 이름을 EventMessageFile로 변경합니다. 또한 이 값을 더블 클릭해서 5단계에서 복사한 값을 채워 넣습니다.


 

7.     이제 5단계 부분의 항목인 Event à Application à SQLISPackage 항목을 삭제합니다.

 

8.     시스템을 재 시작 합니다.

 

9.     이제 이벤트 로그 부분을 확인해 보면 다음과 같이 SSIS 항목이 새로 나타나는 것을 볼 수 있습니다. (PC OSWindows 2008이라 Windows 2003과는 다를 수 있습니다.)

 

 

 

10.   SSIS 패키지 수행 관련 로그는 이제 SSIS 항목에만 기록됩니다.



반응형
반응형

SSIS 패키지를 실행할 주의 사항

 

한대성

Microsoft pREMIER FIELD ENGINEER

 

 

 

SSIS 패키지를 만들어서 수행할 , 수동으로 패키지를 돌리는 경우가 종종 있습니다.

패키지의 일부분을 수정한 , 그냥 BIDS 내에서 실행을 시키는 것이지요. 정확히 말해 이러한 행위는 SSIS 패키지 디버깅 작업입니다.

 

패키지 내의 작업 개체가 별로 많이 않을 때에는 상관없지만, 다음과 같은 경우에는 실행시킬 주의하셔야 것이 있습니다.

 

예를 들어 다음과 같이 간단한 패키지를 고려해 봅시다.

 


그림
1) 단순 반복 수행하는 패키지

 

For 루프 컨테이너에서 1000 반복 수행을 하는 단순한 패키지 입니다.

 

패키지를 BIDS 내에서 실행시켰을 때와 dtexec.exe 명령으로 실행시켰을 때의 수행 시간과 서버(패키지가 실행되는) CPU 비교해 보면 다음과 같습니다.

 


그림
2) BIDS에서 실행시켰을

 

 


그림
3) DTEXEC 명령을 이용해서 실행시켰을

 

 


그림
4) % CPU 성능 비교

 

구분

BIDS 내에서 실행

Dtexec 명령 이용 실행

수행 시간

20.608

3.9

% of CPU

최대 100

최대 58

 

BIDS 내에서 패키지를 잘못 실행했다간 서버 다운 시킬 있습니다.

참고로, 패키지와 같이 많은 횟수를 반복해서 수행할 경우, BIDS Process 부분에 결과를 뿌리는 부분에서 상당한 부하를 발생시키기도 합니다.


그림
5) Progress 결과 출력 화면

 

출력할 결과가 아주 많은 경우, 패키지를 중지시켜도 결과를 출력하는 작업 때문에 서버가 거의 멈추는 경우도 발생할 있습니다. 이를 방지하기 위해 SSIS 2008에서는 다음과 같은 고마운(^^) 기능이 추가되었습니다.


그림
6) 진행률 보고 디버깅 활성 여부 옵션

 

반복 수행이 많을 경우, 위의 옵션을 상태에서 BIDS에서 패키지를 실행시키는 것이 그나마 안전하게 패키지를 수행하는 방법입니다.

 

 

 

결론

작업 개체(=태스크) 많은 패키지의 경우, 직접 BIDS에서 수행하지 말고 dtexec 명령을 이용해서 패키지를 수행토록 한다~!

 

 

반응형
반응형

데이터 내보내기를 이용한 유니코드 유니코드 변환 만들기

 

한대성

 

 

오늘은 개인적으로 종종 이용하는 방법에 대해 소개하고자 합니다.

SSIS 이용해서 데이터를 주고 받는 작업을 하다 보면 기존의 SQL 2000 DTS 쿼리와는 다르게 여간 까다로운 아닙니다. 여기서 까다롭다라는 것은 Unicode-NonUnicode 일치, Code Page 일치, Length 일치 등을 말합니다. 이러한 까다로움은 임의로 변환을 해서 데이터가 이상하게 전달되는 것을 막고자 하는 일반적인 ETL 툴의 특징이긴 하지만, 쿼리나 어플리케이션 등에서 생각 없이 사용했던 환경이라면 귀찮은 특징이지요.

 

예제 설명을 위해 임시 테이블들을 준비합니다.

USE TEMPDB

GO

 

CREATE TABLE NonUnicodeSource

(

             Seq INT IDENTITY,

             Col1 VARCHAR(20),

             Col2 VARCHAR (20)

)

GO

 

CREATE TABLE UnicodeSource

(

             Seq INT IDENTITY,

             Col1 NVARCHAR(20),

             Col2 NVARCHAR(20)

)

GO

 

INSERT NonUnicodeSource(Col1, Col2) VALUES ('테스트데이터', '테스트데이터')

INSERT NonUnicodeSource(Col1, Col2) VALUES ('테스트데이터', '테스트데이터')

INSERT NonUnicodeSource(Col1, Col2) VALUES ('테스트데이터', '테스트데이터')

GO

 

INSERT UnicodeSource(Col1, Col2) VALUES (N'테스트데이터', N'테스트데이터')

INSERT UnicodeSource(Col1, Col2) VALUES (N'테스트데이터', N'테스트데이터')

INSERT UnicodeSource(Col1, Col2) VALUES (N'테스트데이터', N'테스트데이터')

GO

 

CREATE TABLE NonUnicodeTarget

(

             Seq INT,

             Col1 VARCHAR(20),

             Col2 VARCHAR(20)

)

GO

 

CREATE TABLE UnicodeTarget

(

             Seq INT,

             Col1 NVARCHAR(20),

             Col2 NVARCHAR(20)

)

GO

 

 

다음과 같이 SQL 쿼리를 이용한다면 유형에 상관없이 처리됩니다.

 

INSERT NonUnicodeTarget

SELECT * FROM UnicodeSource

GO

/*

(3 row(s) affected)

*/

 

INSERT UnicodeTarget

SELECT * FROM NonUnicodeSource

GO

/*

(3 row(s) affected)

*/

 

하지만, SSIS 패키지로 만들면 다음과 같이 기분 나쁜 경고를 띄우면서 실행조차 안됩니다.

 

쿼리나 DTS에서는 암시적 변환(Implicit Conversion) 일어나서 그냥 무시하고 들어가지만 SSIS에서는 허용 하겠다라는 것이지요. 이와 관련해서는 이전에도 여러 글에서 다루었습니다.

 

코드 코드 터로

유니코드 또는 비유니코드 문자열 데이터 형식으로 변환 오류

 

정석대로 데이터 원본과 데이터 대상 간에 파생 열을 추가해서 변환을 주는 것이 가장 좋긴 합니다.



 

그런데, 테이블의 열이 많다면 아주 귀찮은 작업이지요. 필자는 열이 300개가 넘는(이걸 테이블이라고 해야하나...) 경우를 매핑한 적이 있습니다.

 

 

간혹 사용하는 방법인데, 매핑을 편리하게 하는 방법을 소개하겠습니다.

데이터 가져오기/내보내기를 이용하여 패키지를 만드는 것이지요.



 

데이터 내보내기를 이용해서 원본 테이블 또는 쿼리와 대상 테이블을 설정하고선,



 

패키지를 실행하지 말고 저장합니다.



 

저장된 패키지를 열어보면 다음과 같이 이쁘고 친절하게(^^) 변환을 해놨습니다.




 

데이터 흐름 자체를 복사해서 개발하는 패키지에 붙여 넣기 , 연결 정보만 정확히 맞춰주면 됩니다.

 

~!!!

NCHAR에서 CHAR 매핑 시킬 때에는 신경 쓰셔야 합니다. SSIS 문제가 아니라 DB 데이터 상의 문제입니다. NCHAR(10) CHAR(10)으로 데이터 옮기면 쿼리상에서도 데이터 잘린다고 에러를 냅니다. SSIS에서도 마찬가지로 패키지는 만들어지는 실행 시키면 데이터가 잘리기 때문에 에러가 발생합니다. 경우에는 변환 작업에서 길이를 배로 늘려주면 됩니다.

 , NCHAR(10) CHAR(20)으로 매핑 되도록 대상 테이블을 만들 만들어주신다면 위와 같은 방법으로 처리할 있습니다.

 

반응형
반응형
Event Log를 활용해보자. (응용 편)

백도훈

에이디컨설팅 선임 컨설턴트
 


 

1.       Temp라는 이름의 Int32 변수 생성합니다.

2.       SQL 실행 작업 추가하겠습니다.

3.       Connection 속성으로 아무 DB에나 연결해주세요.

4.       SQLStatement 속성에 아래의 쿼리를 입력합니다.

select 1 as V where 1 = 0

5.       ResultSet 속성을 단일 행으로 선택합니다.

6.       결과 집합 메뉴에서 결과 이름을 V, 변수 이름은 Temp 설정해주세요.

 

 

7.       , 이제 상단의 이벤트 처리기 탭을 선택해서 에러가 발생했을 수행할 작업을 설정해보도록 하겠습니다.

8.       실행 파일은 패키지를 선택해주시고 이벤트 처리기는 OnError 선택해주세요.
저의 경우에는 패키지 명이 ADEventLog.dtsx였기 때문에 아래와 같은 상태입니다.

 

 

9.       화면에서 스크립트 작업 추가합니다.
스크립트 메뉴의 ReadOnlyVariables 속성에 다음과 같은 변수를 설정합니다.
SourceName, PackageName, ErrorDescription
왠지 너무 급하게 같아서 여기까지 작업을 한데 모아서 인증 샷을 찍겠습니다.


별로 감흥이 없군요 -,.a

 

10.    계속 갑니다. 스크립트 디자인 버튼을 클릭하여 VS for App 창을 열고 아래의 소스를 입력합니다.

Imports System

Imports System.Data

Imports System.Math

Imports Microsoft.SqlServer.Dts.Runtime

Imports System.Diagnostics

 

Public Class ScriptMain

    Public Sub Main()

        Dim PackageName As String = "P_" + Dts.Variables("PackageName").Value.ToString

        Dim ErrorDescription As String = Dts.Variables("ErrorDescription").Value.ToString

        Dim SourceName As String = Dts.Variables("SourceName").Value.ToString

 

        If Not EventLog.SourceExists(PackageName) Then

            EventLog.CreateEventSource(PackageName, "SSIS Log")

        End If

 

        EventLog.WriteEntry(PackageName, SourceName + ": " + ErrorDescription)

 

        Dts.TaskResult = Dts.Results.Success

    End Sub

End Class

앞에서 추가한 SourceName, PackageName, ErrorDescription 변수들은 시스템 변수들로서 우리에게
어느 패키지, 어디에서, 어떤 에러가 났다는 것을 알려줄 고마운 친구들입니다.
마구마구 사용합니다;;;


제어 흐름에서 추가한 SQL 실행 작업은 단일 행을 설정하고 변수와 매핑을 시켰기 때문에 값이 들어
와야 하지만 쿼리 상으로 아무 값도 넘어오지 않기 때문에 에러가 발생합니다.

에러를 기록하기 위해서 이벤트 처리기의 OnError 이벤트에 어떤 작업을 설정해놔서 에러가 발생하면
이벤트 로그에 남기도록 구성을 것입니다.

이벤트 처리기로 처리했으니 다른 에러 처리도 추가해보겠습니다.

 

11.    제어 흐름 디자인 창으로 돌아와서 데이터 흐름 작업 추가하고 SQL 실행 작업과 연결합니다.
위의 SQL 실행 작업은 에러가 발생할 이므로 연결 선을 더블 클릭해서 선행 제약 조건 편집기 창을
띄웁니다. 거기서 값을 성공에서 완료로 변경합니다.

 

12.    데이터 흐름 작업을 더블 클릭해서 데이터 흐름 디자인 창으로 들어옵니다.
OLE DB
원본 추가하고 연결 관리자는 아까 생성한 DB 설정합니다.
데이터 액세스 모드는 SQL 명령으로 변경합니다.
SQL
명령 텍스트 입력 창에 아래의 쿼리를 입력합니다.

select '1' AS InputCol union all

select '2' AS InputCol union all

select '3' AS InputCol union all

select 'aaa' AS InputCol union all

select '0' AS InputCol union all

select '4' AS InputCol union all

select '5'


강좌를 성실히 읽어 분이라면 위의 쿼리를 제가 어디서 가져왔는지 아실 텐데… ^^;;;.
스크립트 변환에서 오류 처리하기 강좌에서 사용된 쿼리입니다.

13.    스크립트 구성 요소 추가합니다.
입력 메뉴에서 InputCol 선택해주시구요.
/출력 메뉴에서 출력0 > 출력 열을 선택하시고 추가를 하겠습니다.
이름은 OutputCol 좋겠네요.
데이터 타입은 부호 없는 4바이트 정수 [DT_I4] 설정합니다.
출력0 선택하시고 우측 공용 속성 ExclusionGroup 0 아닌 다른
(
여기서는 1)으로 변경합니다.
스크립트 메뉴를 선택하시고 스크립트 디자인을 클릭하셔서 VS for App 창을 엽니다.

여기까지의 인증 ~!

 

왠지 인증 샷이 사람을 혼란하게 만드는 같습니다. 하지만 컷씩 캡쳐 했더니 나중에 이미지가 너무 많아져서;;;
이해 해주세용~ ^^;;

 

14.    VS for App 아래의 소스를 입력합니다.

Imports System

Imports System.Data

Imports System.Math

Imports Microsoft.SqlServer.Dts.Pipeline.Wrapper

Imports Microsoft.SqlServer.Dts.Runtime.Wrapper

Imports System.Diagnostics

 

Public Class ScriptMain

    Inherits UserComponent

 

    Public Overrides Sub 입력0_ProcessInputRow(ByVal Row As 입력0Buffer)

        Dim i As Integer

 

        Try

            i = CInt(10 / CInt(Row.InputCol))

            Row.OutputCol = i

            Row.DirectRowTo출력0()

        Catch ex As Exception

            Dim PackageName As String = "P_ADEventLog"

            Dim TaskName As String = "스크립트 구성 요소"

 

            If Not EventLog.SourceExists(PackageName) Then

                EventLog.CreateEventSource(PackageName, "SSIS Log")

            End If

 

            EventLog.WriteEntry(PackageName, _

                "Where: " + TaskName + System.Environment.NewLine + "Error Message: " + ex.Message)

        End Try

    End Sub

 

End Class

 

여기서는 Try ~ Catch 문으로 에러를 처리하려고 합니다. 자세한 설명은 한대성 님의 스크립트 변환에서
오류 처리하기 강좌를 한번 읽어주세요. ^^;;;

 

15.    데이터 흐름 디자인 창으로 나와서 멀티 캐스트 같은 작업을 하나 추가하고 스크립트 구성 요소와 연결해줍니다.
~ 이제 준비가 됐으니 실행을 해볼까요?

 

16.    디버깅을 해봅니다.
저의 경우에는 다음과 같은 결과가 출력되었습니다.



이벤트 로그로 달려가봅니다.
어떤 로그가 남겨졌을까요


메일도 아닌 것이 3통이 와있습니다.



위에서 말했다시피 SQL 실행 작업에서 단일 결과 집합이 반환되지 않아서 오류가 발생했고,
스크립트 구성 요소에서 변환 실패와 0으로 나누려는 때문에 오류가 2차례 발생하였습니다.

 

이벤트 처리기에 등록하거나 Try ~ Catch 문을 이용하면 오류를 로그로 남기는 것이 가능하리라 생각됩니다.

아무리 생각해도 스크립트 작업은 SSIS에게 날개를 달아준 같습니다. ^^;;; MS 인듯
반응형
반응형
Event Log를 활용해보자. (이론 편)


백도훈

에이디컨설팅 선임 컨설턴트
 


스크립트
변환에서 오류 처리하기
강좌를 읽다가

이벤트 로그에 오류를 기록해보는 어떨까? 라는 생각이 들었습니다.

 

날은 생각만 하고 지나갔는데

원격에서 패키지 호출하기 강좌를 읽다가 호출된 패키지 내에서는

중간에 어떤 값이 넘어가고 있는지 궁금했지만 메시지 박스도 뜨지 않아서

체크하는 것이 어려웠습니다.

 

어떤 오류나 정보를 테이블에 기록하고 오류를 관리하는 체계적인 방법임에 틀림없습니다.

하지만 패키지 개발 중에 어떤 값이 넘어가는지 어떤 오류가 뜨는 잠깐 확인할

이벤트 로그(뷰어) 활용하면 좋을 같습니다.

 

스크립트 작업에서 이벤트 로그를 남기는 방법에 대해서 함께 생각했으면 합니다.

 

1.       Int32 데이터 형식의 Value라는 변수를 추가합니다. (기본 값은 0)

2.       SQL 실행 작업을 추가합니다.

3.       Connection 속성으로 아무 DB 연결합니다.

4.       SQLStatement 속성에 다음의 쿼리를 입력합니다.

SELECT ? = CONVERT(INT, RAND() * 100)

5.       매개 변수 매핑 메뉴에서 추가 버튼을 클릭하고
변수 이름은 Value, 방향은 OutPut, 데이터 형식은 LONG, 매개 변수는 0 입력합니다.

 

이제 변수 Value안에는 어떤 정수가 들어갈 텐데 어떤 값이 들어가는지 아무도 모릅니다.

 

6.       스크립트 작업을 추가하고 SQL 실행 작업과 연결합니다.

7.       ReadOnlyVariables 속성에 Value, PackageName, TaskName 입력합니다.

8.       스크립트 디자인 버튼을 클릭해서 VS for App 엽니다.
우리가 사용할 클래스는 System.Diagnostics.EventLog이고 로그를 남기는 함수는 WriteEntry()입니다.
아래의 소스를 입력합니다.

Imports System

Imports System.Data

Imports System.Math

Imports Microsoft.SqlServer.Dts.Runtime

Imports System.Diagnostics

 

Public Class ScriptMain

    Public Sub Main()

        Dim PackageName As String = Dts.Variables("PackageName").Value.ToString

        Dim TaskName As String = Dts.Variables("TaskName").Value.ToString

        Dim Value As String = Dts.Variables("Value").Value.ToString

 

        EventLog.WriteEntry(PackageName, _

            "TaskName: " + TaskName + System.Environment.NewLine + ": " + Value)

 

        Dts.TaskResult = Dts.Results.Success

    End Sub

End Class

Imports 줄에 함수 의외로 간단한가요? -_-;;;
WriteEntry
함수의 번째 변수는 이벤트 로그의 소스(원본) 기록될 내용이고
번째 변수는 설명 부분에 기록될 메시지입니다.

9.       ~ 실행 해보겠습니다. F5 디버깅 버튼을 살포시 눌러주세용~
그리고, 관리 도구로 달려가서 우리를 기다리는 이벤트 뷰어를 열어보겠습니다.


응용 프로그램 이라는 로그 파일에 패키지 이름이 원본으로 들어간 이벤트가 등록되었습니다.
설명 부분에 보니깐 작업 이름과 넘어온 값이 기록되었군요.

정도만 되더라도 만족할만하군요.
하지만 여기서 조금 응용을 해보도록 하겠습니다.

이벤트 뷰어를 보면 응용 프로그램, 보안, 시스템 등의 로그가 있습니다.
응용 프로그램 로그에 남기지 말고 SSIS 패키지 전용 로그를 만들어서 SSIS 패키지에서 남기는
이벤트는 모두 로그에 남기도록 해보겠습니다.

 

10.    스크립트 작업의 내용을 조금 변경하겠습니다. VS for App 열어주세요.
소스를 다음과 같이 바꿔줍니다. (Copy & Paste 하는 것이 정신 건강에 이로울지도… -_-;;)

Imports System

Imports System.Data

Imports System.Math

Imports Microsoft.SqlServer.Dts.Runtime

Imports System.Diagnostics

 

Public Class ScriptMain

    Public Sub Main()

        Dim PackageName As String = "P_" + Dts.Variables("PackageName").Value.ToString

        Dim TaskName As String = Dts.Variables("TaskName").Value.ToString

        Dim Value As String = Dts.Variables("Value").Value.ToString

 

        If Not EventLog.SourceExists(PackageName) Then

            EventLog.CreateEventSource(PackageName, "SSIS Log")

        End If

 

        EventLog.WriteEntry(PackageName, _

            "TaskName: " + TaskName + System.Environment.NewLine + ": " + Value)

 

        Dts.TaskResult = Dts.Results.Success

    End Sub

End Class

 

 

달라진 것은 무어냐?

If Not EventLog.SourceExists(PackageName) Then

        EventLog.CreateEventSource(PackageName, "SSIS Log")

End If

이것입니다.

영어 시간은 아니지만 위의 지문을 해석하자면
“PackageName
이라는 변수 안에 들어있는 문자열을 원본으로 하는 로그가 있냐?
없으면 앞으로 원본은 SSIS Log라는 이름의 로그에 기록하겠다.”
라는 뜻으로 의역할 있습니다.

그러면 우리의 친절한 닷넷씨는 만약 SSIS Log라는 로그 파일이 없으면 파일을 만들어서 거기에
기록하고 파일이 있으면 그냥 로그 파일에 기록을 합니다.

그런데 우리는 조금 전에 패키지 이름으로 이벤트 로그에 남기도록 한번 실행을 했었습니다.
따라서 PackageName 변수 안의 문자열을 원본으로 하는 이벤트 로그가 응용 프로그램이라는
로그 파일에 저장이 됐었습니다.

 

따라서 새로운 이름으로 원본을 던져 필요가 있었는데 그래서

Dim PackageName As String = "P_" + Dts.Variables("PackageName").Value.ToString

패키지 이름 앞에 “P_” 붙여주었습니다.

이제 한번 실행해보겠습니다.

이벤트 뷰어를 보니 좌측 로그 파일 폴더에 아무것도 생기지 않았습니다.
제가 구라를 모양이 돼버렸습니다. -_-;;;

좌측 로그 파일 폴더는 새로 고침이 되질 않습니다.

따라서 이벤트 뷰어를 닫고 새로 열어보겠습니다.


SSIS Log라는 로그 파일이 생겼고 이벤트가 새로 등록되었습니다.

 

이렇게 이벤트 로그를 남기는 방법을 이용해서

에러 핸들링을 때는 물론이고 스크립트 작업을 하면서도 이벤트 로그를 남길 수가 있습니다.

남은 응용뿐
반응형
반응형


SQL 실행 작업에서 결과 값을 받아야 경우가 있습니다.

오늘 하려는 이야기는 결과가 단일 행일 경우에만 해당되는 이야기입니다.

 

일반적인 방법으로는 SQL 실행 작업 편집기에서 결과 집합을 변경하고



결과
집합에서 결과 이름과 변수 이름을 매핑 시켜서 받아오는 방법이 있습니다.


 

다른 방법으로는 매개 변수 매핑에서 매개 변수의 방향을 OutPut으로 변경해서 받아오는 방법이 있습니다.


 

그래서 여러 가지 경우에서 나타나는 방법의 차이점을 알아보고자 테스트를 생각입니다.


그래서 아래와 같은 패키지를 만들어서 비교를 해볼 생각입니다.


 

테스트 종류는 아래와 같습니다.

 

자료형

종류

1

String

있음

결과 집합

2

String

없음

결과 집합

3

String

있음

매개 변수 매핑

4

String

없음

매개 변수 매핑

5

Int32

있음

결과 집합

6

Int32

없음

결과 집합

7

Int32

있음

매개 변수 매핑

8

Int32

없음

매개 변수 매핑

 

- 변수의 준비

SSIS 패키지를 준비합니다.

변수를 8 생성합니다. 이름은 그냥 변수 1, 2, 3…으로 하겠습니다.

이름

데이터 형식

변수1

String

변수2

String

변수3

String

변수4

String

변수5

Int32

5

변수6

Int32

6

변수7

Int32

7

변수8

Int32

8

 

- 연결 관리자의 준비

하단의 연결 관리자에서 OLE DB 연결을 생성합니다. AdventureWorks에서 테스트 하겠습니다.

AdventureWorks 없다면 문자열과 숫자 형을 Select 있는 아무 DB 연결해도 상관없습니다.

연결 관리자 이름을 SourceDB 변경하겠습니다.

 

- 1) 결과 집합, String, 있음 (SQL 실행 작업)

1.        SQL 실행 작업 추가합니다. 이름은 1) 결과 집합, String, 있음이라고 변경하겠습니다.

2.        Connection 속성은 SourceDB 연결 해주고 SQLStatement 속성에는 아래의 쿼리를 입력합니다.

Select Top 1 Name From Production.Product

 

3.        ResultSet 속성을 단일 으로 변경하겠습니다.

4.        결과 집합 메뉴에서 결과 이름을 Name, 변수 이름은 변수1 설정 해줍니다.

 

- 2) 결과 집합, String, 없음 (SQL 실행 작업)

1.       SQL 실행 작업 추가합니다. 이름은 2) 결과 집합, String, 없음이라고 변경하겠습니다.

2.       Connection 속성은 SourceDB 연결 해주고 SQLStatement 속성에는 아래의 쿼리를 입력합니다.

Select Top 1 Name From Production.Product Where 1 = 0

 

3.       ResultSet 속성을 단일 으로 변경하겠습니다.

4.       결과 집합 메뉴에서 결과 이름을 Name, 변수 이름은 변수2 설정 해줍니다.
(
위의 1) SQL 실행 작업과 쿼리와 변수만 다르고 설정은 같으므로 캡쳐는 생략하겠습니다.)

 

- 3) 매개 변수, String, 있음 (SQL 실행 작업)

1.       SQL 실행 작업 추가합니다. 이름은 3) 매개 변수, String, 있음이라고 변경하겠습니다.

2.       Connection 속성은 SourceDB 연결 해주고 SQLStatement 속성에는 아래의 쿼리를 입력합니다.

Select Top 1 ? = Name From Production.Product

 

3.       매개 변수 매핑 메뉴에서 변수 이름은 변수3으로 방향은 OutPut, 데이터 형식은 VARCHAR,
매개 변수 이름은 0으로 설정해줍니다.

 

- 4) 매개 변수, String, 없음 (SQL 실행 작업)

1.       SQL 실행 작업 추가합니다. 이름은 4) 매개 변수, String, 없음이라고 변경하겠습니다.

2.       Connection 속성은 SourceDB 연결 해주고 SQLStatement 속성에는 아래의 쿼리를 입력합니다.

Select Top 1 ? = Name From Production.Product Where 1 = 0

 

3.       매개 변수 매핑 메뉴에서 변수 이름은 변수4 방향은 OutPut, 데이터 형식은 VARCHAR,
매개 변수 이름은 0으로 설정해줍니다.
(
위의 3) SQL 실행 작업과 쿼리와 변수만 다르고 설정은 같으므로 캡쳐는 생략하겠습니다.)

 

- 5) 결과 집합, Int32, 있음 (SQL 실행 작업)

1.       SQL 실행 작업 추가합니다. 이름은 5) 결과 집합, Int32, 있음이라고 변경하겠습니다.

2.       Connection 속성은 SourceDB 연결 해주고 SQLStatement 속성에는 아래의 쿼리를 입력합니다.

Select Top 1 ProductID From Production.Product Order By ProductID

 

3.       ResultSet 속성을 단일 으로 변경하겠습니다.

4.       결과 집합 메뉴에서 결과 이름을 ProductID, 변수 이름은 변수5 설정 해줍니다.
(
위의 1) SQL 실행 작업과 쿼리와 변수만 다르고 설정은 같으므로 캡쳐는 생략하겠습니다.)

 

- 6) 결과 집합, Int32, 없음 (SQL 실행 작업)

1.       SQL 실행 작업 추가합니다. 이름은 6) 결과 집합, Int32, 없음이라고 변경하겠습니다.

2.       Connection 속성은 SourceDB 연결 해주고 SQLStatement 속성에는 아래의 쿼리를 입력합니다.

Select Top 1 ProductID From Production.Product Where 1 = 0

 

3.       ResultSet 속성을 단일 으로 변경하겠습니다.

4.       결과 집합 메뉴에서 결과 이름을 ProductID, 변수 이름은 변수6으로 설정 해줍니다.
(
위의 1) SQL 실행 작업과 쿼리와 변수만 다르고 설정은 같으므로 캡쳐는 생략하겠습니다.)

 

- 7) 매개 변수, Int32, 있음 (SQL 실행 작업)

1.       SQL 실행 작업 추가합니다. 이름은 7) 매개 변수, Int32, 있음이라고 변경하겠습니다.

2.       Connection 속성은 SourceDB 연결 해주고 SQLStatement 속성에는 아래의 쿼리를 입력합니다.

Select Top 1 ? = ProductID From Production.Product Order By ProductID

 

3.       매개 변수 매핑 메뉴에서 변수 이름은 변수7 방향은 OutPut, 데이터 형식은 VARCHAR,
매개 변수 이름은 0으로 설정해줍니다.
(
위의 3) SQL 실행 작업과 쿼리와 변수만 다르고 설정은 같으므로 캡쳐는 생략하겠습니다.)

 

- 8) 매개 변수, Int32, 없음 (SQL 실행 작업)

1.       SQL 실행 작업 추가합니다. 이름은 8) 매개 변수, Int32, 없음이라고 변경하겠습니다.

2.       Connection 속성은 SourceDB 연결 해주고 SQLStatement 속성에는 아래의 쿼리를 입력합니다.

Select Top 1 ? = ProductID From Production.Product Where 1 = 0

 

3.       매개 변수 매핑 메뉴에서 변수 이름은 변수8 방향은 OutPut, 데이터 형식은 VARCHAR,
매개 변수 이름은 0으로 설정해줍니다.
(
위의 3) SQL 실행 작업과 쿼리와 변수만 다르고 설정은 같으므로 캡쳐는 생략하겠습니다.)

 

- 기타 설정

1.       SQL 실행 작업을 1번부터 8번까지 모두 연결해줍니다.

2.       그리고 마지막 8번에서 중단점 편집을 하겠습니다. OnPostExecute 이벤트를 받는 경우 중단을 사용하겠습니다.

 

3.       2), 6) 연결선에 작업을 한가지 해야 하지만 일단 실행을 해보겠습니다. F5 키를 눌러서 디버깅 해보겠습니다.

에러가 발생했습니다.

실행 결과 탭을 클릭해서 오류 메시지를 확인해보겠습니다.


단일 결과 집합이 지정되었지만 행이 반환되지 않았습니다.” 라는 오류 메시지를 확인할 있습니다.

4.       그럼, 테스트의 원활한 진행을 위해서 2), 3) 사이의 제약 조건을 변경하도록 하겠습니다.
디버깅을 중지하고 제어흐름 디자인 창으로 돌아옵니다.
2), 3)
사이의 작업 선을 더블 클릭해서 편집기를 엽니다. 제약 조건 성공을 완료로 변경하겠습니다.


다시 실행해보겠습니다.

! 예상됐던 바이지만 에러가 발생했습니다.


진행률 탭을 확인해보면 6)번에서도 2)번과 동일한 에러가 발생한 것을 확인할 수가 있습니다.

 

5.       4번의 작업을 6), 7) 사이의 작업 선에도 합니다. (선행 제약 조건을 편집합니다.)
다시 실행해보겠습니다.


 

6.       메뉴에서 디버그 > > 지역을 클릭해서 지역 변수 디버깅 창을 확인해보겠습니다.
Variables
트리를 열면 변수1~8까지 확인을 있습니다.

 

7.       분석
데이터가 있을 경우에는 데이터 형식에 관계없이 올바른 값을 가져오는 것을 확인할 있습니다.
2), 6)
번은 오류로 인한 실패가 발생했기 때문에 변수2, 변수6 값은 변수의 초기값에서 변하지 않았다고 생각할 있습니다.

2), 6)
번과 동일한 작업을 했지만 결과 집합 대신 매개 변수로 출력 값을 받은 4), 8)번은 오류가 발생하지 않았습니다.
대신 String 변수엔 빈 문자열 Int32 변수엔 이상한 값이 들어갔습니다.
이후에 별도의 SQL 실행 작업을 추가해서 테스트해봤더니 값은 계속 바뀌더군요.
DBNULL
값을 처리하게 되는 당시의 메모리 주소와 관계가 있지 않을까 조심스레 예상해봅니다.

 

8.       결론.
결과 집합을 이용하여 값을 가져올 때에는 실행하는 쿼리 내에서 Null 처리하도록
쿼리를 작성하거나 패키지에서 선행 제약 조건을 편집해주는 등의 처리가 필요할 것입니다.

반면, 매개 변수를 이용해서 값을 가져올 때에는 값이 Null이라면
문자열은 문자열이 출력된다는 것을 기억하시고
숫자 형일 때에는 예상할 없는 나올 있으므로 주의하여 사용하는 것이 좋을 같습니다.
대신 Count(*)처럼 출력 결과가 Not Null 보장된 쿼리에서는 사용할 있겠습니다.

매개 변수를 이용해서 값을 받아오면 문자열 컬럼의 경우 쿼리에서
Null
처리를 하지 않고 편리하게 가져올 있는 장점이 있습니다.

결과 집합과 매개 변수를 이용한 출력 사용은
각각, , 단점이 있으므로 상황에 맞게 사용하는 지혜가 필요할 같습니다.

끝으로 어설픈 응용 팁을 적자면,
매개 변수를 이용해서 단일 행을 받아오려면
Select Top 1 ? = col1, ? = col2 from Table
처럼 매개 변수를 여러 사용하시면 가능합니다. ^^
반응형
반응형

엑셀 파일로 데이터 내보내기 문제

 

한대성

 

 

 

SQL Server 2005 가져오기/내보내기 기능 중에서 엑셀 파일에서 데이터를 가져오거나 내보낼 일부 문제가 있습니다.

 

다음과 같은 예제 데이터를 준비해 봅시다.

 


USE
TEMPDB

GO

 

CREATE TABLE SampleData

(

                  Seq int identity,

                  Col varchar(10) default('abcdefghij')

)

GO

 

INSERT SampleData DEFAULT VALUES

GO 10

 

 

D:\ 루트에 결과가 저장될 (!) 엑셀 파일을 하나 만듭시다. (D:\Result.xls)

 

 

그런 다음, Management Studio에서 tempdb 선택하고 내보내기 마법사를 실행합니다.

 


 

데이터 원본은 tempdb 지정하고, 대상은 Microsoft Excel 지정한 , D:\Result.xls 파일을 선택합니다.


 

다음을 눌러 하나 이상의 테이블 또는 뷰에서 데이터 복사 선택하고 내보내기 테이블인 SampleData 테이블을 선택한 , 다음 à 다음을 눌러 내보내기를 합니다.


 

처리됩니다.

 

엑셀 파일을 열어봐도 정상적으로 출력됩니다.

 

 

, 이제 다시 데이터 내보내기를 봅시다. 동일한 테이블과 동일한 엑셀 파일입니다.



에러가
납니다. 유효성 검사 부분부터 에러가 발생합니다.


 

분명 동일한 방식으로 했는데, 처음에는 성공이고 번째는 실패라.

차이점이 뭘까요. 답은 번째는 시트가 없는 상태였고, 번째는 시트가 있는 상태입니다.

 

세밀하게 비교하기 위해 번째와 번째의 작업을 패키지로 저장한 비교해 봅시다.

(SSIS 패키지로 저장하는 방법은 마지막 단계 전에 SSIS 패키지로 저장을 선택하면 됩니다.)

 

 


 

다르죠.

우선, 에러 원인을 설명하자면, 테이블의 col 열은 varchar(10) 비유니코드 열입니다. 하지만, 엑셀 파일의 열은 유니코드(nvarchar 또는 nchar, ntext )로만 저장이 됩니다. SSIS에서는 이러한 유형이 차이를 가만 놔두지 않고 에러로 출력을 하는 것이지요. 에러를 내지 않으려면 번째 그림의 오른쪽과 같이 데이터 변환 부분에서 열의 유형을 바꿔주는 작업이 있어야 합니다.

 

 

 

번째 경우는 변환이 자동으로 추가되기 때문에 에러가 나지 않았습니다. 하지만 번째는 이러한 변환이 없기 때문에 패키지가 시작되기 전에 유효성 검사, 패키지 내에 있는 작업 개체들의 메타 정보나 유형 등을 점검하는 단계에서 에러를 발생시키는 것이지요.

 

필자 개인적인 생각으로는, 만약 시트가 있는 경우에는 번째 그림의 SQL 작업 준비, 엑셀 시트를 만드는 작업만 빼고 수행해야 하겠지만, 실수인지 다른 의도가 있는 것인지 모르겠지만 데이터 유형 변환까지도 버렸네요.

 

 

그럼 어떻게 해야 에러를 발생시키지 않고 처리를 있을까요?

 

번째 방법은 다음과 같이 원본 테이블의 varchar 또는 char 열을 모두 유니코드 형태로 바꿔서 읽어오도록 쿼리 문을 지정하는 방법입니다.

데이터 내보내기에서 직접 테이블을 지정하지 말고, 다음과 같이 전송할 데이터를 지정할 쿼리 작성 선택한 ,

 

아래와 같이 유니코드 형태로 casting 하는 쿼리를 입력합니다.


 

주의할 것은 다음 단계에서 저장될 엑셀 시트를 제대로 지정해 주셔야 합니다.


 

 

귀찮지요?

 

 

 

다른 번째 방법은, 대상 시트를 지정하는 단계에서 그냥 새로운 시트 명을 입력하는 것입니다.

 

그런 다음, 엑셀 파일 내에서 데이터를 옮기거나 붙이도록 하는 것이지요.

 

번째 방법은, 위에서 설명한 것과 같이 패키지로 내려 받은 다음, SQL 작업 준비, 시트를 생성하는 단계만 지우고선 패키지를 실행하는 방법입니다. 정기적으로 내려 받아야 하는 경우라면 고려해 볼만 합니다.

 

 

참고하세요^^

반응형
반응형

데이터 원본에서 SQL 동적 쿼리 이용하기

 

한대성

MS SQL Server MVP

 

 

 

다음과 같은 동적 쿼리(Dynamic Query) 데이터 흐름 작업의 원본으로 사용하고자 하는 경우를 살펴보겠습니다.

 

DECLARE @SQL VARCHAR(1000)

SET @SQL = 'SELECT TOP 10 * INTO #AAA FROM Person.Address'

SET @SQL = @SQL + ' SELECT * FROM #AAA'

EXEC(@SQL)

 

 

미리 보기(Preview) 하면 아래와 같이 결과가 나옵니다.


 

하지만, 매핑(Columns) 탭에 들어가면 아무것도 나타나지 않습니다.


 

매핑이 이루어지지 않으면, 패키지를 구성할 없기 때문에 사실상 사용 불가능한 것이지요.

 

 

해결 방안을 찾기 전에 우선 이런 현상이 나타나는 것일까요.

SSIS 결정적(Determinate) 구조를 가져야 합니다. ( 소리냐~)

패키지 개발 단계에서 전송되는 열의 정보나 크기, 형태 모든 구조가 만들어져야 하며, 패키지 실행 중에는 이를 변경할 없습니다.

 

그것과 이것이 무슨 관계일까요?

SSIS 패키지는 위와 같이 동적 쿼리를 사용하는 데이터 원본에서 정보를 얻어와야 패키지를 구성할 있습니다. 그런데, 위와 같은 동적 쿼리는 쿼리 실행 전에 정보를 없는 형태입니다.

(글로 설명할려니깐 혼란만 초래하는 같네요. 안와닿으시면 통과~)

 

 

그럼, 어떻게 하면 될까요?

꽁수를 사용해서 이를 구현할 있습니다. (이전에 방법 알아내느라 한참 애먹었습니다. ,.)

 

 

1. OLE DB 대신 ADO.NET 연결을 사용해야 합니다. 쿼리를 실행시켜서 결과를 받는 경우라면 차이 없습니다. 기존 작업 개체들은 OLE DB 연결을 사용하고 있었다면 데이터 흐름 작업만 ADO.NET 쓰도록 설정해도 되겠지요?

 

2. 데이터 흐름에서 OLE DB 원본 대신 DataReader 원본 사용합니다.

 

3. DataReader 원본에서 위에서 추가한 연결을 설정하고,

 

 

4. 구성요소 속성(Component Properties) 에서 쿼리를 입력합니다.

~!!! 위의 쿼리를 그대로 넣지 마시고, 동적 쿼리 결과 형태와 동일한 열의 테이블이나 쿼리 만들어 넣습니다. 우선 정적인 테이블 또는 결과 셋을 이용해서 정보가 어떤 것이다라는 것을 SSIS 패키지에다가 알려주고 이를 이용해서 구성해야 하기 때문입니다.


 

예제에서는 동일한 구조를 가지는

 

                  SELECT TOP 10 * FROM Person.Addrsss

 

쿼리를 사용하였습니다.

 

매핑 탭에서 정보를 확인한 다음, 확인을 눌러 편집기를 닫고, 다음 변환들을 구성합니다.

 


 

5. 이제 단계가 중요합니다. DataReader 원본 선택한 , 속성 창에서 ValidateExternalMetadata 속성을 True에서 False 변경합니다.


 

구조를 정의해 놨으니깐, 따로 검사하지 말아라~라는 속성입니다.

 

 

6. 이제 제어 흐름 영역으로 이동한 다음, 만들어진 데이터 흐름 작업 선택하고 속성 창에 있는 Expressions 버튼을 클릭해서 (Expression) 작성기를 엽니다.

 

아래와 같이 [DataReader 원본].[SqlCommand] 속성을 선택하고 옆에 있는 버튼을 클릭해서 작성기를 엽니다.

 

 

 

 

7. 작성기에서 다음과 같이 동적 쿼리를 입력합니다.

 


, 쿼리 , 뒤로 따옴표(“) 쳐야 하며 슬래쉬(\) 경우, (\\) 바꿔줘야 합니다.

 

 

 

되었습니다. 테스트 봅시다. 위에서는 TOP 10 으로 만들었는데, 동적 쿼리에서는 TOP 30 데이터를 가져오게 해놨습니다.

 

 

동적 쿼리를 변경해서 TOP 100으로 해서도 테스트.

 

 

 

 

단순하진 않지만, 그렇다고 ~ 복잡한 편도 아닙니다. (속성 하나와 사용하는 밖에는..)

 

데이터 원본으로 동적 쿼리를 사용해야 한다면 이와 같은 방법으로도 구현할 있다는 것을 참고하시기 바랍니다.


2009.12.06
다음 글에 설명된 대로 하면 간단히 구현 가능합니다.
http://www.sqlleader.com/mboard.asp?exec=view&strBoardID=SS2005SSIS&intSeq=3647

반응형
반응형
안녕하세요?

환경은 2003 Server / SSIS 영문판 입니다.

service pack2 는 설치 전입니다.

일단 설치후 SSIS 를 open 하니 프로젝트가 통채로 안보이더군요.

인터넷에(msdn forum) 관련 에러와 쓰레드를 찾아보시면 DTS.dll 을 등록해라고 나옵니다.

위치는 는 파일 검색 하기로 DTS.dll 을 찾아보세요.

regsvr32 DTS.dll 해서 dll 을 등록하면 프로젝트가 보입니다.

그런데 두번째 문제가 발생하는데,

Data Flow Task 가 보이질 않습니다.

관련 링크 http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=162315&SiteID=1

해외에서도 뾰족한 답변이 없더군요.

그때에는 DTS.dll 과 같은 디렉토리에  DTSPipeline.dll 을 regsvr32 로 등록하세요.
 그외 dataflow 와 이름이 비슷한 SQLTaskConnections.dll 을 등록해보세요.


작동이 잘 될것입니다.

서비스팩 2를 설치하면  문제가 없을듯하나, 혹시 설치중 오류로 인해  안될수도 있을때

위의 방법을 사용하십시요.
반응형
반응형

SQL 2000에서 SQL 2005로 데이터 이관 시 'STREAM' 에러

 

한대성

MS SQL Server MVP

에이디컨설팅 책임 컨설턴트 | SQLLeader.com 운영자

 

 

SQL Server 2000에서 2005로 데이터를 전송하는 과정에서 다음과 같은 에러가 발생하는 경우가 있습니다.

 

DTS를 이용해서 SQL 2000에서 2005로 보내는 경우

 

2005 데이터 가져오기/내보내기를 이용해서 처리하는 경우

 

이와 같은 현상은 원본 데이터에서 잘못된 데이터가 원인이며, SQL 2000에서는 이 경우에 에러를 발생시키지 않았지만, SQL 2005의 빠른 로드를 사용하는 방식에서는 에러를 발생합니다.

 

 

1. 상황 재연

잘못된 데이터를 만들기 위해 Hex 수정 기능이 있는 텍스트 에디터를 이용해서 다음과 같이 텍스트 데이터를 입력합니다.

Hex Editor를 이용해서 다음과 같이 임의의 값을 추가합니다.

추가 후에는 다음과 같이 ?와 같은 특수 기호가 나타납니다.

 

 

 

2. 테스트 테이블 생성 및 입력

쿼리 분석기에서 임의의 테이블을 생성하고 위의 텍스트 파일을 Bulk Loading 시킵니다.

USE TEMPDB

GO

 

CREATE TABLE Source

(

                  ColData varchar(20)

)

GO

 

BULK INSERT Source FROM 'd:\SampleData.txt'

GO

 

입력된 데이터의 바이트 수를 확인합니다.

SELECT ColData,  DATALENGTH(ColData) FROM Source

GO

 

 

 

 

 

3. 데이터 페이지 확인

다음과 같은 방식으로 실제 입력된 데이터를 확인합니다.

DBCC TRACEON(3604)

GO

 

DBCC IND('tempdb','Source',0)

/*

1               33             NULL       NULL       213575799              0               10             0               0               0                  0               0

1               31             1               33             213575799              0               1               0               0               0                  0               0

*/

 

DBCC PAGE(tempdb, 1, 31, 3)

/*

lot 0 Offset 0x60

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

Record Type = PRIMARY_RECORD                       

Record Attributes =  NULL_BITMAP VARIABLE_COLUMNS  

4312E060:  00040030  01000001  4e001500  616d726f 0..........Norma

4312E070:  7461446c        61                     lData

ColData                          = NormalData      

 

Slot 1 Offset 0x75

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

Record Type = PRIMARY_RECORD                       

Record Attributes =  NULL_BITMAP VARIABLE_COLUMNS  

4312E075:  00040030  01000001  42001600  656b6f72 0..........Broke

4312E085:  7461446e      c561                     nData.

ColData                          = BrokenData      

*/

 

 

4. 이 테이블을 이용해서 SQL 2000에서 2000, 2005로 가져오기/내보내기 테스트를 수행합니다.

 

 

 

 

 

결과1) SQL 2000 à SQL 2000

에러 없이 정상적으로 처리되며, 잘못된 데이터라도 동일하게 유지됩니다.

 

결과2) SQL 2000 à SQL 2005 : SQL 2000의 데이터 가져오기/내보내기 or DTS 패키지 이용

-         데이터 가져오기/내보내기 또는 DTS 패키지는 빠른 로드 옵션이 적용되어 처리됩니다.

 

이 경우, 에러가 발생합니다.

 

 

위의 그림에서 빠른 로드 사용 옵션 체크를 해제하면 정상적으로 처리됩니다.

 

 

결과3) SQL 2000 à SQL 2005 : SQL 2005의 데이터 가져오기/내보내기 or SSIS 패키지 이용

-         2000에서와 마찬가지로 빠른 로드 옵션이 적용되어 처리되며, 옵션이 설정된 경우 역시 에러가 발생합니다.

 

SQL 2005의 경우에도 데이터 가져오기/내보내기는 다음과 같이 빠른 로드 옵션이 적용되어 처리됩니다.

      

2000에서와 같이 테이블 또는 뷰 빠른 로드대신 테이블 또는 뷰로 변경해서 처리하면 정상적으로 처리됩니다.

 

 

 

[결론]

1. SQL 2005에서 Bulk Insert와 관련되어 내부적(??)으로 처리 방식이 변경되어 위와 같은 현상이 발생하는 것 같습니다. 참고로 동일한 데이터에 대해서도 Bulk Insert시 차이가 있을 수도 있습니다.

             SQL 2000

            

            

             SQL 2005

 

2. SQL 2000에서 SQL 2005로 데이터를 옮기는 과정에서 위와 같은 에러가 발생할 경우, 패키지로 저장한 후, 빠른 로드 옵션을 제거해서 수행하거나, 잘못된 데이터를 변환한 후 수행합니다.

 


송혁 이러한 문제의 원인은 SQL Server 2000과 2005의 orphaned DBCS lead byte의 유효성 체크에 대한 차이로 발생 할 수 있는것으로 알고 있습니다.
SQL Server 2000에서는 데이타가 들어오는 과정에서 모든 경우에 체크를 하는 것이 아닌, 변환 혹은 문자열 작업에 의해 orphaned DBCS lead byte가 제거되게 됩니다.
하지만 데이타의 타입이 같은 경우 어떤 체크 없이 잘못된 데이터가 그대로 SQL Server 2000로 입력되어 지게 됩니다.
SQL Server 2005의 경우는 이러한 데이터 유효성 체크가 강화되어 2000의 잘못된 데이터를 2005로 전송시 오류가 발생하게 됩니다.

이러한 문제에 대한 임시 방편으로는 현재의 데이터 타입과 다른 타입으로 변환하여 업데이트 하는 방법도 있습니다.
만약 char(10)타입이었다면 varchar(10)으로 변환하면 orphaned DBCS lead byte가 제거되어 동일한 문제가 발생하지 않습니다.


2007/07/27

김태환 DBCC TRACEON(-1, 7307)을 통해서도 해결 가능합니다. ^^;

7307 : TEMP QP\QE\gargisur Fix up data while validating data length of remote columns
2007/12/13

반응형
반응형

Oracle DB OLE DB 명령 변환 구성하기

 

한대성

MS SQL Server MVP

에이디컨설팅 | SQLLeader.com 운영자

  

 

 SQL 쿼리에서 커서(Cursor)를 이용한 데이터 처리 방법과 같이, 입력된 데이터를 개별 건 단위로 처리하기 위한 기능으로 SSIS에서 OLE DB 명령이라는 개체가 있습니다. 예를 들어, 원본에서 읽어온 다음, 변환을 거친 1,000개의 데이터를 건 단위로 UDDATE 또는 INSERT, DELETE를 수행하도록 해야 할 경우에 이용할 수 있는 변환입니다.

 

  

   (OLE DB 명령에 대한 상세 사항은 다음 링크의 강좌를 참고하시기 바랍니다.)

 

OLE DB 명령은 다음 형식과 같은 매개변수가 포함된 쿼리를 입력한 다음, 입력 데이터의 열과 쿼리의 입력 매개변수를 매핑하게 됩니다.

UPDATE TARGETTABLE SET CODE = 'AA' WHERE CODE = ?

 

   

 

 

하지만, 오라클 연결 관리자(ex : OraOLEDB.Oracle.1)와 같이 연결 관리자에서 테이블의 매개 변수 정보를 반환하지 않는 경우도 있습니다.

 

위와 같이 매개 변수가 포함된 쿼리를 입력하면, 매개 변수에 해당하는 열의 정보를 얻을 수 없기 때문에 다음과 같은 에러 메시지를 출력합니다.

 

Error at Data Flow Task [OLE DB Command [447]]: SSIS Error Code DTS_E_OLEDBERROR.  An OLE DB error has occurred. Error code: 0x80040E51.

An OLE DB record is available.  Source: "OraOLEDB"  Hresult: 0x80040E51  Description: "공급자는 매개 변수 정보를 유도할 없으며 SetParameterInfo 호출되지 않았습니다.".

 

이와 같은 경우에는 OLE DB 명령을 이용한 작업을 직접 수행할 수는 없으며, 대신 다음과 같은 스크립트 구성 요소(변환)을 이용하여 처리하거나, SQL Server에서 연결된 서버(Linked Server)를 구성한 후 데이터를 입력하는 저장 프로시저를 별도로 구현하여 이용하는 방법을 사용해야 합니다.

 

 

 

 

스크립트 구성 요소(변환)을 이용하여 처리하는 방법

 

OLE DB 명령 대신 스크립트 구성 요소(변환)을 추가한 후, 다음과 같은 스크립트를 이용합니다.

본 예에서는 AAA라는 테이블에 Seq라는 Integer열과 Col이라는 Char(10)의 열에 데이터를 입력하는 쿼리를 수행하는 경우입니다. OleDBCommand 개체와 OledbParameter 개체를 이용해서 매개 변수의 정보를 지정하고, 입력하는 방식으로 처리합니다.

   

 

Imports System

Imports System.Data

Imports System.Math

Imports Microsoft.SqlServer.Dts.Pipeline.Wrapper

Imports Microsoft.SqlServer.Dts.Runtime.Wrapper

Imports System.Data.OleDb

 

 

Public Class ScriptMain

    Inherits UserComponent

 

    Dim oledbConn As OleDbConnection

    Dim oledbCmd As OleDbCommand

    Dim oledbParam As oledbParameter

 

    Public Overrides Sub AcquireConnections(ByVal Transaction As Object)

 

        Dim connectionString As String

        oledbConn = New OleDbConnection("Provider=OraOLEDB.Oracle.1;Password=password;Persist Security Info=True;User ID=system;Data Source=orcl")

        oledbConn.Open()

 

    End Sub

 

    Public Overrides Sub PreExecute()

 

        oledbCmd = New OleDbCommand("INSERT INTO AAA(seq, col) VALUES(?, ?)", oledbConn)

        oledbParam = New OleDbParameter("@seq", OleDbType.Integer)

        oledbCmd.Parameters.Add(oledbParam)

        oledbParam = New OleDbParameter("@col", OleDbType.Char, 10)

        oledbCmd.Parameters.Add(oledbParam)

 

    End Sub

 

 

    Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)

        With oledbCmd

            .Parameters("@seq").Value = Row.seq

            .Parameters("@col").Value = Row.col

            .ExecuteNonQuery()

        End With

    End Sub

 

    Public Overrides Sub ReleaseConnections()

        oledbConn.Close()

    End Sub

 

End Class

 

 

 

 

 

Linked Server를 이용하는 방법

 

Management Studio의 서버 개체 -> 연결된 서버 또는 쿼리 분석기를 이용해서 Oracle 또는 다른 DBMS와의 연결을 설정합니다.

 

)

EXEC sp_addlinkedserver 'OracleLinked', 'Oracle','MSDAORA'

GO

EXEC sp_addlinkedsrvlogin 'OracleLinked', 'FALSE',NULL, 'system', 'passwd'

GO

 

 

 

다음과 같이 연결된 서버에 데이터를 입력하는 저장 프로시저를 생성합니다.

CREATE PROC INSERT_ORACLE @SEQ int, @Col Char(10)

AS

        INSERT OracleLinked..SYSTEM.AAA

        VALUES(@Seq, @Col)

GO

 

 

그런 다음, SSIS 패키지의 OLE DB 명령 개체에서 이 저장 프로시저가 생성된 OLE DB 연결로 변경하고 SqlCommand에 이 저장 프로시저를 입력합니다.

 

열 매핑 탭에서 각 매개 변수에 맞는 입력을 지정하면 됩니다.

 

 

 

 

  

본 게시판에 실린 글은 누구나 복사하셔서 이용하셔도 되지만, 반드시 출처(SQLLeader.com) 링크를 밝혀주셔야 합니다.
반응형
반응형

Excel Data 로딩 시 Null로 처리되는 문제 

 

한대성

  

   

Excel 파일의 데이터를 테이블로 입력하는 경우에 대해 살펴봅시다.

 

 

Case

Excel File

 

Table

Case 1

 

Case 2

 

 

Case 3

 

 

Excel 데이터를 로드할 경우, Excel ISAM 드라이브에서 처음 몇 개의 행을 읽어서 데이터의 유형을 결정하게 됩니다. 이 때, 데이터 유형은 텍스트 형(nvarchar)이거나 숫자 형(Float)형 둘 중의 하나로 결정됩니다. Case 2의 경우, ISAM 드라이브에서 몇 개의 행을 읽어본 후 파악한 결과, 데이터는 숫자 형으로 판단했기 때문에 “‘0313”으로 입력된 세 번째 행의 데이터는 문자 데이터로 간주해서 Null로 처리됩니다. Case 3의 경우 “’0313”으로 입력된 데이터를 보고, 문자형 데이터라 판단했기 때문에 “3209”와 같은 숫자 형 데이터를 Null로 처리하게 됩니다.

 

이러한 현상은 Excel Data를 연결할 때의 연결 문자열과 상관 있습니다. 기본적으로 Excel 파일의 연결 문자열은 다음과 같이 IMEX에 대한 속성이 생략된 형태입니다.

 

Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\Code.xls;Extended Properties="EXCEL 8.0;HDR=YES;";

 

IMEX 속성은 Excel 파일이 데이터 출력(Export)용인지 데이터 입력(Import)용인지를 설정하는 속성으로, 생략하면 0, , Export모드로 인식하여 위와 같은 현상이 발생합니다.

 

Case 2, Case 3과 같이 텍스트 형태와 숫자 형태가 섞여 있는(셀의 속성과는 상관없이) Excel 데이터를 로딩할 경우에는 다음과 같이 연결 문자열에 IMEX=1이라는 값을 추가하면 됩니다.

 

 

Case 2

Case 3

 

IMEX=1로 설정한 경우, 다음 레지스트리에 있는 값을 읽어오게 됩니다.

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Excel]

TypeGuessRows 값은 데이터의 유형을 유추할 읽어올 (8)이며, ImportMixedType 읽어온 데이터를 처리할 유형(Text)입니다. 값이 Text이기 때문에 숫자 형의 데이터라도 모두 문자형(Text) 인식하게 됩니다.

 

 

IMEX=1로 설정할 경우에는 다음과 같은 사항을 주의해야 합니다. Import 모드이기 때문에 데이터를 읽어오는 경우에는 문제없이 잘 수행되나, 해당 연결로 데이터를 출력하는 경우에는 에러가 발생하게 됩니다. 따라서, 읽어오기 위한 Excel 연결과, 내보내기 위한 Excel 연결을 따로 관리하는 것을 권장합니다.

 

 

 

 

 

 

본 게시판에 실린 글은 누구나 복사하셔서 이용하셔도 되지만, 반드시 출처(SQLLeader.com) 링크를 밝혀주셔야 합니다.
반응형
반응형



멀티 집계 변환 수행

   

한대성

에이디컨설팅 책임 컨설턴트| SQLLeader.com 운영자

 

 

오늘은 조금 가벼운 기능을 소개합니다. 새로운 기능은 아니며, 집계 변환 강좌에 소개된 내용을 예제로 만든 것입니다.

 

집계 탭에서 상단의 고급(A) 버튼을 클릭하면 출력 경로에 대한 설정을 할 수 있는 부분이 나타납니다. 집계 연산은 하나의 입력에 대해 여러 개의 여러 개의 집계를 만들 수 있으며, 각각의 집계 작업이 출력이 됩니다. 예를 들어, 고객명, 제품명, 조회수, 구매수량, 구매금액이 입력 데이터에 대해, 고객명과 제품명을 기준으로 값들의 합계를 구하는 연산 작업(집계 출력 1), 고객명에 대한 고유한 제품명 수(Distinct Count)를 계산하는 집계 작업(집계 출력 2)을 수행해야 한다면, 별도의 집계 변환을 추가하지 않고도, 하나의 집계 변환에서 두 가지 형태의 집계 작업을 수행할 수 있습니다.

 

SSIS의 특징 중 하나는 데이터를 자체 데이터 처리 엔진을 이용하여 메모리에서 처리한다는 점입니다. 이러한 방식으로 인해 SQL 쿼리에서와는 조금 다른 형태로 이용할 수 있습니다.

 

집계 변환, GROUP BY 연산을 수행하는 변환은 SSIS에 포함된 여러 변환들 중에서 비용이 높은 변환입니다. 비용이 높다는 것은 데이터를 처리할 때 메모리를 많이 사용한다는 것입니다. 추후에 자세히 다루겠지만, SSIS의 변환은 크게 세 가지 형태로 나뉩니다.

 

동기 변환(Synchronize Transform), 비동기 변환(Asynchronize Transform), 반동기 변환(Semi-Synchronize Transform)입니다. (한글 변역은 제 마음대로 한 것입니다.^^)

동기 변환에는 데이터 변환, 파생 열, 감사, 조건부 분할 등이며, 비동기 변환은 집계, 정렬, 행 샘플링 등입니다. 반동기 변환에는 비율 샘플링이 있습니다.

이런 구분은 입력 데이터에 대한 처리 방식에 따라 나뉩니다. 데이터 변환이나 파생 열 변환과 같이 입력되는 데이터를 바로 처리한 후 출력하는 방식이 동기 변환입니다. 정렬이나 집계와 같이 모든 데이터가 다 로딩된 후에야 처리를 하고 출력하는 방식이 비동기 변환이며, 입력 데이터 중 일부가 입력된 후에 수행되는 방식이 반동기 변환입니다.

 

성능상으로는 동기 변환 유형의 작업이 다른 유형에 비해 성능도 우수하며 서버에 큰 부하도 발생시키지 않습니다. 하지만, 정렬이나 집계 변환과 같은 비동기 변환 작업을 수행해야 할 경우가 있습니다.

 

예제로 사용할 데이터는 SQL 2000pubs DB에 있는 sales 테이블입니다.

 

 

이와 같은 형태의 데이터에 대해, stor_id , ord_num , payterms , title_id qty 합을 구해야 할 경우, 다음과 같이 총 4개의 쿼리를 이용해야 합니다.

 

SELECT stor_id, sum(qty) as sumqty FROM saels GROUP BY stor_id

GO

SELECT ord_num, sum(qty) as sumqty FROM saels GROUP BY ord_num

GO

SELECT payterms, sum(qty) as sumqty FROM saels GROUP BY payterms

GO

SELECT title_id, sum(qty) as sumqty FROM saels GROUP BY title_id

GO

 

하지만, SSIS 패키지를 이용하여 이를 구현한다면 다음과 같이 한 번만 데이터를 입력한 후 메모리 내에서 각 유형별로 집계를 수행하게 됩니다.

 

 

메모리에 데이터를 모두 로딩해야 한다는 점은 있지만, 일단 로딩된 데이터에 대해 여러 형태의 집계를 수행할 수 있다는 점에서는 상당한 장점이 될 수 있습니다.

 

여러 형태의 집계를 한 번에 수행한다면 메모리 부하가 클 수 있습니다.

물론 하나의 집계 연산일 때 보다는 더 필요할 수 있습니다. 하지만, 우선 쿼리를 이용하는 방식과 비교했을 때 원본 데이터를 한 번만 읽어도 되기 때문에 Disk Read 부하를 줄일 수 있습니다. 물론 SQL Table 형태의 데이터가 아니더라도 집계를 수행할 수 있다라는 장점도 있겠지요.

 

그럼 위와 같이 한 번에 4개의 집계를 수행하는 것과 한 번에 하나의 집계 형태로 4번 수행하는 것이 좋을까요? 특별한 경우를 제외하고는 위와 같은 경우가 더 좋습니다.

집계나 정렬 변환에서 데이터를 처리할 때에는 두 가지 형태의 메모리 버퍼를 이용합니다 하나는 플랫 버퍼(Flat Buffer)이며, 입력되는 데이터를 저장하는 역할을 합니다. 또 다른 하나는 프라이빗 버퍼(Private Buffer)이며, 집계 또는 정렬 연산을 수행할 때 이용되는 임시 메모리 영역입니다. 위와 같이 작성한다면 최소한 플랫 버퍼로 데이터를 로딩하는 작업은 한 번만 수행하면 되기 때문에 여러 개로 분리해서 수행할 때보다 우수하다고 할 수 있습니다.

 

이와 같이 설정하는 방법은 다음과 같습니다.

 

 

기본적인 집계 변환 편집기는 위와 같은 형태입니다. 여기서 위에 있는 고급(A) 버튼을 클릭하면 여러 집계를 설정할 수 있는 부분이 나타납니다.

 

 

두 번째 행을 선택한 후, 집계 이름을 입력하면 아래의 사용 가능한 입력 열이 다시 초기화되어 열을 설정하도록 변합니다.

 

 

집계 연산에서 사용할 열을 선택하고 아래 부분에서 연산 방법(Sum or Avg )을 지정하면 두 번째의 집계가 설정된 것입니다. 이와 같은 방식으로 필요한 만큼의 집계 작업을 설정합니다.

 

, 이제 집계 변환 작업을 다른 변환 또는 데이터 대상으로 연결을 하려고 하면 다음과 같이 집계를 선택할 창이 나타납니다. 해당 변환 또는 대상에 맞는 집계를 선택해 주면 됩니다.

 

 

이외에도 집계 연산에서 사용할 메모리의 크기를 지정해주는 옵션이나 집계 데이터의 추정치를 입력하여 메모리를 사전에 확보하도록 하는 고급 설정 기능도 있습니다.

 

물론 SQL GROUP BY보다 항상 우수한 것은 아닙니다.

대표적으로, 문자열 데이터에 대해서는 MAX, MIN 연산이 불가능하다는 것입니다.

 

 

아쉽지만  다른 우수한 기능들로 인해 만족스럽지요.^^

 

그러나~!, 처리 데이터가 SQL Table이며, 한 번만 GROUP BY를 수행해도 될 경우에는 집계 연산보다는 가급적 SQL Engine에서 처리하도록 합시다. 정렬도 마찬가지입니다.

(이와 관련해서는 추후에 다룰 예정입니다.)
반응형
반응형


유니코드 데이터를 비유니코드 데이터로 변환

한대성

에이디컨설팅 책임 컨설턴트| SQLLeader.com 운영자

 

박상우님께서 다음과 같은 질문을 하셔서 이와 관련된 숨은(^^) 꽁수 하나를 소개하고자 합니다. 이와 관련된 문제로 한동안 고민하다가 알게 된 방식입니다..

 

 

Question : 2005에서 유니코드(NVARCHAR)로 된 칼럼을 2000 VARCHAR 칼럼으로 전송을 하려고 하는데 강좌에서처럼 "데이터변환" 이나 "파생 열"을 사용하지 않고 직접맵핑을 해 전송하려 했더니 오류가 발생하더라구요. 그 역으로 전송하려고 해도 마찬가지구요.

"데이터변환" 이나 "파생 열"을 사용하면 되긴 하는데 번거로운 감이 있어서 혹시 묵시적으로 변환되어 전송될 수 있는 옵션은 없는지 궁금합니다.

 

SQL 2000에서는 유니코드 데이터를 비유니코드 데이터로 변환하는 것이 매우 용이했습니다. 정확히 말해서, 별 신경을 쓰지 않았습니다. 암시적 변환(Implicit Conversion)이라고 해서 DTS에서 알아서 변형해서 처리를 해 주었기 때문이지요.

하지만 SSIS에서는 이러한 조건 규칙이 매우 엄격히 적용됩니다.

 

, varchar, char, text 형과 같은 비유니코드 데이터를 nvarchar, nchar, ntext 형의 유니코드 대상으로 바로 입력할 수도 없으며, 그 역의 경우도 마찬가지입니다.

 

 

 

예를 들어 다음과 같은 임시 테이블을 생성해 봅시다.

 

USE TEMPDB

GO

 

CREATE TABLE NonUnicodeSource

(

             Seq INT IDENTITY,

             Col1 VARCHAR(20),

             Col2 CHAR(20)

)

GO

 

CREATE TABLE UnicodeSource

(

             Seq INT IDENTITY,

             Col1 NVARCHAR(20),

             Col2 NCHAR(20)

)

GO

 

INSERT NonUnicodeSource(Col1, Col2) VALUES ('테스트데이터', '테스트데이터')

INSERT NonUnicodeSource(Col1, Col2) VALUES ('테스트데이터', '테스트데이터')

INSERT NonUnicodeSource(Col1, Col2) VALUES ('테스트데이터', '테스트데이터')

GO

 

INSERT UnicodeSource(Col1, Col2) VALUES (N'테스트데이터', N'테스트데이터')

INSERT UnicodeSource(Col1, Col2) VALUES (N'테스트데이터', N'테스트데이터')

INSERT UnicodeSource(Col1, Col2) VALUES (N'테스트데이터', N'테스트데이터')

GO

 

CREATE TABLE NonUnicodeTarget

(

             Seq INT,

             Col1 VARCHAR(20),

             Col2 CHAR(20)

)

GO

 

CREATE TABLE UnicodeTarget

(

             Seq INT,

             Col1 NVARCHAR(20),

             Col2 NCHAR(20)

)

GO

 

 

SSIS 패키지에서 데이터 흐름 작업을 추가한 후, tempdb를 가리키는 OLE DB 연결을 추가하고 OLE DB 원본OLE DB 대상을 추가합니다.

 

 

NonUnicodeSource è UnicodeTarget 으로 보내기

비유니코드형 데이터를 유니코드형 대상으로 바로 입력하는 경우 위와 같은 유효성 에러가 발생합니다. 일반적인 방법으로는 파생 열 변환 또는 데이터 변환 등을 이용하여 유형을 변경하는 작업을 수행해야 합니다.

 

 

 

 

 

하지만, 꼭 이렇게 파생 열 변환을 추가해서 변형해야 하는 것은 아닙니다.

 

다음 그림과 같이 Unicode Target을 선택한 후, 마우스 오른쪽 버튼을 클릭해서 나타나는 메뉴 중 고급 편집기 표시(A)를 선택합니다.

고급 UnicodeTarget 편집기에서 마지막에 있는 /출력 속성 탭을 보면 외부 열입력 열이 있습니다.

입력 열은 데이터 변환으로부터 현재 작업 개체인 데이터 대상 개체로 입력되는 열 정보이며, 외부 열은 입력된 열 정보를 대상 개체에 저장하기 위해 출력하는 열 정보입니다. 입력 열의 정보는 수정을 할 수 없지만, 외부 열의 정보는 수정할 수 있습니다.

 

자 여기서 잠깐.. SSIS에서 형이 맞지 않다고 출력하는 부분은 바로 이 부분입니다. 입력 열 정보와 외부 열 정보의 차이로 인해 유효성 경고를 나타내는 것입니다.

그럼, 다음과 같은 외부 열의 정보를 입력 열과 같은 유형으로 변경해버리면 되겠네요.!!

<변경 전 외부 열 Col1 정보>

 

<변경 후 외부 열 Col1 정보>

 

Col2도 마찬가지로 변경한 후 확인해 봅시다.

 

그런데? 마찬가지로 유효성 경고가 납니다. 다시 고급 편집기에서 외부 열을 확인해 보면 Col1, Col2가 바꾼 유형이 아닌 원래 유형으로 되어 있는 것을 보실 수 있습니다.

 

아우띠..(좌절하지 마시고..^^)

SSIS의 숨겨진 기능 중의 하나가 또 소개됩니다. Unicode Target이라는 대상을 선택한 후 속성 창을 보면 ValidateExternalMetadata 라는 것이 있습니다. 정확한 용도는 더 있겠지만, 제가 파악한 바로는(^^) 외부의 메타 정보와 지정한 열 정보에 대해 검사를 하고 다른 경우에 외부 정보로 강제 변환하도록 하는 설정입니다.

복잡하면 그냥 넘어가시고, 이 값을 True에서 False로 변경하고 다시 Col1, Col2의 정보를 변경해 봅시다.

실행 시키면 됩니다.  데이터를 확인해봐도?

정상입니다.

 

왜 이런 것이 되냐하면^^

암시적 형 변환이 SQL Server 엔진에서 이루어진 것입니다. , 데이터 대상 어댑터 역할을 하는 SSIS OLE DB 대상까지 강제로 형 변환을 해서 데이터를 넘긴 것이며, SQL 엔진의 암시적 형 변환 기능을 이용한 것입니다.

 

SQL 엔진에서는 암시적 형 변환이 가능합니다.

다음과 같은 쿼리를 참고하시기 바랍니다.

 

 

 

 

 

UnicodeSource è NonUnicodeTarget 으로 보내기

이것도 앞의 방식대로 수행하면 가능합니다.

 

 

 

엑셀 데이터 è NonUnicodeTarget 으로 보내기

엑셀 데이터도 Unicode이며 위와 같이 수행하면 변환 가능합니다.

 

 

 

 

정리하자면,

1.       데이터 대상에서 ValidateExternalMetadata 속성을 False로 변경한 후,

2.       고급 편집기의 입/출력 속성에서 외부 열 정보를 변경해주면 SSIS에서도 암시적 형 변환이 가능하다

입니다.

 

반응형
반응형


정렬 변환을 이용한 중복 데이터 제거

 

한대성

에이디컨설팅 책임 컨설턴트| SQLLeader.com 운영자

 

다음과 같은 예제 데이터를 생각해 봅시다.

 

아래의 결과는 SQL 2000의 예제 데이터베이스인 pubs에서 이용할 수 있습니다.

 

SELECT title_id, type, pub_id, royalty FROM pubs..titles

WHERE royalty IS NOT NULL

ORDER BY pub_id, royalty, title_id

 

 

 

다음과 같은 요구 사항을 생각해 봅시다.

pub_id별로 가장 royalty가 낮은 건을 추출하시오.

만약 royalty가 동일한 건이 여러 건 있는 경우, title_id가 가장 높은 건 하나만 추출하시오.

 

데이터 건수가 얼마 안되니깐, 우선 결과를 생각해보면 다음과 같습니다.

 

이것을 쿼리로 한 번 생각해봅시다. 여러 형태의 쿼리가 있을 수 있겠지만, 저는 다음과 같이 작성할 것 같습니다.

 

 

SELECT title_id, type, pub_id, royalty

INTO #TEMP

FROM pubs..titles

WHERE royalty IS NOT NULL

ORDER BY pub_id, royalty, title_id

 

 

SELECT A.title_id, MIN(type) as type, A.pub_id, A.royalty

FROM #TEMP A

JOIN

(

             SELECT B.pub_id, B.royalty, max(title_id) as title_id

             FROM #TEMP B

             JOIN

                           (

                                        SELECT pub_id, min(royalty) as royalty

                                        FROM #TEMP

                                        GROUP BY pub_id

                           ) C ON B.pub_id = C.pub_id AND B.royalty = C.royalty

             GROUP BY B.pub_id, B.royalty

) D ON A.title_id = D.title_id AND A.pub_id = D.pub_id AND A.royalty = D.royalty

GROUP BY A.title_id, A.pub_id, A.royalty

ORDER BY A.pub_id

 

MIN(type)를 추가한 것은 title_id, pub_id, royalty가 모두 같은 중복건이 있을 경우에 하나만 출력하도록 하기 위함이며, MIN 대신 MAX를 이용하여도 상관 없습니다.  어쨌든 간단하지는 않네요.

 

 

이를 SSIS의 변환을 이용해서 구현해보도록 하겠습니다.

 

데이터 흐름 작업을 하나 추가한 후, OLE DB 원본을 이용하여 원본 데이터를 입력 받습니다. 쿼리는 위의 쿼리를 입력해주면 됩니다.

 

왼쪽의 도구상자에서 정렬 변환을 추가한 후, OLE DB 원본과 연결합니다.

정렬을 다음과 같이 설정합니다. 이 때 아래에 있는 중복되는 정렬 값이 있는 행 제거 옵션을 체크합니다.

 

정렬 변환을 또 추가한 후, 앞의 정렬 변환과 연결하고 다음과 같이 설정합니다.

 

마찬가지로 정렬 변환을 하나 더 추가한 후, 앞의 정렬 변환과 연결하고 다음과 같이 설정합니다.

 

이제 행 변환 또는 아무 데이터 대상을 추가해서 마지막의 정렬 변환과 연결합니다.

 

각 단계에 데이터 뷰어를 추가해서 수행되는 결과를 살펴봅시다.

우선 첫 번째 OLE DB 원본에서 정렬 1로의 흐름은 테이블에서 읽어온 데이터 전부이겠네요.

 

그 다음, 정렬 1과 정렬 2 사이의 데이터 뷰어 결과는 다음과 같습니다.

순서 변화만 있고 다른 변화는 없지요? 만약에 pub_id, royalty, title_id가 같은 데이터가 있었다면 하나만 남고 제거되었을 것입니다. 이에 대해서는 다음 단계에서 자세히 설명토록 하겠습니다.

 

정렬 2와 정렬 3 사이의 데이터 뷰어입니다. , 정렬 2를 통과한 결과이지요.

정렬 2? pub_id를 오름 차순으로 royalty를 내림차순으로 정렬하고, 중복되는 행은 제거하라는 것이었습니다.

앞의 결과와 같이 비교해서 봅시다.

복잡하게 보이지만 나름대로 규칙이 있습니다. pub_id royalty를 기준으로 정렬했고 중복을 제거했기 때문에 처리 결과는 pub_id royalty별 한 개만 출력됩니다. 그럼 어떤 값이 출력될까요? 가장 마지막에 입력되는 데이터입니다.

, pub_id 0877, royalty 10인 데이터의 경우, 가장 마지막에 입력되는 TC7777이 출력됩니다.

 

정렬 3을 통과한 결과도 마찬가지입니다. 정렬 3 pub_id로만 정렬하였으며, 중복 데이터를 제거하기 때문에 동일한 pub_id의 데이터 중에서 royalty값이 가장 낮은 값만 출력됩니다.(∵정렬 2에서 pub_id 오름차순, royalty 내림차순으로 출력되기 때문)

 

 

원하는 결과가 나왔네요.

 

어떻게 보면 쿼리보다 복잡할 수도 있겠지만, 열의 수가 더 많아지거나 테이블 형태의 데이터가 아닌 경우에는 SSIS가 더 좋을 수도 있겠지요.

 

중요한 것은?

SSIS의 정렬 변환에는 특이한(^^)옵션인 중복되는 정렬 값이 있는 행 제거(R) 옵션이 있다는 것입니다.
반응형
반응형


조회 변환에 Foreach 루프 컨테이너 설정하기

한대성

에이디컨설팅 책임 컨설턴트| SQLLeader.com 운영자

 

 조회 변환을 이용한 데이터 처리에서 언급한 대로 패키지에 Foreach 루프 컨테이너를 설정하는 것을 설명하겠습니다. 이 부분은 앞의 글에 비해서는 간단한 부분이며 기존에도 몇 번 다루었던 내용이기도 합니다. 참고용^^

 

만약 해당 패키지에서 입력되는 엑셀파일이 InputData.xls 하나만 있는 것이 아니라, 동일한 형태의 여러 엑셀 파일이 있을 경우입니다.

 

예제로 쓸 엑셀 파일 5개를 만들겠습니다. 엑셀 파일은 InputData.xls와 동일한 구조입니다.

이 때, 기존 파일인 InputData.xls은 지워줍니다..(유효성 경고 에러 설명을 위해^^)

 

우선 기존 패키지의 제어 흐름Foreach 루프 컨테이너를 추가하고, 읽어온 파일명을 저장할 문자형 변수를 추가합니다. 이 때 변수의 범위는 패키지 수준으로 합니다. 패키지 수준으로 변수 정의는 제어 흐름의 빈 영역을 클릭한 후에 변수를 추가하면 됩니다. 그런데 왜 패키지 수준(=전역 변수)로 설정해야 하느냐? 이 변수를 엑셀 연결에서 쓸 것이기 때문입니다.

, Foreach 루프 컨테이너에서 파일명을 읽어와서 변수에 저장되면, 이 변수를 이용한 식(Expression)으로 정의된 엑셀 연결에서 사용할 파일명을 바꾸게 되는 방식입니다. 이 변수가 Foreach 루프 컨테이너 범위에서 지정된 변수인 경우에는 엑셀 연결에서 쓸 수가 없습니다.

위와 같이 SourceFile 이라는 이름의 String형 변수를 추가하고, 아무 값이나 입력합니다.

그런 후, Foreach 루프 컨테이너를 더블 클릭해서 편집기를 연 후 다음과 같이 설정합니다.

본 예제에서는 D:\ InputData01.xls 형식으로 파일을 두었기 때문에 위와 같이 설정했습니다. 이 부분은 상황에 맞게 조절하세요~.

.. 그럼 읽어온 파일 이름 정보를 어디에다가 저장하도록 설정하는 부분입니다. 변수 매핑 탭으로 이동한 후, 앞에서 추가한 변수(SourceFile)를 지정합니다.

여기까지가 파일 이름(디렉토리 포함)을 읽어서 변수에 저장하도록 설정한 부분입니다. 파일이 10개이면 10번 돌면서 매 번마다 변수의 값을 바꾸겠죠?.

 

. 이제 연결 관리자에서 엑셀파일 연결을 선택한 후, 오른쪽에 있는 속성 창을 봅시다.

보아하니, ExcelFilePath 라는 속성에 파일 이름이 지정되어 있네요. 그럼 이 놈만 차례차례 바꿔주면 될낀데?(=될 것 같은데) 어뜨케?(=어떻게?)

아래에 있는 Expressions를 이용합시다. 이러한 경우에 사용하라고 제공되는 기능입니다~^^

Expressions를 선택하면 오른쪽에 버튼이 나타나고 클릭하면 아래와 같은 속성 식 편집기가 나타납니다. 속성 중에 ExcelFilePath를 선택합니다. 그런 후, 옆의 식 부분의 버튼을 클릭.

특별히 식 작성할 필요는 없겠지요? 그냥 단순히 @[사용자::SourceFile]이라는 변수만 지정하면 될 것 같네요.

 

확인을 눌러 식 작성기 및 편집 창을 다 닫아버리고 지금까지 구성된 패키지 한 번 봅시다.

 

 

Foreach 루프 컨테이너 속성도 설정해줬고, 엑셀파일 연결도 설정했는데 위와 같다면? 쌩뚱맞죠.. 넣어줍시다..데이터 흐름 작업을 컨테이너 안으로

 

이제 데이터 흐름 작업Foreach 루프 컨테이너가 도는 만큼(=반복 수행되는 만큼) 실행 될 것입니다. 진짜? 실행시켜 봅시다.

 

 

 

만약에 제가 한 순서대로 그대로 따라오셨다면, 위와 같이 에러를 출력하고 실행 안 되는 것이 정상입니다.^^

 

조놈은 모야~!!!!

 

SSIS의 특출난(@.@) 기능 중에 하나가 작업 수행 전 유효성 검사라는 것을 한다는 것입니다. , 작업을 시작하기 전에 『테이블은 있는지, 엑셀 파일은 있는지, 복사 시키려고 하는 열의 타입이나 크기는 맞는지 등등을 점검하는 단계입니다.

왜 할까요? 만약에 10단계의 초대형 작업을 수행합니다. 그런데 실수로 9단계나 10단계에서 입력할 테이블을 만들어놓지 않았네요.. 관리자가 수행하라고 해서 몇 날 몇 일을 수행했는데, 9단계 가서 테이블이 없어서 에러요~! 라고 실패해버립니다. 막막하죠.,...(제가 자주 경험했던 유형입니다.. 바보죠ㅎㅎ) 그래서 미리 돌기 전에 『테이블 없소~! 라고 경고 주는 것입니다.

 

그런데, 가끔씩 이 기능이 필요 없는 경우도 있겠죠? 지금과 같은 경우입니다. 지금은 엑셀 파일을 임의의 파일 이름으로 지정하였습니다. Foreach 루프 컨테이너가 돌면서 제대로 할당할 것이니깐요. 그런데 SSIS는 그 임의의 값을 파일명으로 생각하고 없다고 해버리네요. 허 참~! 이런 경우에 해 주는 작업이 Delay(=연기해라)+Validation(유효성(검사를)) =DelayValidation 속성입니다.

데이터 흐름 작업을 선택한 후 속성에서 DelayValidation 속성을 False에서 True로 바꿉니다.

 

그런 후, 수행하면 깜빡깜빡 거리면서 수행됩니다. 옆의 기분 나쁜 느낌표 마크는 유효성 경고인데, 무시하라고 했으니깐 무시하면 되겠지요^^

 

 

순식간이지만, 5개의 엑셀 파일이 모두 다 처리되었습니다.

 

확인은? 각자 해보시기 바랍니다..^^

 

궁금한 점이나 의문 사항은 댓글로 해주시길 바랍니다
반응형
반응형


다음과 같은 질문 메일을 받았습니다.

 

Question : 접수 프로세스에 접목시키려는 부분입니다.

어떤 지원부분에 있어.. 원서를 접수 받고.. 그 접수자의 별도 제출서류가 있을 경우 그 제출서류에 대한 도착여부를 데이터로 저장하고 싶습니다.

 

1. 엑셀파일로 다수의 수험번호, 도착상태ID, 간략 메모 값을 받습니다.

A. (상태 ID: 1=불필요, 2=미도착, 3=도착, 4=서류미비)

B. 간략메모 : 어떤 서류가 미비 되었는지 간략 메모를 넣을 수 있습니다.(일단 여기선 배재)

2. A라는 테이블에 해당 ROW의 수험번호를 조회하여 IDX값을 받아옵니다.

3. 받아온 IDX값과 도착상태ID값을 B라는 테이블에 저장합니다.

(여기서.. 중요한 점은 기존에 해당 IDX값이 저장되어있다면 Update, 없으면 Insert를 하고 싶습니다.)

 

For루프 컨테이너를 사용해서 해볼까 하는데.. 어떻게 진행해야 할까요?

 

원본 데이타는 엑셀이고 비교테이블은 A테이블 대상테이블은 B테이블입니다.

 

기존 DTS 2000으로 작업을 진행했었는데 엑셀 데이타 1000건을 넘겼을 경우 잦은 오류가 발생 하더라구요. 해서 이번 좋은 기회에 바꿔보려고 합니다.

 

요런(^^) 조건을 만족하는 패키지를 만들어봅시다.

 

, 조건을 좀 더 나누어서 세 가지로 진행하겠습니다.

1. 위의 요구 사항을 조회 변환을 이용하여 구현하기

2. 입력되는 엑셀 파일이 여러 개 일 때 Foreach 루프 컨테이너 씌우기

 

이렇게 두 가지 형태로 만들어보겠습니다.

 

 

우선 다음과 같은 준비 작업을 하겠습니다.

 

조회 테이블 A

USE TEMPDB

GO

 

IF EXISTS (SELECT * FROM SYSOBJECTS WHERE NAME='TABLEA' AND XTYPE = 'U')

DROP TABLE TABLEA

GO

 

--코드 테이블

CREATE TABLE TABLEA

(

             IDX INT IDENTITY,

             IDNO CHAR(8) NOT NULL

)

GO

 

--임의 코드값 발생

SET NOCOUNT ON

DECLARE @I AS INT

SET @I = 20000

 

WHILE @I>=1

BEGIN

INSERT TABLEA(IDNO) VALUES ('A' + RIGHT('00000000' + CAST(@I AS VARCHAR), 7))

SET @I = @I - 1

END

SET NOCOUNT OFF

GO

 

--매핑 안되는 경우에 대한 처리를 위해 일부 데이터를 지웁니다.

DELETE FROM TABLEA

WHERE IDNO IN ('A0000324', 'A0000225', 'A0000765','A0000758','A0000104','A0000554')

GO

 

SELECT TOP 10 * FROM TABLEA

/*

IDX IDNO

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

1            A0020000

2            A0019999

3            A0019998

4            A0019997

5            A0019996

6            A0019995

7            A0019994

8            A0019993

9            A0019992

10          A0019991

*/

 

 

결과 저장 테이블 B : 매핑 되는 건이 입력 or 수정 됩니다.

USE TEMPDB

GO

 

IF EXISTS (SELECT * FROM SYSOBJECTS WHERE NAME='TABLEB' AND XTYPE = 'U')

DROP TABLE TABLEB

GO

 

--매핑되는 데이터 결과 테이블

CREATE TABLE TABLEB

(

             순번 INT IDENTITY,

             수험번호 CHAR(8),

             도착상태 TINYINT,

             IDX INT,

             간략메모 TEXT

)

GO

 

 

결과 저장 테이블 C : 입력 데이터 중에서 테이블 A와 매핑이 안 되는 건이 저장됩니다.

USE TEMPDB

GO

 

IF EXISTS (SELECT * FROM SYSOBJECTS WHERE NAME='TABLEC' AND XTYPE = 'U')

DROP TABLE TABLEC

GO

 

--매핑 안 되는 데이터 결과 테이블

CREATE TABLE TABLEC

(

             순번 INT IDENTITY,

             수험번호 CHAR(8),

             도착상태 TINYINT,

             간략메모 TEXT

)

GO

 

 

입력 엑셀 데이터 (10,000) : D:\InputData.xls

수험번호

도착상태

간략메모

A0006853

2

메모메모A0006853

A0006910

1

메모메모A0006910

A0000386

2

메모메모A0000386

A0001959

4

메모메모A0001959

A0002282

3

메모메모A0002282

A0003198

4

메모메모A0003198

A0009000

4

메모메모A0009000

A0005821

4

메모메모A0005821

A0000036

2

메모메모A0000036

A0004206

1

메모메모A0004206

A0004965

4

메모메모A0004965

A0007500

1

메모메모A0007500

A0004815

4

메모메모A0004815

A0005155

4

메모메모A0005155

A0009572

4

메모메모A0009572

A0008573

1

메모메모A0008573

A0006463

4

메모메모A0006463

A0000186

2

메모메모A0000186

A0004464

1

메모메모A0004464

A0009642

2

메모메모A0009642

A0007817

4

메모메모A0007817

A0002225

1

메모메모A0002225

A0000083

1

메모메모A0000083

A0002475

1

메모메모A0002475

A0003398

3

메모메모A0003398

A0000585

2

메모메모A0000585

A0001938

3

메모메모A0001938

 

 

 

. 그럼 우선 작업 유형부터 생각해 봅시다.

1) 엑셀 데이터를 읽어서 수험 번호에 해당하는 IDX값을 TABLEA로부터 검사하기

 : 조회 변환을 이용해도 되고, 조인 변환을 이용해도 됩니다. 장단점이 있겠지만, 저는 여기서 조회 변환을 쓰겠습니다. 조인 변환은 다들 잘 아시겠지요? (쿼리 잘 하시잖슴까~^^)

2) 요구 사항에는 없었는데, 혹시나 TABLEA에 매핑 안 되는 엑셀 데이터가 있겠지요? 매핑 안 되는 데이터는 별도의 테이블 C(TABLEC)에 저장합니다.

3) 매핑 되는 데이터 이더라도 TABLEB에 이미 들어가 있는 경우에는 UPDATE, 그렇지 않은 경우에는 INSERT 합니다. 이것은? 이것도 조회 변환을 이용합니다.

 

오케..데이터 읽고 조회 변환하고 하는 거 보니깐, 이건 데이터 흐름 작업이네. 라고 생각되시지요?

 

제어 흐름 영역에다가 데이터 흐름 작업 하나 추가합니다. 이왕 추가하는 김에 연결 관리자에서 tempdb를 지정하는 OLE DB 연결도 추가하고, 엑셀 파일에 대한 엑셀 연결도 추가합니다. 혹시나 연결 추가 방법 잘 모르시면 앞의 기본 강좌들을 참고하시기 바랍니다..

 

 

데이터 흐름 작업을 클릭하면 데이터 흐름 영역으로 넘어가죠? , 그럼 우선 엑셀 원본을 추가하고선, 엑셀 연결을 지정합니다.

 

참고로, 엑셀 파일의 문자열 데이터는 모두 UNICODE입니다. 따라서 nvarchar 형태로 매핑이 되어야 합니다. 하지만, 어라~! 결과가 저장하는 테이블은 varchar로 만들었네요!… ..

여기서 SSIS가 조금씩 싫어질 수도.^^

SQL 2000 DTS에서는 그냥 변형 시켰습니다. 아니, 시켜줬습니다. Implicit Conversion(=암시적 or 암묵적(@.@) 변환). nvarchar라도 DTS 맘대로 그냥 varchar형으로 알아서 변경해서 넣어버렸지요. 요런 특징이 편한 분들도 계셨을 건데, 제 경우에는 요것 땜시로 몇 번 크게 고생해서 싫어졌습니다.

SSIS? 절대 그런 것 없습니다. 특히나 유니코드와 비유니코드 간에는 자동으로 안 바꿉니다. 그래서 파생 열 변환이나 데이터 변환과 같은 변환을 이용해서 직접 변경해줘야 합니다. 여기서는 파생 열 변환을 이용하겠습니다. 파생 열 변환을 추가한 후, 엑셀 데이터 원본과 연결합니다. 그러고선, 파생 열 변환에 다음과 같이 입력합니다.

 

 

 

 

중간 부분만 좀 더 확대해서 보면~

 

새 열로 추가하면서도 파생 열 이름은 똑같이 [수험번호], [도착상태], [간략메모]와 같이 원본 입력 열 이름과 같네요.. (이렇게도 되더라고요 ㅎㅎ.. 그냥 해 봤습니다..)

 

, 이제 조회 변환을 추가하여 파생 열 변환과 연결합니다.

그런 후, 조회 변환의 속성은 다음과 같이 지정합니다.

여기서 직접 테이블을 선택해도 되지만, 가급적이면 필요한 열만 포함하는 쿼리를 이용하도록 습관화(!) 합시다.

열 탭에서 다음과 같이 IDX열을 체크합니다. 이것은 조회 변환을 한 후에 IDX 열을 포함시키라는 것입니다.

고급 탭은 나중에 테스트 해보세요..요리 조리..

 

여기서 한 번 더 설명하겠습니다. ? 조회 변환의 특징~

조회 변환은 입력 데이터가 조회 데이터와 매핑 되면 딱 한 놈만 매핑 합니다. 만약 조회 테이블에 여러 데이터가 있더라도 한 놈만 매핑 시킵니다. (테스트 했을 때에는 마지막 놈이었는데, 좀 불확실~^^)

그리고, 매핑 안되면 오류로 처리됩니다. 조인 변환과의 차이지요? 조인의 경우에는 매핑 안되면 땡(!)입니다. 하지만, 이 변환은 에러로 처리해줍니다. 고맙죠~^^ 그럼? 실패?

기본적으로는 작업 실패입니다. 하지만, 아래에 있는 오류 출력 구성(G)을 이용해서 오류에 대한 처리 방법을 변경할 수 있습니다. 오류를 무시하도록 할 수도 있고, 오류가 발생한 데이터를 다른 경로로 출력할 수도 있습니다.

여기서는 다른 경로로 출력하겠습니다. 우선 OLE DB 대상을 하나 추가한 후에 조회 변환의 적색 선과 연결시킵니다. 그러면 다음과 같은 창이 자동으로 뜹니다. 요 창이 바로 조회 작업의 오류에 대한 처리를 설정하는 창이며, 위의 그림에서 오류 출력 구성(G)을 눌렀을 때 나타나는 것과 같은 창입니다.

 

오류 부분을 그림과 같이 행 리디렉션으로 설정합니다. 그런 후 OLE DB 대상(그림에서 매핑 안 되는 데이터)을 더블 클릭해서 편집기를 띄운 후, 대상 테이블은 TABLEC로 지정합니다.

또한 매핑 탭에서 다음과 같이 열을 지정합니다. 굳이 여기서는 오류 정보를 넣을 필요 없기 때문에 세 열만 지정합니다.

사용 가능한 입력 열에 보면 조로코롬(@.@) 되어있지요? , 앞에서 말한 것처럼 열 이름을 동일하게 가지고 가더라도 변환 이름이 앞에 붙어서 구분됩니다.

 

, 이제는 매핑 된 데이터에 대한 처리를 합시다. 매핑이 된 데이터 이더라도 TABLEB에 이미 들어가 있으면 Update, 없으면 Insert를 해야 합니다. 요놈도 역시 조회 작업으로 해 봅시다. 또 하나의 조회 변환을 추가한 후, 기존의 조회 변환과 연결시킵니다.

SELECT 수험번호 FROM TABLEB (NOLOCK)

으로 쿼리를 입력하고선, 열 탭에서 다음과 같이 그냥 연결만 하고 열 추가를 하지 않습니다. (할 필요 없겠죠? 그냥 검사만 하는 것이기 땜시로..)

 

, 만약에 매핑이 된다면? 이 데이터(입력 데이터) TABLEB에 이미 있는 데이터라는 것을 말하겠지요. 매핑이 안 된다면? TABLEB에 없는 데이터이지요.

따라서, 여기서도 위와 같이 오류 출력을 구성해서 오류가 난 데이터(=매핑이 안된 데이터) TABLEB에 입력하는 것을 구성합니다. 새로운 OLE DB 대상을 추가한 후, 조회 변환의 적색 선과 연결하고선, 위에서와 같이 오류 출력 구성을 행 리디렉션, 그리고 조회 변환의 편집기 창에서 열을 지정해줍니다.

 

 

 

, 이제 하나 남았네요. 기존에 있는 데이터인 경우엔 업데이트 해라~!

요놈은? OLE DB 명령을 이용합니다.

일단 추가.. OLE DB 명령. 조회 변환의 녹색 선과 연결.

 

OLE DB 명령을 더블 클릭해서 나타나는 편집기에서 연결 관리자를 지정합니다.

 

구성 요소 속성 탭의 SqlCommand 부분에 다음과 같은 쿼리를 입력합니다.

 UPDATE TABLEB SET IDX = ? WHERE 수험번호= ?

 

열 매핑 탭에서는 다음과 같이 연결해 줍니다.

 

~!. 한 번 돌려봅시다.

 

매핑 안된 데이터 6개는 TABLEC에 저장됩니다.

 

TABLEB에는 기존 데이터가 없기 때문에 모두 새로 입력됩니다. 9,994.

 

만약 다시 돌린다면? 다음 그림과 같겠지요?

 

마지막으로 성능을 위해서 인덱스를 잡아주는 쎈스~(테이블 만들 때 해줘야겠죠?)

CREATE INDEX IDX_TABLEA_1 ON TABLEA(IDNO)

GO

 

CREATE INDEX IDX_TABLEB_1 ON TABLEB(수험번호)

GO

 

 

다음 강좌는 동일한 환경에서 만약에 엑셀 파일이 여러 개일 때 Foreach 루프 컨테이너로 씌우는 것을 하겠습니다.

 

반응형
반응형


데이터 관련 업무를 하다 보면 서로 다른 두 서버간의 데이터 동기화 작업을 해야 할 경우가 많이 있습니다.

 

여러 경우가 있겠지만 본 글에서는 다음과 같은 상황에서 SSIS의 조회 변환을 이용한 처리 방법을 설명하도록 하겠습니다.

 

 

자 위의 그림과 같이 Source Table에는 새로운 데이터가 발생이 되며, 다른 서버의 Target Table에는 새롭게 추가된 데이터만 넣어야 하는 경우입니다.

 

만약 같은 서버 내의 SQL 테이블인 경우에는 Left Join 또는 Not Exists 문을 이용하여 처리하면 되겠지만, 원격 서버인 경우에는? Linked Server를 이용하여 쿼리를 사용하기에는 문제가 많겠지요. 그리고, 만약 데이터가 SQL Table이 아니라면? 원본이 텍스트 파일이라면?

 

이러한 경우에 SSIS 패키지를 이용할 수 있습니다.

 

다음과 같이 두 테이블을 준비합니다. 두 테이블은 서로 다른 서버 또는 서로 다른 DB에 만들어도 됩니다. (테스트니깐~^^)

 

CREATE TABLE SOURCE

(

       SEQ INT IDENTITY,

       VAL VARCHAR(10) DEFAULT('AAA'),

       CONSTRAINT PK_SOURCE PRIMARY KEY(SEQ)

)

GO

본 예제에서는 Source Table Localhost 인스턴스의 tempdb에 만들겠습니다.

 

다음과 같이 대상 테이블도 만듭니다.

CREATE TABLE TARGET

(

       SEQ INT ,

       VAL VARCHAR(10),

       CONSTRAINT PK_TARGET PRIMARY KEY(SEQ)

)

GO

본 예제에서는 localhost\ss2005 라는 SQL 2005 인스턴스의 tempdb에 만들겠습니다.

 

, 이제 SOURCE 테이블에 값을 좀 넣읍시다. 데이터를 넣을 때 여러 방법이 있겠지만, 만약 SQL Server 2005 Management Studios를 이용한다면 다음과 같은 방법으로 한 번 해 보시기 바랍니다.

 

GO 뒤에 숫자 붙이기.. 이것은 SQL 2005의 기능이 아니라 Management에 추가된 기능입니다. , Management Studios를 이용할 경우, DB SQL 2000이더라도 수행됩니다.^^

어쨌든 Source 테이블에 3000개의 데이터를 입력했습니다.

 

, 그럼 빈 SSIS 패키지를 하나 추가한 후, 데이터 흐름 작업을 추가합니다.

 

데이터 흐름 영역에서 OLE DB 원본을 갖다 놓고선, 속성에서 새로 만들기(N)을 이용하여 SOURCE 테이블에 대한 연결을 만듭니다. (잘 모르시면 앞의 예제들 참고하세요.)

 

열 탭 한 번 눌러서 열 확인해 주시고, 확인을 눌러 창을 닫습니다.

 

이제 도구상자에서 조회 변환을 끌어서 갖다 놓은 후, OLE DB 원본의 녹색선과 연결합니다.

조회 변환을 더블 클릭하여 나타나는 속성 창에서 새로 만들기(N)을 클릭하여 조회용 연결을 만듭니다. 어떤 조회? 여기서는 원본 테이블에서 읽은 데이터를 TARGET 테이블과 비교하는 과정이기 때문에 TARGET 테이블이 있는 DB가 조회 연결이 되겠지요.

 

그러고선, 조회용 결과를 테이블로 하지 말고, 테이블의 키 열만 SELECT 하는 쿼리로 지정합니다.

 

열 탭에서 연결 관계를 확인합니다.

고급은 그냥 구경만~^^ - 이 부분이 중요합니다. 나중에. 테이블의 크기에 따라 캐싱 사이즈를 조절하거나 행 단위 처리 등을 지정해야 할 수도 있습니다.

 

우선은 확인을 눌러 닫고선 도구상자에서 OLE DB 대상을 끌어서 데이터 흐름 영역에 추가합니다.

이 때, 조회 변환의 녹색선과 연결하지 말고, 적색선과 연결합니다.

? 조회가 되는 데이터, 즉 매핑이 되는 데이터는 이미 TARGET 테이블에 있는 데이터이기 때문에 여기서는 필요가 없고 조회가 안되는 데이터인 오류 데이터가 결국은 새로 추가된 데이터이기 때문입니다.

 

적색선을 OLE DB 대상에 연결하면 구성 창이 나타납니다.

오류 부분에 행 리디렉션으로 변경한 후 확인을 눌러 창을 닫습니다.

 

이제, OLE DB 대상을 더블 클릭한 후, 다음과 같이 지정합니다.

그런 다음 매핑 탭에서 SEQ VAL 열만 지정합니다. (자동으로 지정되어 있을 것입니다.^^)

확인을 눌러 실행시키면 다음과 같이 데이터 전송됩니다.

 

이 상태에서 또 실행 시키면?

전송되는 데이터가 없습니다. , 새로운 데이터가 없다는 것입니다.

 

, 쿼리 분석기에서 SOURCE 테이블에 신규 데이터를 추가하고 다시 돌려봅시다.

100,000개의 데이터를 추가했습니다.

위와 같이 103,000개의 원본 데이터 중 매핑이 안된 데이터(=신규로 발생한 데이터) 100,000개가 추가됩니다.

 

 

 

데이터가 엄청나게 많은 경우에는 조회 변환캐싱 옵션을 조절해 보시기 바랍니다. 캐싱 설정 부분은 다음 글을 참고하세요.

 

http://www.sqlleader.com/mboard.asp?exec=view&strBoardID=SS2005SSIS&intPage=2&intCategory=0&strSearchCategory=|s_name|s_subject|&strSearchWord=&intSeq=428

 

http://www.sqlleader.com/mboard.asp?exec=view&strBoardID=SS2005QNA&intPage=2&intCategory=0&strSearchCategory=|s_name|s_subject|&strSearchWord=&intSeq=540

 

 

반응형
반응형


ODBC 데이터 원본과 마찬가지로 스크립트 구성요소 - 대상을 이용하여 ODBC 대상도 구현 가능합니다.
 
구현 단계는 ODBC 데이터 원본에서와 비슷하기 때문에 생략하고 스크립트와 예제 파일을 첨부합니다.
 
ODBC를 이용하여 ODBCTest 라는 테이블에 입력하는 예제입니다.
 
 
 

Imports System

Imports System.Data

Imports System.Math

Imports Microsoft.SqlServer.Dts.Pipeline.Wrapper

Imports Microsoft.SqlServer.Dts.Runtime.Wrapper

Imports System.Data.Odbc

 

Public Class ScriptMain

    Inherits UserComponent

 

    Dim odbcConn As OdbcConnection

    Dim odbcCmd As OdbcCommand

    Dim odbcParam As OdbcParameter

 

    Public Overrides Sub AcquireConnections(ByVal Transaction As Object)

 

        Dim connectionString As String

        connectionString = Me.Connections.연결.ConnectionString

        odbcConn = New OdbcConnection(connectionString)

        odbcConn.Open()

 

    End Sub

 

    Public Overrides Sub PreExecute()

 

        odbcCmd = New OdbcCommand("INSERT INTO pubs..ODBCTest(AddressID, City) VALUES(?, ?)", odbcConn)

        odbcParam = New OdbcParameter("@addressid", OdbcType.Int)

        odbcCmd.Parameters.Add(odbcParam)

        odbcParam = New OdbcParameter("@city", OdbcType.VarChar, 30)

        odbcCmd.Parameters.Add(odbcParam)

 

    End Sub

 

    Public Overrides Sub 입력_ProcessInputRow(ByVal Row As 입력Buffer)

 

        With odbcCmd

            .Parameters("@addressid").Value = Row.AddressID

            .Parameters("@city").Value = Row.City

            .ExecuteNonQuery()

        End With

 

    End Sub

 

    Public Overrides Sub ReleaseConnections()

 

        odbcConn.Close()

 

    End Sub

 

End Class

 
 
반응형
반응형


프로젝트 때문에 글을 많이 올리지 못했네요.

 

Q&A에 오순근 님이 ODBC를 이용한 데이터 원본에 대해 질문해 주셔서 이에 대한 방법을 설명하겠습니다.

 

SQL 2005 SSIS에서는 ODBC를 이용하여 SQL 명령은 실행할 수 있습니다.

하지만, 데이터 흐름 영역에서는 ODBC 데이터 원본 또는 ODBC 데이터 대상이 없습니다.

(수정 : 2007.01.26 : DataReader 원본에서 .NET 공급자\Odbc Data Provider를 이용하여 ODBC 원본을 사용할 수는 있습니다.)

 

이를 구현하기 위해서는 스크립트 구성요소의 원본 기능을 이용해야 합니다.

 

 

다음과 같이 구현하는 예를 설명하겠습니다.

 

SQL Server 2000에 대한 ODBC 연결을 이용하여

SELECT au_id, au_lname FROM pubs.dbo.authors

라는 입력 쿼리의 결과를 이용하는 방법을 설명하겠습니다.

 

[사전 환경]

제어판의 ODBC 관리자에서 테스트용 ODBC 설정을 하나 생성합니다. 본 예제에서는 SS2000_ODBC로 추가하겠습니다.

 

 

1.       빈 패키지 파일을 하나 생성합니다.

2.       화면의 아래 부분에 있는 연결 관리자에서 마우스 오른쪽 버튼을 클릭하여 나타나는 메뉴 중 새 연결(W)를 선택한 후, ODBC 연결을 추가합니다.


 

3.       연결 관리자 창에서 ODBC 연결을 지정합니다.



4.       도구상자에서 데이터 흐름 작업을 추가한 후, 데이터 흐름 영역으로 이동하여 스크립트 구성 요소를 추가합니다. 이 때 유형은 원본으로 선택합니다.



5.       추가한 스크립트 연결을 더블 클릭하여 편집기를 엽니다. 편집기의 연결 관리자 탭에서 추가(A) 버튼을 클릭한 후, 연결 관리자 부분에 2단계에서 추가한 ODBC 연결을 지정합니다.

 

6.       조금 번거로운 작업을 수행해야 하는 단계입니다. /출력 탭에서 출력되는 열에 대한 정의를 추가해줘야 합니다. [출력 0] à [출력 열] 을 선택한 후, 열 추가(C) 버튼을 클릭한 후, 새로운 열을 하나 추가합니다. 이 열의 이름을 au_id로 변경하고 DataType문자열 [DT_STR], Length10로 설정합니다. 동일한 방식으로 au_lname이라는 열을 추가하고 DataType문자열 [DT_STR], Length40으로 설정합니다.



7.       스크립트 탭의 스크립트 디자인(S)를 클릭하여 VSA를 실행시킨 후, 다음 스크립트를 입력합니다. 스크립트에 대한 설명은 주석 부분을 참고하시기 바랍니다.

 

Imports System

Imports System.Data

Imports System.Math

Imports Microsoft.SqlServer.Dts.Pipeline.Wrapper

Imports Microsoft.SqlServer.Dts.Runtime.Wrapper

Imports system.Data.Odbc  ' ODBC 연결을 위해 다음을 포함합니다.

 

 

Public Class ScriptMain

    Inherits UserComponent

 

    Dim odbcConn As OdbcConnection  ' ODBC 연결

    Dim odbcCmd As OdbcCommand      ' ODBC 명령개체

    Dim odbcParam As OdbcParameter  ' ODBC 매개변수개체

    Dim odbcReader As OdbcDataReader    ' ODBC 데이터개체

 

    Public Overrides Sub AcquireConnections(ByVal Transaction As Object)

 

        Dim connectionString As String

        connectionString = Me.Connections.연결.ConnectionString

        odbcConn = New OdbcConnection(connectionString)

        odbcConn.Open()

 

    End Sub

 

    Public Overrides Sub PreExecute()

 

        Dim odbcCmd As New OdbcCommand("SELECT au_id, au_lname FROM pubs.dbo.authors", odbcConn)

        odbcReader = odbcCmd.ExecuteReader

 

    End Sub

 

    Public Overrides Sub CreateNewOutputRows()

 

        Do While odbcReader.Read

            With 출력0Buffer

                .AddRow()

                .auid = odbcReader.GetString(0)

                .aulname = odbcReader.GetString(1)

            End With

        Loop

 

    End Sub

 

    Public Overrides Sub PostExecute()

 

        odbcReader.Close()

 

    End Sub

 

    Public Overrides Sub ReleaseConnections()

 

        Me.Connections.연결.ReleaseConnection(odbcConn)

 

    End Sub

 

End Class

 

 

8.       임의의 레코드 대상 또는 플랫 파일 대상 등을 추가하여 생성한 원본과 연결한 후 출력 결과를 확인합니다.

 

 

 

 

 

한대성 DataReader를 이용하여 .NET 공급자\Odbc Data Provider로 ODBC 원본을 구현하는 방법도 있습니다.~^^
(늦게 알았습니다..흑...)
대신 DataReader를 이용한 ODBC 대상은 안되더군요...

참고하세요~~
2007/01/26

 

반응형
반응형


변환 작업 중 유니코드 형(DT_NTEXT 또는 DT_WSTR) 데이터를 DT_STR 형으로 변경하는 방법입니다.

데이터 변환 작업 중 파생열 변환을 이용하여 다음과 같이 처리하면 됩니다.

 

(DT_STR,4000,949)((DT_TEXT,949)<유니코드 형 입력열>)

 

참고할 사항은, 유니코드 형 데이터를 직접 DT_STR형으로는 변환 불가능하며, 일단 DT_TEXT형으로 변경한 후에 이것을 DT_STR 형으로 변경해야 합니다.

(? 글쎄요~^^ 이유는 모르겠고, 이와 같이 해야만 변경 가능하더라고요~)

 

 

첨부하는 예제 패키지를 참고하시기 바랍니다.

 

 

반응형
반응형


SSIS를 이용하여 작업을 구성할 때, 필요에 따라서 일정 시간 동안 멈추도록 하는 작업이 필요한 경우가 있습니다.

 

SQL Query에서는 WAITFOR DELAY 명령을 이용하여 구현할 수 있었습니다.

 

 

 

SSIS에서 이러한 기능을 구현하는 방법에는 여러 가지가 있을 수 있겠지만, 다음과 같이 FOR 루프 컨테이너를 이용하여 구현할 수 있습니다.

 

 

EvalExpression 에 다음과 같은 식을 대입하여 대기 작업을 설정합니다.

 

DATEADD( "ss", 10, @[System::ContainerStartTime]) > GETDATE()

 

참고로, 현재의 버전인 SQL 2005 SP1 에서는 FOR 루프 및 ForEach 루프 컨테이너에서 메모리 사용과 관련된 약간의 버그가 있어서 Exception 에러가 발생될 수도 있습니다. 하지만 SP2에서 수정된다고 하네요.

 

참고하시기 바랍니다.

 

 

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

SQLLeader.com / ADConsulting / 한대성 (olaper@지메일.)

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

반응형
반응형


세미나랑 프로젝트랑 기타 등등 여러 일들로 인해 글이 좀 뜸했네요~^^

 

이번 테크넷 브리핑 세미나에서도 잠깐 데모 보여드렸던 내용인데요. 스크립트 변환을 이용하여 비표준화된 데이터에 대한 처리 방법을 구현한 것입니다. MSDN에 추가된 내용을 바탕으로 한 번 만들어 보았습니다.

 

여기서 비표준화된 형태란, 다음과 같이 테이블과 같은 형태가 아닌 데이터를 말합니다.

 

##############################################################

Package Name = 05_수행시간측정

Package Description =

Package Start Time = 2006-10-31 11:05:52

 

             Container Name = 병렬 수행

             Container Description = 스크립트 작업

             Start Container Time = 2006-10-31 11:05:52

             End Container Time = 2006-10-31 11:05:52

             ##Duration = 00:00:00

 

             Container Name = 대기

             Container Description = 스크립트 작업

             Start Container Time = 2006-10-31 11:05:52

             End Container Time = 2006-10-31 11:05:52

             ##Duration = 00:00:00

 

             Container Name = 데모 시퀀스 컨테이너

             Container Description = 시퀀스 컨테이너

             Start Container Time = 2006-10-31 11:05:52

             End Container Time = 2006-10-31 11:05:58

             ##Duration = 00:00:06

 

Package End Time = 2006-10-31 11:05:58

 

##############################################################

##     Total Package Duration = 00:00:06

##############################################################

 

 

이와 같은 입력 데이터에 대해 다음과 같은 테이블 형태의 모양으로 변환하고자 할 때,

PackageName

ContainerName

ContainerDescription

StartTime

EndTime

Duration

05_수행시간측정

병렬 수행

스크립트 작업

2006-10-31 11:05:52

2006-10-31 11:05:52

00:00:00

05_수행시간측정

대기

스크립트 작업

2006-10-31 11:05:52

2006-10-31 11:05:52

00:00:00

 

데이터 흐름 영역에 포함된 스크립트 변환 작업을 이용하여 수행할 수 있습니다.

 

행 단위로 텍스트 데이터를 읽은 후, 스크립트 변환 작업에서 행을 분석한 후, 잘라내어 출력시키는 방식입니다.

스크립트 변환에서 주의할 점은, 출력 부분에서 SynchronousInputID 값을 0으로 설정해 주는 것입니다. 이는 입력 버퍼와는 별도로 출력 버퍼를 사용하도록 지정하는 것입니다.(비동기 방식)

 

 

스크립트 부분은 다음과 같습니다.

Imports System

Imports System.Data

Imports System.Math

Imports Microsoft.SqlServer.Dts.Pipeline.Wrapper

Imports Microsoft.SqlServer.Dts.Runtime.Wrapper

 

Public Class ScriptMain

    Inherits UserComponent

 

    Dim PackageName As String

 

 

    Public Overrides Sub 입력_ProcessInputRow(ByVal Row As 입력Buffer)

        '

        ' Add your code here

        '

        Dim colName As String

        Dim colValue As String

 

        If Row..Trim.Length > 0 And Row..IndexOf("=") > 0 Then

 

            colName = Row..Substring(0, Row..IndexOf("=")).Trim

 

            If Row..Substring(0, Row..IndexOf("=")).TrimEnd.Length > 1 Then

 

                colValue = Row..Substring(Row..IndexOf("=") + 1).Trim

                Select Case colName

                    Case "Container Name"

                        Me.출력Buffer.AddRow()

                        Me.출력Buffer.ContainerName = colValue

                        Me.출력Buffer.PackageName = PackageName

                    Case "Container Description"

                        Me.출력Buffer.ContainerDescription = colValue

                    Case "Start Container Time"

                        Me.출력Buffer.StartTime = CDate(colValue)

                    Case "End Container Time"

                        Me.출력Buffer.EndTime = CDate(colValue)

                    Case "##Duration"

                        Me.출력Buffer.Duration = colValue

                    Case "Package Name"

                        PackageName = colValue

                End Select

 

 

 

            End If

 

        End If

    End Sub

 

End Class

 

 

SSIS에서는 기존 버전에 비해 다양한 변환 작업들이 제공되기 때문에 스크립트 작업을 많이 할 필요는 없습니다. 하지만, 그렇다고 해서 안 쓸 필요는 없겠지요~^^ VB.net의 막강한 기능들을 최대한 사용할 수 있다는 것이 장점이겠지요.. 뿐만 아니라, 스크립트 작업들이 Compile 된 상태로 처리가 되기 때문에 이전 보다는 훨~씬 성능이 우수합니다..(물론 패키지의 사이즈는 조금 커지겠지요~..)

 

첨부하는 패키지 파일 및 데모 입력 파일을 이용해서 테스트 해 보시기 바랍니다..

 

반응형

+ Recent posts

반응형