문자열 값(통화, 자리수 구분)을 숫자타입으로 변경

※ 자세한 설명은 생략 (정규식은 10g 이상 가능)

 

SELECT TO_NUMBER( REGEXP_REPLACE('$-1,234,567.89', '[^0-9.-]', '') ) NUM FROM DUAL

 

자작이며, PHP Library중 하나인 ADOdb의 crypt.inc.php의 MD5Crypt Class를 C#으로 변경 후 Oracle용 PL/SQL에 맞게 변경하였습니다.

 

MS-SQL, SQLite는 C#을 이용하여 DLL로 제작하여 로딩하시면 사용 가능합니다.

 

패키지명은 HxCrypt라고 하였습니다.

별도로 비트연산용 PKG_UTILS( http://overoid.tistory.com/35 ) / 첨부(PKG_UTILS_Oracle.sql) 참조를 이용하였습니다.

 

자세한 내용은 첨부파일을 참고하시기 바랍니다.

 

 

(ADODB가 GNU 라이센스이므로 공유는 당연하다 판단했습니다. / C#과 Oracle용으로 마이그레이션한 라이블러리를 공개합니다.)

PHP용 소스 출처 : http://adodb.org/

 

 

- 암호화 : HxCrypt.Encrypt(문자열, 키값) //호출 할 때마다 다른 값이 리턴됨

- 복호화 : HxCrypt.Decrypt(암호 문자열, 키값)

 

암호화 문자열과 키값은 반드시 키보드에 존재하는 영문+숫자+특수키 값만을 정상적으로 사용 가능하며,

 

기타 다른 문자(특수문자, 한글, )들은 문자 인코딩 타입과 플랫폼에 따라 상이한 결과가 나오므로 주의가 필요함.

 

 

[CODE]

CREATE OR REPLACE PACKAGE HxCrypt AS
/******************************************************************************
   // 출처 : userpark.net / userpark@userpark.net
   // 배포 라이센스 : GNU
   // 원 소스 출처 : http://adodb.org/ , crypt.inc.php, MD5Crypt
   NAME:       HxCrypt
   PURPOSE:

   REVISIONS:
   Ver        Date        Author           Description
   ---------  ----------  ---------------  ------------------------------------
   1.0        2018/05/10      userpark       1. Created this package.
******************************************************************************/

  FUNCTION base64_encode(inputString VARCHAR2) RETURN VARCHAR2;
  FUNCTION base64_decode(inputString VARCHAR2) RETURN VARCHAR2;
  FUNCTION Md5(inputString VARCHAR2) RETURN VARCHAR2;
  FUNCTION keyED(inputValue VARCHAR2, inputKey VARCHAR2) RETURN VARCHAR2;
  FUNCTION Encrypt (inputValue VARCHAR2, inputKey VARCHAR2) RETURN VARCHAR2;
  FUNCTION Decrypt (inputValue VARCHAR2, inputKey VARCHAR2) RETURN VARCHAR2;
  
END HxCrypt;
/



CREATE OR REPLACE PACKAGE BODY HxCrypt AS
  outputString VARCHAR2(2000);

FUNCTION base64_encode(inputString VARCHAR2) RETURN VARCHAR2 AS
  BEGIN
    outputString := utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(inputString)));
    RETURN outputString;
    EXCEPTION
     WHEN NO_DATA_FOUND THEN
       NULL;
     WHEN OTHERS THEN
       -- Consider logging the error and then re-raise
       RAISE;
  END base64_encode;
  
  FUNCTION base64_decode(inputString VARCHAR2) RETURN VARCHAR2 AS
  BEGIN
    outputString := utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(inputString)));
    RETURN outputString;
    EXCEPTION
     WHEN NO_DATA_FOUND THEN
       NULL;
     WHEN OTHERS THEN
       -- Consider logging the error and then re-raise
       RAISE;
  END base64_decode;
  
  FUNCTION Md5(inputString VARCHAR2) RETURN VARCHAR2 AS
  BEGIN
    --outputString := Md5(inputString);
    outputString := LOWER(RAWTOHEX(UTL_RAW.CAST_TO_RAW(sys.dbms_obfuscation_toolkit.md5(input_string => inputString))));
    RETURN outputString;
    EXCEPTION
     WHEN NO_DATA_FOUND THEN
       NULL;
     WHEN OTHERS THEN
       -- Consider logging the error and then re-raise
       RAISE;
  END Md5;
  
  FUNCTION KeyED (inputValue VARCHAR2, inputKey VARCHAR2) RETURN VARCHAR2 IS
