Post List

2015년 9월 4일 금요일

Python 과 Oracle 연동 #03 cx_Oracle : Cursor Object 및 SQL 실행하기

앞 장에서 cx_Oracle.connect() 함수를 이용하여 Oracle에 접속하는 방법에 대해서 살펴보았습니다.
그 결과 Connection Object를 생성하였습니다.

Connection Object에서 SQL문을 실행하기 위해서는 Cursor Object를 생성해야 합니다.
Connection.cursor() 함수를 실행하여 얻을 수 있습니다.

import cx_Oracle

conn = cx_Oracle.connect('sys/orange@localhost:1521/orcl', mode = cx_Oracle.SYSDBA)
cursor = conn.cursor()

순서상 Connection Object에 대한 설명이 먼저 와야 하지만, 기본적인 활용 단계에서는 자세히 살펴보지 않아도 됩니다.

Transaction을 제어, logon password 변경, shutdown database, cache size 변경 등의 작업을 할 경우에는 Connection Object에 대해서 아셔야 합니다만,
SQL 실행에 대해서는 몰라도 상관없습니다.

Connection Object에 대한 설명은 아래 Link에서 문서를 참조하시기 바랍니다.

http://cx-oracle.readthedocs.org/en/latest/connection.html


* Cursor Object

Connection Object 에서 cursor() 함수를 이용하여 선언이 가능합니다.
일반적으로는 1개의 cursor를 계속 해서 반복 사용하는게 보통입니다.
큰 project에서는 여러개의 cursor를 각각 선언하여 사용하기도 합니다.
cursor 별로 다른 query 결과를 담아두고 필요에 따라 fetch 하면서 사용하는 식의 process를 생각하시면 여러 cursor 의 필요성을 충분히 생각하실 수 있을 것입니다.

Cursor Object 의 기능 중 다음 3가지 가장 중요합니다.
일단 저정도만 알아도 Oracle에 대한 작업에는 큰 지장이 없습니다.

1. Parse

 cx_Oracle.Cursor.parse([statement])

중요하다고 바로 위에서 얘기했지만, 솔직히 몰라도 상관없는 기능이긴 합니다.
통상적으로는 execute() 실행시 자동으로 parse 단계를 거치기 때문에 잘 사용되지 않습니다만,
실행전에 statementvalidate 할 용도로 사용 할 수 있습니다.
만약 statement에 error가 있다면

ORA-00900 : invalid SQL statement,
ORA-01301 : insufficient privileges
ORA-00921 : unexpected end of SQL command

등의 DatabaseError exception을 야기시킵니다.

2. Execute

 cx_Oracle.Cursor.execute(statement, parameters)

statement 하나만 인자로 받은 경우에는 해당 statement를 실행합니다.
binding variable을 사용할 경우에는 parameters도 같이 입력을 해 주어야 합니다.
parameters 로 Dictionary를 전달할 경우에는 bind variable 이름과 값을 전달해 주면 되며,
parameters 로 List를 전달할 경우에는 bind variable의 순서대로 값을 전달해 주면 됩니다.
return 값이 있는 경우에는 List로 결과값들을 받습니다.
(binding variable 에 대해서는 다음 post에서 설명드리겠습니다.)

3. Fetch

Query 에서만 사용가능한 기능입니다. 왜냐면 DDL 과 DCL은 return 값이 없기 때문입니다.
cursor 가 query를 실행시키지 않은 경우에 사용하게 되면 InterfaceError exception 을 발생시킵니다.

cx_Oracle.Cursor.fetchall()
남아있는 모든 Row 들을 Tuple 들의 Listreturn 합니다.

cx_Oracle.Cursor.fetchmany([rows_no])
인자로 전달한 수 만큼의 row를 return 합니다.

cx_Oracle.Cursor.fetchone()
하나의 row를 tuplereturn 합니다.

Cursor Object에 대해서 좀 더 자세히 알고 싶으시면 아래 Link를 참고하세요.

http://cx-oracle.readthedocs.org/en/latest/cursor.html

* 예제

* 결과

>>> print(cursor.fetchone())
(7369, 'SMITH', 'CLERK', 7902, datetime.datetime(1980, 12, 17, 0, 0), 800.0, None, 20)