ctr NUMBER := 0;
i NUMBER := 0;
nInput NUMBER := 0;
nKey NUMBER := 0;
keyValue VARCHAR2(2000);
iTxt NUMBER;
iKey NUMBER;
iVal NUMBER;
BEGIN
    i := 1;
    keyValue := Md5(inputKey);
    nInput := LENGTH(inputValue);
    nKey := LENGTH(keyValue);
    ctr := 1;
    outputString := null;
    WHILE i <= nInput LOOP
        IF ctr = nKey THEN 
           ctr := 1;
        END IF;
        --utl_raw.cast_to_raw(inputString)
        iTxt := ASCII(SUBSTR(TO_CHAR(inputValue), i, 1));
        --iTxt := utl_raw.cast_to_raw(SUBSTR(TO_CHAR(inputString), i + 1, 1));
        iKey := ASCII(SUBSTR(TO_CHAR(keyValue), ctr, 1));
        --iKey := utl_raw.cast_to_raw(SUBSTR(TO_CHAR(keyValue), ctr + 1, 1));
        --iVal := iTxt ^ iKey;
        iVal := PKG_UTILS.BITXOR(iTxt,iKey);
        outputString := outputString || CHR(iVal);
        --outputString := outputString || utl_raw.cast_to_varchar2(TO_CHAR(iVal));
        ctr := ctr + 1;
        i := i + 1;
        EXIT WHEN i > nInput; 
    END LOOP;
    RETURN outputString;
   EXCEPTION
     WHEN NO_DATA_FOUND THEN
       NULL;
     WHEN OTHERS THEN
       -- Consider logging the error and then re-raise
       RAISE;
END KeyED;

FUNCTION Encrypt (inputValue VARCHAR2, inputKey VARCHAR2) RETURN VARCHAR2 IS
Result VARCHAR2(2000);
ctr NUMBER := 0;
i NUMBER := 0;
n NUMBER := 0;
keyValue VARCHAR2(2000);
nKey NUMBER := 0;
iTxt NUMBER;
iKey NUMBER;
iVal NUMBER;
cKey VARCHAR2(8);
BEGIN
    i := 1;
    ctr := 1;
    keyValue := Md5(TO_CHAR(CEIL(DBMS_RANDOM.VALUE(0,32000))));
    n := LENGTH(inputValue);
    nKey := LENGTH(keyValue);
    Result := null;
    WHILE i <= n LOOP
        IF ctr = nKey THEN 
           ctr := 1;
        END IF;
        cKey := SUBSTR(TO_CHAR(keyValue), ctr, 1);
        iTxt := ASCII(SUBSTR(TO_CHAR(inputValue), i, 1));
        iKey := ASCII(cKey);
        --iVal := iTxt ^ iKey;
        iVal := PKG_UTILS.BITXOR(iTxt,iKey);
        Result := Result || cKey || CHR(iVal);
        ctr := ctr + 1;
        i := i + 1;
        EXIT WHEN i > n; 
    END LOOP;
    outputString := base64_encode(KeyED(Result, inputKey));
    RETURN outputString;
   EXCEPTION
     WHEN NO_DATA_FOUND THEN
       NULL;
     WHEN OTHERS THEN
       -- Consider logging the error and then re-raise
       RAISE;
END Encrypt;

FUNCTION Decrypt (inputValue VARCHAR2, inputKey VARCHAR2) RETURN VARCHAR2 IS
i NUMBER := 0;
n NUMBER := 0;
keyValue VARCHAR2(2000);
iTxt NUMBER;
iKey NUMBER;
iVal NUMBER;
BEGIN
    i := 1;
    keyValue := KeyED(base64_decode(inputValue), inputKey);
    n := LENGTH(keyValue);
    outputString := null;
    WHILE i <= n LOOP
        iKey := ASCII(SUBSTR(TO_CHAR(keyValue), i, 1));
        i := i + 1;
        iTxt := ASCII(SUBSTR(TO_CHAR(keyValue), i, 1));
        --iVal := iTxt ^ iKey;
        iVal := PKG_UTILS.BITXOR(iTxt,iKey);
        outputString := outputString || CHR(iVal);
        i := i + 1;
        EXIT WHEN i > n; 
    END LOOP;
    
    RETURN outputString;
   
   EXCEPTION
     WHEN NO_DATA_FOUND THEN
       NULL;
     WHEN OTHERS THEN
       -- Consider logging the error and then re-raise
       RAISE;
           
END Decrypt;


END HxCrypt;
/

 

 

HxCrypt_Oracle_userpark.sql

 

PKG_UTILS_Oracle.sql

 