>>> print(cursor.fetchone())
(7499, 'ALLEN', 'SALESMAN', 7698, datetime.datetime(1981, 2, 20, 0, 0), 1600.0, 300.0, 30)

>>> print(cursor.fetchmany(2))
[(7521, 'WARD', 'SALESMAN', 7698, datetime.datetime(1981, 2, 22, 0, 0), 1250.0, 500.0, 30), (7566, 'JONES', 'MANAGER', 7839, datetime.datetime(1981, 4, 2, 0, 0), 2975.0, None, 20)]

>>> print(cursor.fetchall())
[(7654, 'MARTIN', 'SALESMAN', 7698, datetime.datetime(1981, 9, 28, 0, 0), 1250.0, 1400.0, 30), (7698, 'BLAKE', 'MANAGER', 7839, datetime.datetime(1981, 5, 1, 0, 0), 2850.0, None, 30), (7782, 'CLARK', 'MANAGER', 7839, datetime.datetime(1981, 6, 9, 0, 0), 2450.0, None, 10), (7788, 'SCOTT', 'ANALYST', 7566, datetime.datetime(1982, 12, 9, 0, 0), 3000.0, None, 20), (7839, 'KING', 'PRESIDENT', None, datetime.datetime(1981, 11, 17, 0, 0), 5000.0, None, 10), (7844, 'TURNER', 'SALESMAN', 7698, datetime.datetime(1981, 9, 8, 0, 0), 1500.0, 0.0, 30), (7876, 'ADAMS', 'CLERK', 7788, datetime.datetime(1983, 1, 12, 0, 0), 1100.0, None, 20), (7900, 'JAMES', 'CLERK', 7698, datetime.datetime(1981, 12, 3, 0, 0), 950.0, None, 30), (7902, 'FORD', 'ANALYST', 7566, datetime.datetime(1981, 12, 3, 0, 0), 3000.0, None, 20), (7934, 'MILLER', 'CLERK', 7782, datetime.datetime(1982, 1, 23, 0, 0), 1300.0, None, 10)]

>>> for record in cursor: print(record)
(7369, 'SMITH', 'CLERK', 7902, datetime.datetime(1980, 12, 17, 0, 0), 800.0, None, 20)
(7499, 'ALLEN', 'SALESMAN', 7698, datetime.datetime(1981, 2, 20, 0, 0), 1600.0, 300.0, 30)
(7521, 'WARD', 'SALESMAN', 7698, datetime.datetime(1981, 2, 22, 0, 0), 1250.0, 500.0, 30)
(7566, 'JONES', 'MANAGER', 7839, datetime.datetime(1981, 4, 2, 0, 0), 2975.0, None, 20)
(7654, 'MARTIN', 'SALESMAN', 7698, datetime.datetime(1981, 9, 28, 0, 0), 1250.0, 1400.0, 30)
(7698, 'BLAKE', 'MANAGER', 7839, datetime.datetime(1981, 5, 1, 0, 0), 2850.0, None, 30)
(7782, 'CLARK', 'MANAGER', 7839, datetime.datetime(1981, 6, 9, 0, 0), 2450.0, None, 10)
(7788, 'SCOTT', 'ANALYST', 7566, datetime.datetime(1982, 12, 9, 0, 0), 3000.0, None, 20)
(7839, 'KING', 'PRESIDENT', None, datetime.datetime(1981, 11, 17, 0, 0), 5000.0, None, 10)
(7844, 'TURNER', 'SALESMAN', 7698, datetime.datetime(1981, 9, 8, 0, 0), 1500.0, 0.0, 30)
(7876, 'ADAMS', 'CLERK', 7788, datetime.datetime(1983, 1, 12, 0, 0), 1100.0, None, 20)
(7900, 'JAMES', 'CLERK', 7698, datetime.datetime(1981, 12, 3, 0, 0), 950.0, None, 30)
(7902, 'FORD', 'ANALYST', 7566, datetime.datetime(1981, 12, 3, 0, 0), 3000.0, None, 20)
(7934, 'MILLER', 'CLERK', 7782, datetime.datetime(1982, 1, 23, 0, 0), 1300.0, None, 10)

>>> print
(cursor.execute('SELECT * FROM SCOTT.TESTPY').fetchall())
[(10, 'LUNA')]




댓글 없음:

댓글 쓰기