[PHP / Crypt / MD5Crypt]암호화, 복호화 Class (ADOdb의 crypt.inc.php

http://userpark.net/124


[C# / .NET / Crypt / HxCrypt]암호화, 복호화 Class

http://userpark.net/125


[ORACLE / PL/SQL / Crypt / HxCrypt]암호화, 복호화 PACKAGE(Class)

http://userpark.net/126

 

 



2012/09/26 - [DBMS] - 순진한 트리(문서) - 재귀쿼리 방법론 에서 언급된 재귀적호출 중 MS-SQL을 이용한 MSDN자료 입니다.





원문 : http://msdn.microsoft.com/ko-kr/library/ms186243(v=sql.105).aspx







CTE(공통 테이블 식)를 사용하면 자기 자신을 참조하는 재귀적 CTE를 만들 수 있으므로 상당히 유용합니다. 재귀적 CTE는 최초 CTE가 반복적으로 실행되어 전체 결과 집합을 얻을 때까지 데이터의 하위 집합을 반환하는 CTE입니다.

재귀적 CTE를 참조하는 쿼리를 재귀 쿼리라고 합니다. 재귀 쿼리의 일반적인 용도는 계층적 데이터를 반환하는 것입니다. 예를 들어 직원을 조직도에 표시하는 경우 또는 부모 제품에 하나 이상의 구성 요소가 있고 이러한 구성 요소가 하위 구성 요소를 가지거나 다른 부모의 구성 요소일 수도 있는 제품 구성 정보(BOM) 시나리오에 데이터를 표시하는 경우가 있습니다.

재귀적 CTE는 SELECT, INSERT, UPDATE, DELETE 또는 CREATE VIEW 문 내에서 재귀 쿼리를 실행하는 데 필요한 코드를 상당히 단순화할 수 있습니다. 이전 버전의 SQL Server에서 재귀 쿼리를 실행하려면 일반적으로 임시 테이블, 커서 및 논리를 사용하여 재귀 단계의 흐름을 제어해야 합니다. 공통 테이블 식에 대한 자세한 내용은 공통 테이블 식 사용을 참조하십시오.

Transact-SQL의 재귀적 CTE 구조는 다른 프로그래밍 언어의 재귀 루틴과 비슷합니다. 다른 언어의 재귀 루틴은 스칼라 값을 반환하지만 재귀적 CTE는 여러 행을 반환할 수 있습니다.

재귀적 CTE는 다음 세 요소로 구성됩니다.

  1. 루틴의 호출

    재귀적 CTE의 첫 번째 호출은 UNION ALL, UNION, EXCEPT 또는 INTERSECT 연산자로 조인된 하나 이상의 CTE_query_definitions로 구성됩니다. 이러한 쿼리 정의는 CTE 구조의 기본 결과 집합을 형성하기 때문에 앵커 멤버라고 합니다.

    CTE_query_definitions는 CTE 자체를 참조하지 않는 경우 앵커 멤버로 간주됩니다. 모든 앵커 멤버 쿼리 정의를 첫 번째 재귀 멤버 정의 앞에 배치하고 UNION ALL 연산자를 사용하여 마지막 앵커 멤버를 첫 번째 재귀 멤버와 조인해야 합니다.

  2. 루틴의 재귀 호출

    재귀 호출에는 CTE 자체를 참조하는 UNION ALL 연산자로 조인된 하나 이상의 CTE_query_definitions가 포함됩니다. 이러한 쿼리 정의를 재귀 멤버라고 합니다.

  3. 종료 확인

    종료 확인은 암시적으로 수행됩니다. 이전 호출에서 반환되는 행이 없을 때 재귀가 중지됩니다.

참고 참고

잘못 구성된 재귀적 CTE로 인해 무한 루프가 발생할 수 있습니다. 예를 들어 재귀 멤버 쿼리 정의가 부모 열과 자식 열 모두에 대해 동일한 값을 반환하면 무한 루프가 생성된 것입니다. 재귀 쿼리의 결과를 테스트할 때 INSERT, UPDATE, DELETE 또는 SELECT 문의 OPTION 절에서 MAXRECURSION 힌트 및 0과 32,767 사이의 값을 사용하여 특정 문에 허용되는 재귀 수준의 수를 제한할 수 있습니다. 자세한 내용은 쿼리 힌트(Transact-SQL)WITH common_table_expression(Transact-SQL)을 참조하십시오.

의사 코드 및 의미 체계

재귀적 CTE 구조에는 앵커 멤버와 재귀 멤버가 적어도 하나씩 포함되어야 합니다. 다음 의사 코드에서는 단일 앵커 멤버와 단일 재귀 멤버가 포함된 간단한 재귀적 CTE의 구성 요소를 보여 줍니다.

WITH cte_name ( column_name [,...n] )

AS

(

CTE_query_definition –- Anchor member is defined.

UNION ALL

CTE_query_definition –- Recursive member is defined referencing cte_name.

)

-- Statement using the CTE

SELECT *

FROM cte_name

재귀 실행의 의미 체계는 다음과 같습니다.

  1. CTE 식을 앵커 멤버와 재귀 멤버로 분할합니다.

  2. 앵커 멤버를 실행하여 첫 번째 호출 또는 기본 결과 집합(T0)을 만듭니다.

  3. Ti는 입력으로 사용하고 Ti+1은 출력으로 사용하여 재귀 멤버를 실행합니다.

  4. 빈 집합이 반환될 때까지 3단계를 반복합니다.

  5. 결과 집합을 반환합니다. 이것은 T0에서 Tn까지의 UNION ALL입니다.

다음 예에서는 Adventure Works Cycles 회사에서 직급이 가장 높은 직원부터 시작되는 계층적 직원 목록을 반환하여 재귀적 CTE 구조의 의미 체계를 보여 줍니다. 이 예 다음에는 코드 실행 연습이 있습니다.

Transact-SQL
-- Create an Employee table.
CREATE TABLE dbo.MyEmployees
(
	EmployeeID smallint NOT NULL,
	FirstName nvarchar(30)  NOT NULL,
	LastName  nvarchar(40) NOT NULL,
	Title nvarchar(50) NOT NULL,
	DeptID smallint NOT NULL,
	ManagerID int NULL,
 CONSTRAINT PK_EmployeeID PRIMARY KEY CLUSTERED (EmployeeID ASC) 
);
-- Populate the table with values.
INSERT INTO dbo.MyEmployees VALUES 
 (1, N'Ken', N'Sánchez', N'Chief Executive Officer',16,NULL)
,(273, N'Brian', N'Welcker', N'Vice President of Sales',3,1)
,(274, N'Stephen', N'Jiang', N'North American Sales Manager',3,273)
,(275, N'Michael', N'Blythe', N'Sales Representative',3,274)
,(276, N'Linda', N'Mitchell', N'Sales Representative',3,274)
,(285, N'Syed', N'Abbas', N'Pacific Sales Manager',3,273)
,(286, N'Lynn', N'Tsoflias', N'Sales Representative',3,285)
,(16,  N'David',N'Bradley', N'Marketing Manager', 4, 273)
,(23,  N'Mary', N'Gibson', N'Marketing Specialist', 4, 16);


Transact-SQL
USE AdventureWorks2008R2;
GO
WITH DirectReports (ManagerID, EmployeeID, Title, DeptID, Level)
AS
(
-- Anchor member definition
    SELECT e.ManagerID, e.EmployeeID, e.Title, edh.DepartmentID, 
        0 AS Level
    FROM dbo.MyEmployees AS e
    INNER JOIN HumanResources.EmployeeDepartmentHistory AS edh
        ON e.EmployeeID = edh.BusinessEntityID AND edh.EndDate IS NULL
    WHERE ManagerID IS NULL
    UNION ALL
-- Recursive member definition
    SELECT e.ManagerID, e.EmployeeID, e.Title, edh.DepartmentID,
        Level + 1
    FROM dbo.MyEmployees AS e
    INNER JOIN HumanResources.EmployeeDepartmentHistory AS edh
        ON e.EmployeeID = edh.BusinessEntityID AND edh.EndDate IS NULL
    INNER JOIN DirectReports AS d
        ON e.ManagerID = d.EmployeeID
)
-- Statement that executes the CTE
SELECT ManagerID, EmployeeID, Title, DeptID, Level
FROM DirectReports
INNER JOIN HumanResources.Department AS dp
    ON DirectReports.DeptID = dp.DepartmentID
WHERE dp.GroupName = N'Sales and Marketing' OR Level = 0;
GO


코드 연습 예

  1. 재귀적 CTE인 DirectReports는 앵커 멤버와 재귀 멤버를 하나씩 정의합니다.

  2. 앵커 멤버가 기본 결과 집합 T0을 반환합니다. 이 직원은 회사에서 직급이 가장 높습니다. 즉, 상급 관리자가 없습니다.

    다음은 앵커 멤버에서 반환하는 결과 집합입니다.

    ManagerID EmployeeID Title                         Level
    --------- ---------- ----------------------------- ------
    NULL      1          Chief Executive Officer        0
    
  3. 재귀 멤버는 앵커 멤버 결과 집합에 있는 직원의 직속 하급자를 반환합니다. 이것은 Employee 테이블과 DirectReports CTE 간의 조인 작업을 통해 수행됩니다. 재귀 호출을 설정하는 것은 바로 CTE 자신에 대한 이 참조입니다. 입력(Ti)으로 사용된 CTE DirectReports 의 직원을 기준으로 조인(MyEmployees.ManagerID = DirectReports.EmployeeID)은 (Ti)를 관리자로 둔 직원을 출력(Ti+1)으로 반환합니다. 따라서 재귀 멤버의 첫 번째 반복은 다음 결과 집합을 반환합니다.

    ManagerID EmployeeID Title                         Level
    --------- ---------- ----------------------------- ------
    1         273        Vice President of Sales       1
    
  4. 재귀 멤버가 반복적으로 활성화됩니다. 재귀 멤버의 두 번째 반복에서 3단계의 단일 행 결과 집합(EmployeeID273 포함)이 입력 값으로 사용되어 다음 결과 집합을 반환합니다.

    ManagerID EmployeeID Title                         Level
    --------- ---------- ----------------------------- ------
    273       16         Marketing Manager             2
    273       274        North American Sales Manager  2
    273       285        Pacific Sales Manager         2
    

    재귀 멤버의 세 번째 반복에서 위의 결과 집합이 입력 값으로 사용되어 다음 결과 집합을 반환합니다.

    ManagerID EmployeeID Title                         Level
    --------- ---------- ----------------------------- ------
    16        23         Marketing Specialist          3
    274       275        Sales Representative          3
    274       276        Sales Representative          3
    285       286        Sales Representative          3
    
  5. 실행 중인 쿼리가 반환하는 최종 결과 집합은 앵커 멤버와 재귀 멤버가 생성한 모든 결과 집합의 합집합입니다.

    다음은 이 예에서 반환되는 전체 결과 집합입니다.

    ManagerID EmployeeID Title                         Level
    --------- ---------- ----------------------------- ------
    NULL      1          Chief Executive Officer       0
    1         273        Vice President of Sales       1
    273       16         Marketing Manager             2
    273       274        North American Sales Manager  2
    273       285        Pacific Sales Manager         2
    16        23         Marketing Specialist          3
    274       275        Sales Representative          3
    274       276        Sales Representative          3
    285       286        Sales Representative          3
    

출처 : http://blog.naver.com/lcg2004?Redirect=Log&logNo=60049785458

참고 : http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=17&MAEULNo=8&no=117409&ref=117385

Writing to Oracle CLOB fields
using System.Data.OracleClient

만약 당신이 .NET 코더고 오라클을 갖다가 데이터베이스 작업을 한다면, 이번이 적절하게 사용할 수 있는 기회가 될 것이다.^^ 읽으면서 커멘트도 달아주기 바란다!

우리 현재 프로젝트에서 우리는 ASP.NET 1.1 애플리케이션으로부터 상당한 량의 텍스트를 오라클 CLOB 필드로 쓸 필요가 있다. 우리는 이제껏 표준 MS System.Data.OracleClient 라이브러리를 (더 작은 량의 데이터를 쓰기위해) 사용해왔고, 그것은 우리에게 아주 유용했다. 나는 오라클 ODP.NET과 같은 더 최신버전의 우수한 팩이 있더라도 다른 라이브러리 팩을 소개하고 싶지 않았다.

예전의 자바 프로젝트에서 나는 CLOB를 쓰고 읽는 작업을 해왔고, 또한 나는 당신이 일반 VARCHAR과 같은 필드를 핸들해야 했다는 것을 안다.

따라서 나는 자리잡고 앉아서 .NET 동적Help과 가능하다면 가능한 모든 인터넷을 뒤지기 시작했고, 그 결과 흥미로운 것이 있었고, 나는 세가지 각각 다른 방법을 발견했다. 두가지는 정말로 단순하고 하나는 그리 단순하지 않다. 희안한 것은 내가 두 옵션은 제대로 작동할 것이라고 생각하지 않고-그러나 내가 테스트 했을 때 제대로 작동했다.
나는 3가지 방법을 여기서 공개할 것이다. 그리고 바라건데 .NET과 Oracle로 지가 머하는가를 아는 누군가는 나를 불꽃으로 격추시킬 수 있길 바란다.(청출어람하길 바란다..)

이것을 테스트 하기위해, 나는 오라클에다가 단순한 테이블을 생성하고, 그 테이블은 2개의 필드로 구성되어있다; ID(INT)와 TEXT(CLOB). 바로 그거다. 나는 노트패드로 생성된 단순 텍스트 파일을 읽을 것이며, 그것은 499KB다.

주: 이것은 테스트코드일 뿐, 당신이 실무에서 하고 싶은 것과는 별개이다. 만약 이코드를 사용하고 싶다면, 적절한 에러나 예외, 핸들링 등을 추가하라.

그래서, OracleDataAdapter를 이용하는 첫번째 방법은 안돌아 갈 것이다.(내가 클래스 라이브러리 문서들을 이해한 기준에서는..). 그러나, 맞긴맞다.

public void writeDataWithDA()

{

           FileInfo fi = new FileInfo("c:/temp/testfile.txt");

           StreamReader sr = new StreamReader(fi.FullName);

           String clob = sr.ReadToEnd();

           sr.Close();

 

           OracleDataAdapter da = new OracleDataAdapter(

               "SELECT ID, TEXT FROM CLOBTEST", ConnectionString);

           DataTable dt = new DataTable();

           // get the schema

           da.FillSchema(dt, SchemaType.Source);

 

           OracleCommandBuilder cb = new OracleCommandBuilder(da);

 

           int id = 2;

 

           // create a row containing the data

           DataRow row = dt.NewRow();

           row["ID"] = id;

           row["TEXT"] = clob;

           dt.Rows.Add(row);

 

           // update the table

           da.Update(dt);

}

두번째 방법은 OracleCommand 를 이용하는 것이며, 이것도 안돌아간다(내 생각엔). 근데 원래는 되는 방법이다.

public void writeDataWithCommand()

{

           FileInfo fi = new FileInfo("c:/temp/testfile.txt");

           StreamReader sr = new StreamReader(fi.FullName);

           String tempBuff = sr.ReadToEnd();

           sr.Close();

           

           using(OracleConnection conn = new OracleConnection(ConnectionString))

           {

                      conn.Open();

                      Console.WriteLine("Connected...") ;

                      String strSQL = 

                          "INSERT INTO CLOBTEST (ID,TEXT) VALUES (1,:TEXT_DATA) ";

 

                      OracleParameter parmData = new OracleParameter();

                      parmData.Direction = ParameterDirection.Input;

                      parmData.OracleType = OracleType.Clob;

                      parmData.ParameterName = "TEXT_DATA";

                      parmData.Value = tempBuff;

 

                      OracleCommand cm = new OracleCommand();

                      cm.Connection = conn;

                      cm.Parameters.Add(parmData);

                      cm.CommandText = strSQL;

                      cm.ExecuteNonQuery();

 

                      conn.Close();

           }

 

           Console.WriteLine("Done!") ;

}

이제 세번째 방법이다. 이것은 .NET 클래스 라이브러리 문서가 기술한 C/BLOB 핸들링 방법이며, 임시 LOB 객체를 오라클에 생성한 다음, insert작업을 하기전에, 그 객체를 쓰므로써 핸들링하는 방법이다. 이것은 역시나 잘돌아간다, 근데 이 방법은 트랜젝션과 다른 부분간에 약간 더 많은 혼란을 겪어야 한다.

public void writeWithTempBlob()

{

           FileInfo fi = new FileInfo("c:/temp/testfile.txt");

           StreamReader sr = new StreamReader(fi.FullName);

           String tempBuff = sr.ReadToEnd();

           sr.Close();

 

           using(OracleConnection conn = new OracleConnection(ConnectionString))

           {

                      conn.Open();

                      Console.WriteLine("Connected...") ;

                      OracleTransaction tx = conn.BeginTransaction();

 

                      OracleCommand tempcmd = conn.CreateCommand();

                      tempcmd.Transaction = tx;

                      tempcmd.CommandText = "declare xx clob; begin dbms_lob.createtemporary(xx, false, 0); :tempclob := xx; end;";

                      tempcmd.Parameters.Add(new OracleParameter("tempclob",

                                 OracleType.Clob)).Direction = ParameterDirection.Output;

                      tempcmd.ExecuteNonQuery();

 

                      //get the temp lob object

                      OracleLob tempLob = (OracleLob)tempcmd.Parameters[0].Value;

 

                      //transform into byte array

                      System.Text.Encoding enc = Encoding.Unicode;

                     //MUST be unicode encoded!

 

                      Byte[] b = enc.GetBytes(tempBuff);

 

                      tempLob.BeginBatch(OracleLobOpenMode.ReadWrite);

                      tempLob.Write(b,0,b.Length);

                      tempLob.EndBatch();

 

                      OracleCommand cmd = conn.CreateCommand();

                      cmd.Transaction = tx;

                      cmd.CommandText = 

                          "INSERT INTO CLOBTEST (ID, TEXT) VALUES (:ID, :TEXT)";

                      cmd.Parameters.Add("ID", 3);

                      cmd.Parameters.Add("TEXT", OracleType.Clob).Value = tempLob;

                      //insert the temp lob

 

                      cmd.ExecuteNonQuery();

 

                      tx.Commit(); 

           }

           Console.WriteLine("Done!") ;

}

임시 CLOB에 write할려면 텍스트는 유니코드여야 한다. 안그러면 당신은 완전 많은 문자들이 쓰여진 것을 경험하게 될 것이니 주의하라.^^

다른 참고자료

출처 : http://www.oracleclub.com/article/55741

설명은 안 하겠습니다.

 

WITH t AS
( 
SELECT XMLTYPE('
<ROOT>
<META use="report">
<META-NAME>Type1</META-NAME>
<META-VALUE>REQ1</META-VALUE>
</META>
<META use="report">
<META-NAME>Type2</META-NAME> 
<META-VALUE>REQ3</META-VALUE> 
</META>
<META use="report">
<META-NAME>Type3</META-NAME>
<META-VALUE>REQ4</META-VALUE>
</META>
</ROOT>
') v 
FROM dual 
) 
SELECT ExtractValue(Value(p), '/META/META-VALUE') "META-VALUE"
  FROM t 
     , TABLE(XMLSequence(Extract(v, '/ROOT/META[@use="report"]'))) p 
 WHERE ExtractValue(Value(p), '/META/META-NAME') = 'Type1'
; 
 

+ Recent posts