sqlite3
— SQLite 데이터베이스용 DB-API 2.0 인터페이스¶
소스 코드: Lib/sqlite3/
SQLite는 별도의 서버 프로세스가 필요 없고 SQL 질의 언어의 비표준 변형을 사용하여 데이터베이스에 액세스할 수 있는 경량 디스크 기반 데이터베이스를 제공하는 C 라이브러리입니다. 일부 응용 프로그램은 내부 데이터 저장을 위해 SQLite를 사용할 수 있습니다. SQLite를 사용하여 응용 프로그램을 프로토타입 한 다음 PostgreSQL 이나 Oracle과 같은 더 큰 데이터베이스로 코드를 이식할 수도 있습니다.
The sqlite3 module was written by Gerhard Häring. It provides an SQL interface compliant with the DB-API 2.0 specification described by PEP 249.
To use the module, start by creating a Connection
object that
represents the database. Here the data will be stored in the
example.db
file:
import sqlite3
con = sqlite3.connect('example.db')
The special path name :memory:
can be provided to create a temporary
database in RAM.
Once a Connection
has been established, create a Cursor
object
and call its execute()
method to perform SQL commands:
cur = con.cursor()
# Create table
cur.execute('''CREATE TABLE stocks
(date text, trans text, symbol text, qty real, price real)''')
# Insert a row of data
cur.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)")
# Save (commit) the changes
con.commit()
# We can also close the connection if we are done with it.
# Just be sure any changes have been committed or they will be lost.
con.close()
The saved data is persistent: it can be reloaded in a subsequent session even after restarting the Python interpreter:
import sqlite3
con = sqlite3.connect('example.db')
cur = con.cursor()
To retrieve data after executing a SELECT statement, either treat the cursor as
an iterator, call the cursor’s fetchone()
method to
retrieve a single matching row, or call fetchall()
to get a list
of the matching rows.
이 예제는 이터레이터 방식을 사용합니다:
>>> for row in cur.execute('SELECT * FROM stocks ORDER BY price'):
print(row)
('2006-01-05', 'BUY', 'RHAT', 100, 35.14)
('2006-03-28', 'BUY', 'IBM', 1000, 45.0)
('2006-04-06', 'SELL', 'IBM', 500, 53.0)
('2006-04-05', 'BUY', 'MSFT', 1000, 72.0)
SQL operations usually need to use values from Python variables. However, beware of using Python’s string operations to assemble queries, as they are vulnerable to SQL injection attacks (see the xkcd webcomic for a humorous example of what can go wrong):
# Never do this -- insecure!
symbol = 'RHAT'
cur.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)
Instead, use the DB-API’s parameter substitution. To insert a variable into a
query string, use a placeholder in the string, and substitute the actual values
into the query by providing them as a tuple
of values to the second
argument of the cursor’s execute()
method. An SQL statement may
use one of two kinds of placeholders: question marks (qmark style) or named
placeholders (named style). For the qmark style, parameters
must be a
sequence. For the named style, it can be either a
sequence or dict
instance. The length of the
sequence must match the number of placeholders, or a
ProgrammingError
is raised. If a dict
is given, it must contain
keys for all named parameters. Any extra items are ignored. Here’s an example of
both styles:
import sqlite3
con = sqlite3.connect(":memory:")
cur = con.cursor()
cur.execute("create table lang (name, first_appeared)")
# This is the qmark style:
cur.execute("insert into lang values (?, ?)", ("C", 1972))
# The qmark style used with executemany():
lang_list = [
("Fortran", 1957),
("Python", 1991),
("Go", 2009),
]
cur.executemany("insert into lang values (?, ?)", lang_list)
# And this is the named style:
cur.execute("select * from lang where first_appeared=:year", {"year": 1972})
print(cur.fetchall())
con.close()
더 보기
- https://www.sqlite.org
SQLite 웹 페이지; 설명서는 지원되는 SQL 언어에 대한 문법과 사용 가능한 데이터형을 설명합니다.
- https://www.w3schools.com/sql/
SQL 문법 학습을 위한 자습서, 레퍼런스 및 예제
- PEP 249 - 데이터베이스 API 명세 2.0
Marc-André Lemburg가 작성한 PEP.
모듈 함수와 상수¶
-
sqlite3.
apilevel
¶ String constant stating the supported DB-API level. Required by the DB-API. Hard-coded to
"2.0"
.
-
sqlite3.
paramstyle
¶ String constant stating the type of parameter marker formatting expected by the
sqlite3
module. Required by the DB-API. Hard-coded to"qmark"
.참고
The
sqlite3
module supports bothqmark
andnumeric
DB-API parameter styles, because that is what the underlying SQLite library supports. However, the DB-API does not allow multiple values for theparamstyle
attribute.
-
sqlite3.
version
¶ 이 모듈의 버전 번호(문자열). SQLite 라이브러리의 버전이 아닙니다.
-
sqlite3.
version_info
¶ 이 모듈의 버전 번호(정수들의 튜플). SQLite 라이브러리의 버전이 아닙니다.
-
sqlite3.
sqlite_version
¶ 런타임 SQLite 라이브러리의 버전 번호(문자열).
-
sqlite3.
sqlite_version_info
¶ 런타임 SQLite 라이브러리의 버전 번호(정수들의 튜플).
-
sqlite3.
threadsafety
¶ Integer constant required by the DB-API, stating the level of thread safety the
sqlite3
module supports. Currently hard-coded to1
, meaning “Threads may share the module, but not connections.” However, this may not always be true. You can check the underlying SQLite library’s compile-time threaded mode using the following query:import sqlite3 con = sqlite3.connect(":memory:") con.execute(""" select * from pragma_compile_options where compile_options like 'THREADSAFE=%' """).fetchall()
Note that the SQLITE_THREADSAFE levels do not match the DB-API 2.0
threadsafety
levels.
-
sqlite3.
PARSE_DECLTYPES
¶ 이 상수는
connect()
함수의 detect_types 매개 변수에 사용됩니다.이것을 설정하면
sqlite3
모듈은 반환되는 각 열에 대해 선언된 형을 구문 분석합니다. 선언된 형의 첫 번째 단어를 구문 분석합니다, 즉 “integer primary key”에서는 “integer”를, “number (10)”에서는 “number”를 구문 분석합니다. 그런 다음 해당 열에 대해, 변환기 딕셔너리를 조사하고 그 형에 대해 등록된 변환기 함수를 사용합니다.
-
sqlite3.
PARSE_COLNAMES
¶ 이 상수는
connect()
함수의 detect_types 매개 변수에 사용됩니다.Setting this makes the SQLite interface parse the column name for each column it returns. It will look for a string formed [mytype] in there, and then decide that ‘mytype’ is the type of the column. It will try to find an entry of ‘mytype’ in the converters dictionary and then use the converter function found there to return the value. The column name found in
Cursor.description
does not include the type, i. e. if you use something like'as "Expiration date [datetime]"'
in your SQL, then we will parse out everything until the first'['
for the column name and strip the preceding space: the column name would simply be “Expiration date”.
-
sqlite3.
connect
(database[, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri])¶ SQLite 데이터베이스 파일 database에 대한 연결을 엽니다. 사용자 정의 factory가 주어지지 않는 한, 기본적으로
Connection
객체를 반환합니다.database는 열릴 데이터베이스 파일의 경로명(절대 혹은 현재 작업 디렉터리에 대한 상대)을 제공하는 경로류 객체입니다.
":memory:"
를 사용하여 디스크 대신 램(RAM)에 있는 데이터베이스에 대한 데이터베이스 연결을 열 수 있습니다.데이터베이스가 여러 연결을 통해 액세스 되고, 프로세스 중 하나가 데이터베이스를 수정할 때, 해당 트랜잭션이 커밋될 때까지 SQLite 데이터베이스가 잠깁니다. timeout 매개 변수는 예외를 일으키기 전에 잠금이 해제되기를 연결이 기다려야 하는 시간을 지정합니다. timeout 매개 변수의 기본값은 5.0(5초)입니다.
isolation_level 매개 변수는
Connection
객체의isolation_level
프로퍼티를 참조하십시오.SQLite는 기본적으로 TEXT, INTEGER, REAL, BLOB 및 NULL 형만 지원합니다. 다른 형을 사용하려면 직접 지원을 추가해야 합니다. detect_types 매개 변수와 모듈 수준
register_converter()
함수로 등록된 사용자 정의 변환기를 사용하면 쉽게 할 수 있습니다.detect_types의 기본값은 0입니다 (즉, 형 감지가 없습니다).
PARSE_DECLTYPES
와PARSE_COLNAMES
의 조합으로 설정하여 형 감지를 켤 수 있습니다. SQLite 동작으로 인해, detect_types 매개 변수가 설정되어 있을 때조차, 생성된 필드(예를 들어max(data)
)에 대해 형을 감지할 수 없습니다. 이 경우, 반환되는 형은str
입니다.기본적으로 check_same_thread는
True
며, 만들고 있는 스레드 만 이 연결을 사용할 수 있습니다.False
로 설정하면 반환된 연결을 여러 스레드에서 공유할 수 있습니다. 여러 스레드에서 같은 연결을 사용할 때, 데이터 손상을 피하려면 쓰기 연산을 사용자가 직렬화해야 합니다.기본적으로,
sqlite3
모듈은 connect 호출에Connection
클래스를 사용합니다. 그러나,Connection
클래스의 서브 클래스를 만들고 factory 매개 변수에 클래스를 제공하면connect()
가 그 클래스를 사용하게 할 수 있습니다.자세한 내용은 이 설명서의 섹션 SQLite 와 파이썬 형을 참조하십시오.
sqlite3
모듈은 내부적으로 SQL 구문 분석 오버헤드를 피하고자 명령문 캐시를 사용합니다. 연결에 대해 캐시 되는 명령문의 수를 명시적으로 설정하려면, cached_statements 매개 변수를 설정할 수 있습니다. 현재 구현된 기본값은 100개의 명령문을 캐시 하는 것입니다.If uri is
True
, database is interpreted as a URI with a file path and an optional query string. The scheme part must be"file:"
. The path can be a relative or absolute file path. The query string allows us to pass parameters to SQLite. Some useful URI tricks include:# Open a database in read-only mode. con = sqlite3.connect("file:template.db?mode=ro", uri=True) # Don't implicitly create a new database file if it does not already exist. # Will raise sqlite3.OperationalError if unable to open a database file. con = sqlite3.connect("file:nosuchdb.db?mode=rw", uri=True) # Create a shared named in-memory database. con1 = sqlite3.connect("file:mem1?mode=memory&cache=shared", uri=True) con2 = sqlite3.connect("file:mem1?mode=memory&cache=shared", uri=True) con1.executescript("create table t(t); insert into t values(28);") rows = con2.execute("select * from t").fetchall()
More information about this feature, including a list of recognized parameters, can be found in the SQLite URI documentation.
인자
database
로 감사 이벤트(auditing event)sqlite3.connect
를 발생시킵니다.버전 3.4에서 변경: uri 매개 변수가 추가되었습니다.
버전 3.7에서 변경: database는 이제 문자열뿐만 아니라 경로류 객체 일 수도 있습니다.
-
sqlite3.
register_converter
(typename, callable)¶ 데이터베이스의 바이트열을 사용자 정의 파이썬 형으로 변환할 수 있는 콜러블을 등록합니다. 콜러블은 형 typename 인 모든 데이터베이스 값에 대해 호출됩니다. 형 감지 작동 방식에 대해서는
connect()
함수의 매개 변수 detect_types를 참고하십시오. typename과 질의의 형 이름은 대/소문자를 구분하지 않고 일치시킴에 유의하십시오.
-
sqlite3.
register_adapter
(type, callable)¶ 사용자 정의 파이썬 형 type을 SQLite의 지원되는 형 중 하나로 변환할 수 있는 콜러블을 등록합니다. 콜러블 callable은 단일 매개 변수로 파이썬 값을 받아들이고 다음 형들의 값을 반환해야 합니다: int, float, str 또는 bytes.
-
sqlite3.
complete_statement
(sql)¶ 문자열 sql에 세미콜론으로 끝나는 하나 이상의 완전한 SQL 문이 포함되어 있으면
True
를 반환합니다. SQL이 문법적으로 올바른지 확인하지는 않습니다. 닫히지 않은 문자열 리터럴이 없고 명령문이 세미콜론으로 끝나는지만 확인합니다.이것은 다음 예제와 같이, SQLite 용 셸을 만드는데 사용할 수 있습니다:
# A minimal SQLite shell for experiments import sqlite3 con = sqlite3.connect(":memory:") con.isolation_level = None cur = con.cursor() buffer = "" print("Enter your SQL commands to execute in sqlite3.") print("Enter a blank line to exit.") while True: line = input() if line == "": break buffer += line if sqlite3.complete_statement(buffer): try: buffer = buffer.strip() cur.execute(buffer) if buffer.lstrip().upper().startswith("SELECT"): print(cur.fetchall()) except sqlite3.Error as e: print("An error occurred:", e.args[0]) buffer = "" con.close()
Connection 객체¶
-
class
sqlite3.
Connection
¶ An SQLite database connection has the following attributes and methods:
-
isolation_level
¶ 현재의 기본 격리 수준을 가져오거나 설정합니다. 자동 커밋 모드를 뜻하는
None
이나 “DEFERRED”, “IMMEDIATE” 또는 “EXCLUSIVE” 중 하나입니다. 자세한 설명은 트랜잭션 제어 절을 참조하십시오.
-
cursor
(factory=Cursor)¶ cursor 메서드는 단일 선택적 매개 변수 factory를 받아들입니다. 제공되면, 이것은
Cursor
나 그 서브 클래스의 인스턴스를 반환하는 콜러블이어야 합니다.
-
commit
()¶ 이 메서드는 현재 트랜잭션을 커밋합니다. 이 메서드를 호출하지 않으면, 마지막
commit()
호출 이후에 수행한 작업은 다른 데이터베이스 연결에서 볼 수 없습니다. 데이터베이스에 기록한 데이터가 왜 보이지 않는지 궁금하면, 이 메서드를 호출하는 것을 잊지 않았는지 확인하십시오.
-
close
()¶ 데이터베이스 연결을 닫습니다. 자동으로
commit()
을 호출하지 않음에 유의하십시오.commit()
를 먼저 호출하지 않고 데이터베이스 연결을 닫으면 변경 사항이 손실됩니다!
-
execute
(sql[, parameters])¶ Create a new
Cursor
object and callexecute()
on it with the given sql and parameters. Return the new cursor object.
-
executemany
(sql[, parameters])¶ Create a new
Cursor
object and callexecutemany()
on it with the given sql and parameters. Return the new cursor object.
-
executescript
(sql_script)¶ Create a new
Cursor
object and callexecutescript()
on it with the given sql_script. Return the new cursor object.
-
create_function
(name, num_params, func, *, deterministic=False)¶ 나중에 함수 이름 name으로 SQL 문에서 사용할 수 있는 사용자 정의 함수를 만듭니다. num_params는 함수가 받아들이는 매개 변수의 수입니다 (num_params가 -1이면 함수는 임의의 인자를 취할 수 있습니다). func는 SQL 함수로 호출되는 파이썬 콜러블입니다. deterministic이 참이면, 만들어진 함수는 SQLite가 추가적인 최적화를 수행할 수 있도록 결정론적(deterministic)으로 표시됩니다. 이 플래그는 SQLite 3.8.3 이상에서 지원됩니다, 이전 버전에서 사용되면
NotSupportedError
가 발생합니다.함수는 SQLite가 지원하는 모든 형을 반환할 수 있습니다: bytes, str, int, float 및
None
.버전 3.8에서 변경: deterministic 매개 변수가 추가되었습니다.
예:
import sqlite3 import hashlib def md5sum(t): return hashlib.md5(t).hexdigest() con = sqlite3.connect(":memory:") con.create_function("md5", 1, md5sum) cur = con.cursor() cur.execute("select md5(?)", (b"foo",)) print(cur.fetchone()[0]) con.close()
-
create_aggregate
(name, num_params, aggregate_class)¶ 사용자 정의 집계(aggregate) 함수를 만듭니다.
매개 변수의 수 num_params(num_params가 -1이면 함수는 임의의 인자를 취할 수 있습니다)를 받아들이며, 집계 클래스는
step
메서드와 집계의 최종 결과를 반환하는finalize
메서드를 구현해야 합니다.finalize
메서드는 SQLite가 지원하는 모든 형을 반환할 수 있습니다: bytes, str, int, float 및None
.예:
import sqlite3 class MySum: def __init__(self): self.count = 0 def step(self, value): self.count += value def finalize(self): return self.count con = sqlite3.connect(":memory:") con.create_aggregate("mysum", 1, MySum) cur = con.cursor() cur.execute("create table test(i)") cur.execute("insert into test(i) values (1)") cur.execute("insert into test(i) values (2)") cur.execute("select mysum(i) from test") print(cur.fetchone()[0]) con.close()
-
create_collation
(name, callable)¶ 지정된 name 과 callable로 정렬법(collation)을 만듭니다. 콜러블에는 두 개의 문자열 인자가 전달됩니다. 첫째가 둘째보다 작은 순서면 -1, 같은 순서면 0, 첫째가 둘째보다 큰 순서면 1을 반환 해야 합니다. 이것은 정렬(SQL의 ORDER BY)을 제어하므로, 여러분의 비교는 다른 SQL 연산에 영향을 주지 않습니다.
콜러블 객체는 보통 UTF-8로 인코딩된 파이썬 바이트열로 매개 변수를 가져옵니다.
다음 예제는 “잘못된 방법”으로 정렬하는 사용자 정의 정렬법을 보여줍니다:
import sqlite3 def collate_reverse(string1, string2): if string1 == string2: return 0 elif string1 < string2: return 1 else: return -1 con = sqlite3.connect(":memory:") con.create_collation("reverse", collate_reverse) cur = con.cursor() cur.execute("create table test(x)") cur.executemany("insert into test(x) values (?)", [("a",), ("b",)]) cur.execute("select x from test order by x collate reverse") for row in cur: print(row) con.close()
정렬법을 제거하려면 callable에
None
을 사용해서create_collation
를 호출하십시오:con.create_collation("reverse", None)
-
interrupt
()¶ 연결에서 실행 중일 수 있는 모든 질의를 중단하려면, 이 메서드를 다른 스레드에서 호출할 수 있습니다. 그러면 질의가 중단되고 호출자는 예외를 받습니다.
이 루틴은 콜백을 등록합니다. 콜백은 데이터베이스의 테이블 열에 액세스할 때마다 호출됩니다. 콜백은 액세스가 허용되면
SQLITE_OK
를 반환하고, 전체 SQL 문을 에러를 일으키며 중단해야 하면SQLITE_DENY
를, 열을 NULL 값으로 처리하려면SQLITE_IGNORE
를 반환해야 합니다. 이 상수들은sqlite3
모듈에 있습니다.콜백의 첫 번째 인자는 어떤 종류의 연산이 인가받으려 하는지를 나타냅니다. 두 번째와 세 번째 인자는 첫 번째 인자에 따라 인자이거나
None
이 됩니다. 네 번째 인자는 해당하면 데이터베이스 이름(“main”, “temp” 등)입니다. 다섯 번째 인자는 액세스 시도를 담당하는 가장 안쪽의 트리거나 뷰의 이름이거나, 이 액세스 시도가 입력 SQL 코드에서 직접 발생했으면None
입니다.첫 번째 인자에 가능한 값과 첫 번째 인자에 의존하는 두 번째 및 세 번째 인자의 의미에 대해서는 SQLite 문서를 참조하십시오. 필요한 모든 상수는
sqlite3
모듈에 있습니다.
-
set_progress_handler
(handler, n)¶ 이 루틴은 콜백을 등록합니다. 콜백은 SQLite 가상 머신의 매 n개의 명령어마다 호출됩니다. 장시간 실행되는 작업 중에 SQLite로부터 호출되기를 원할 때 유용합니다, 예를 들어 GUI를 갱신하는데 사용할 수 있습니다.
이전에 설치된 모든 진행 처리기를 지우려면 handler로
None
을 사용하여 메서드를 호출하십시오.처리기 함수에서 0이 아닌 값을 반환하면 현재 실행 중인 질의가 종료되고
OperationalError
예외가 발생합니다.
-
set_trace_callback
(trace_callback)¶ SQLite 백 엔드가 실제로 실행하는 각 SQL 문마다 호출할 trace_callback을 등록합니다.
The only argument passed to the callback is the statement (as
str
) that is being executed. The return value of the callback is ignored. Note that the backend does not only run statements passed to theCursor.execute()
methods. Other sources include the transaction management of the sqlite3 module and the execution of triggers defined in the current database.None
을 trace_callback로 전달하면 추적 콜백을 비활성화합니다.참고
Exceptions raised in the trace callback are not propagated. As a development and debugging aid, use
enable_callback_tracebacks()
to enable printing tracebacks from exceptions raised in the trace callback.버전 3.3에 추가.
-
enable_load_extension
(enabled)¶ 이 루틴은 SQLite 엔진이 공유 라이브러리에서 SQLite 확장을 로드하는 것을 허용/불허합니다. SQLite 확장은 새 함수, 집계 또는 완전히 새로운 가상 테이블 구현을 정의할 수 있습니다. 잘 알려진 확장 중 하나는 SQLite와 함께 배포되는 전체 텍스트 검색 확장입니다.
로드 가능한 확장은 기본적으로 비활성화되어 있습니다. 1를 보세요.
버전 3.2에 추가.
import sqlite3 con = sqlite3.connect(":memory:") # enable extension loading con.enable_load_extension(True) # Load the fulltext search extension con.execute("select load_extension('./fts3.so')") # alternatively you can load the extension using an API call: # con.load_extension("./fts3.so") # disable extension loading again con.enable_load_extension(False) # example from SQLite wiki con.execute("create virtual table recipe using fts3(name, ingredients)") con.executescript(""" insert into recipe (name, ingredients) values ('broccoli stew', 'broccoli peppers cheese tomatoes'); insert into recipe (name, ingredients) values ('pumpkin stew', 'pumpkin onions garlic celery'); insert into recipe (name, ingredients) values ('broccoli pie', 'broccoli cheese onions flour'); insert into recipe (name, ingredients) values ('pumpkin pie', 'pumpkin sugar flour butter'); """) for row in con.execute("select rowid, name, ingredients from recipe where name match 'pie'"): print(row) con.close()
-
load_extension
(path)¶ This routine loads an SQLite extension from a shared library. You have to enable extension loading with
enable_load_extension()
before you can use this routine.로드 가능한 확장은 기본적으로 비활성화되어 있습니다. 1를 보세요.
버전 3.2에 추가.
-
row_factory
¶ 이 어트리뷰트를 커서와 원본 행을 튜플로 받아들이고 실제 결과 행을 반환하는 콜러블로 변경할 수 있습니다. 이렇게 하면, 이름으로 열을 액세스할 수 있는 객체를 반환하는 것과 같이, 결과를 반환하는 더 고급 방식을 구현할 수 있습니다.
예:
import sqlite3 def dict_factory(cursor, row): d = {} for idx, col in enumerate(cursor.description): d[col[0]] = row[idx] return d con = sqlite3.connect(":memory:") con.row_factory = dict_factory cur = con.cursor() cur.execute("select 1 as a") print(cur.fetchone()["a"]) con.close()
튜플을 반환하는 것으로 충분하지 않고 열에 대한 이름 기반 액세스를 원하면,
row_factory
를 고도로 최적화된sqlite3.Row
형으로 설정하는 것을 고려해야 합니다.Row
는 메모리 오버헤드가 거의 없이 열에 대해 인덱스 기반과 대소 문자를 구분하지 않는 이름 기반 액세스를 제공합니다. 아마도 여러분 자신의 사용자 정의 딕셔너리 기반 접근법이나 심지어 db_row 기반 해법보다 더 좋을 것입니다.
-
text_factory
¶ Using this attribute you can control what objects are returned for the
TEXT
data type. By default, this attribute is set tostr
and thesqlite3
module will returnstr
objects forTEXT
. If you want to returnbytes
instead, you can set it tobytes
.하나의 바이트열 매개 변수를 받아들이고 결과 객체를 반환하는 다른 콜러블 객체로 설정할 수도 있습니다.
예시를 위해 다음 예제 코드를 참조하십시오:
import sqlite3 con = sqlite3.connect(":memory:") cur = con.cursor() AUSTRIA = "Österreich" # by default, rows are returned as str cur.execute("select ?", (AUSTRIA,)) row = cur.fetchone() assert row[0] == AUSTRIA # but we can make sqlite3 always return bytestrings ... con.text_factory = bytes cur.execute("select ?", (AUSTRIA,)) row = cur.fetchone() assert type(row[0]) is bytes # the bytestrings will be encoded in UTF-8, unless you stored garbage in the # database ... assert row[0] == AUSTRIA.encode("utf-8") # we can also implement a custom text_factory ... # here we implement one that appends "foo" to all strings con.text_factory = lambda x: x.decode("utf-8") + "foo" cur.execute("select ?", ("bar",)) row = cur.fetchone() assert row[0] == "barfoo" con.close()
-
total_changes
¶ 데이터베이스 연결이 열린 후 수정, 삽입 또는 삭제된 데이터베이스 행의 총수를 반환합니다.
-
iterdump
()¶ SQL 텍스트 형식으로 데이터베이스를 덤프하는 이터레이터를 반환합니다. 나중에 복원할 수 있도록 메모리 데이터베이스를 저장할 때 유용합니다. 이 함수는 sqlite3 셸의 .dump 명령과 같은 기능을 제공합니다.
예:
# Convert file existing_db.db to SQL dump file dump.sql import sqlite3 con = sqlite3.connect('existing_db.db') with open('dump.sql', 'w') as f: for line in con.iterdump(): f.write('%s\n' % line) con.close()
-
backup
(target, *, pages=-1, progress=None, name="main", sleep=0.250)¶ This method makes a backup of an SQLite database even while it’s being accessed by other clients, or concurrently by the same connection. The copy will be written into the mandatory argument target, that must be another
Connection
instance.기본적으로, 또는 pages가
0
이나 음의 정수이면, 전체 데이터베이스가 단일 단계로 복사됩니다; 그렇지 않으면 이 메서드는 한 번에 최대 pages 페이지만큼 복사하는 루프를 수행합니다.progress가 지정되면,
None
또는 매 이터레이션마다 세 개의 정수 인자로 실행되는 콜러블 객체여야 합니다. 세 인자는 각각 직전 이터레이션의 상태(status), 아직 복사해야 할 남은(remaining) 페이지 수, 전체(total) 페이지 수입니다.name 인자는 복사할 데이터베이스 이름을 지정합니다: main 데이터베이스를 나타내는
"main"
, 기본값, 임시 데이터베이스를 나타내는"temp"
또는 첨부된 데이터베이스를 위한ATTACH DATABASE
문에서AS
키워드 뒤에 지정된 이름을 포함하는 문자열이어야 합니다.sleep 인자는 남은 페이지를 백업하는 연속적인 시도 사이에서 잠잘 시간을 초 단위로 지정하며, 정수 또는 부동 소수점 값으로 지정할 수 있습니다.
예제 1, 기존 데이터베이스를 다른 데이터베이스로 복사:
import sqlite3 def progress(status, remaining, total): print(f'Copied {total-remaining} of {total} pages...') con = sqlite3.connect('existing_db.db') bck = sqlite3.connect('backup.db') with bck: con.backup(bck, pages=1, progress=progress) bck.close() con.close()
예제 2, 기존 데이터베이스를 임시 복사본으로 복사:
import sqlite3 source = sqlite3.connect('existing_db.db') dest = sqlite3.connect(':memory:') source.backup(dest)
가용성: SQLite 3.6.11 이상
버전 3.7에 추가.
-
Cursor 객체¶
-
class
sqlite3.
Cursor
¶ Cursor
인스턴스에는 다음과 같은 어트리뷰트와 메서드가 있습니다.-
execute
(sql[, parameters])¶ Executes an SQL statement. Values may be bound to the statement using placeholders.
execute()
는 단일 SQL 문만 실행합니다. 하나 이상의 명령문을 실행하려고 하면Warning
이 발생합니다. 하나의 호출로 여러 SQL 문을 실행하려면executescript()
를 사용하십시오.
-
executemany
(sql, seq_of_parameters)¶ Executes a parameterized SQL command against all parameter sequences or mappings found in the sequence seq_of_parameters. The
sqlite3
module also allows using an iterator yielding parameters instead of a sequence.import sqlite3 class IterChars: def __init__(self): self.count = ord('a') def __iter__(self): return self def __next__(self): if self.count > ord('z'): raise StopIteration self.count += 1 return (chr(self.count - 1),) # this is a 1-tuple con = sqlite3.connect(":memory:") cur = con.cursor() cur.execute("create table characters(c)") theIter = IterChars() cur.executemany("insert into characters(c) values (?)", theIter) cur.execute("select c from characters") print(cur.fetchall()) con.close()
다음은 제너레이터를 사용하는 간단한 예입니다:
import sqlite3 import string def char_generator(): for c in string.ascii_lowercase: yield (c,) con = sqlite3.connect(":memory:") cur = con.cursor() cur.execute("create table characters(c)") cur.executemany("insert into characters(c) values (?)", char_generator()) cur.execute("select c from characters") print(cur.fetchall()) con.close()
-
executescript
(sql_script)¶ This is a nonstandard convenience method for executing multiple SQL statements at once. It issues a
COMMIT
statement first, then executes the SQL script it gets as a parameter. This method disregardsisolation_level
; any transaction control must be added to sql_script.sql_script는
str
의 인스턴스가 될 수 있습니다.예:
import sqlite3 con = sqlite3.connect(":memory:") cur = con.cursor() cur.executescript(""" create table person( firstname, lastname, age ); create table book( title, author, published ); insert into book(title, author, published) values ( 'Dirk Gently''s Holistic Detective Agency', 'Douglas Adams', 1987 ); """) con.close()
-
fetchmany
(size=cursor.arraysize)¶ 질의 결과의 다음 행 집합을 가져와서, 리스트를 반환합니다. 행이 더 없으면 빈 목록이 반환됩니다.
호출 당 가져오는 행의 수는 size 매개 변수로 지정됩니다. 지정되어 않으면, 커서의 arraysize가 가져올 행의 수를 결정합니다. 이 메서드는 size 매개 변수가 나타내는 수만큼의 행을 가져오려고 해야 합니다. 지정된 수의 행이 없어서 이것이 가능하지 않다면, 더 적은 행이 반환될 수 있습니다.
size 매개 변수와 관련된 성능 고려 사항이 있습니다. 최적의 성능을 위해서, 일반적으로 arraysize 어트리뷰트를 사용하는 것이 가장 좋습니다. size 매개 변수가 사용되면,
fetchmany()
호출마다 같은 값을 유지하는 것이 가장 좋습니다.
-
fetchall
()¶ 질의 결과의 모든 (남은) 행을 가져와서 리스트를 반환합니다. 커서의 arraysize 어트리뷰트는 이 연산의 성능에 영향을 줄 수 있습니다. 행이 없으면 빈 리스트가 반환됩니다.
-
close
()¶ (
__del__
이 호출 될 때가 아니라) 지금 커서를 닫습니다.이 시점부터는 커서를 사용할 수 없습니다; 커서로 어떤 연산이건 시도하면
ProgrammingError
예외가 발생합니다.
-
rowcount
¶ sqlite3
모듈의Cursor
클래스가 이 어트리뷰트를 구현하지만, “영향을 받는 행”/”선택된 행”의 판단을 위한 데이터베이스 엔진 자체 지원은 기이합니다.executemany()
문에서, 수정 횟수는rowcount
에 합산됩니다.파이썬 DB API 스펙에 따라,
rowcount
어트리뷰트는 커서에서executeXX()
가 수행되지 않았거나 마지막 연산의 행 개수가 인터페이스에 의해 결정되지 않는 경우 -1입니다. 이런 경우는SELECT
문을 포함하는데, 모든 행을 가져올 때까지 질의가 생성 한 행 수를 결정할 수 없기 때문입니다.3.6.5 이전의 SQLite 버전에서는, 조건 없이
DELETE FROM table
을 하면rowcount
가 0으로 설정됩니다.
-
lastrowid
¶ This read-only attribute provides the row id of the last inserted row. It is only updated after successful
INSERT
orREPLACE
statements using theexecute()
method. For other statements, afterexecutemany()
orexecutescript()
, or if the insertion failed, the value oflastrowid
is left unchanged. The initial value oflastrowid
isNone
.참고
Inserts into
WITHOUT ROWID
tables are not recorded.버전 3.6에서 변경:
REPLACE
문에 대한 지원이 추가되었습니다.
-
arraysize
¶ fetchmany()
에 의해 반환되는 행의 수를 제어하는 읽기/쓰기 어트리뷰트. 기본값은 1입니다. 이는 호출 당 하나의 행을 가져오는 것을 뜻합니다.
-
description
¶ 이 읽기 전용 어트리뷰트는 마지막 질의의 열 이름을 제공합니다. 파이썬 DB API와의 호환성을 유지하기 위해, 각 열마다 7-튜플을 반환하는데, 각 튜플의 마지막 6개 항목은
None
입니다.일치하는 행이 없는
SELECT
문에도 설정됩니다.
-
connection
¶ 이 읽기 전용 어트리뷰트는
Cursor
객체가 사용하는 SQLite 데이터베이스Connection
을 제공합니다.con.cursor()
를 호출하여 생성된Cursor
객체는 con을 참조하는connection
어트리뷰트를 가집니다:>>> con = sqlite3.connect(":memory:") >>> cur = con.cursor() >>> cur.connection == con True
-
Row 객체¶
-
class
sqlite3.
Row
¶ Row
인스턴스는Connection
객체에 대해 고도로 최적화된row_factory
역할을 합니다. 대부분 기능에서 튜플을 모방하려고 합니다.열 이름과 인덱스에 의한 매핑 액세스와, 이터레이션, 표현(repr), 동등성 검사 및
len()
을 지원합니다.두 개의
Row
객체가 정확히 같은 열을 갖고 그 구성원이 같으면 같다고 비교됩니다.-
keys
()¶ 이 메서드는 열 이름 리스트를 반환합니다. 질의 직후,
Cursor.description
에 있는 각 튜플의 첫 번째 멤버입니다.
버전 3.5에서 변경: 슬라이싱 지원이 추가되었습니다.
-
위에서 주어진 예제에서처럼 테이블을 초기화한다고 가정해 봅시다:
con = sqlite3.connect(":memory:")
cur = con.cursor()
cur.execute('''create table stocks
(date text, trans text, symbol text,
qty real, price real)''')
cur.execute("""insert into stocks
values ('2006-01-05','BUY','RHAT',100,35.14)""")
con.commit()
cur.close()
이제 우리는 Row
를 연결합니다:
>>> con.row_factory = sqlite3.Row
>>> cur = con.cursor()
>>> cur.execute('select * from stocks')
<sqlite3.Cursor object at 0x7f4e7dd8fa80>
>>> r = cur.fetchone()
>>> type(r)
<class 'sqlite3.Row'>
>>> tuple(r)
('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14)
>>> len(r)
5
>>> r[2]
'RHAT'
>>> r.keys()
['date', 'trans', 'symbol', 'qty', 'price']
>>> r['qty']
100.0
>>> for member in r:
... print(member)
...
2006-01-05
BUY
RHAT
100.0
35.14
예외¶
-
exception
sqlite3.
DatabaseError
¶ 데이터베이스와 관련된 에러에 대해 발생하는 예외.
-
exception
sqlite3.
IntegrityError
¶ 데이터베이스의 관계형 무결성이 영향을 받을 때 발생하는 예외. 예를 들어, 외부 키(foreign key) 검사가 실패할 때.
DatabaseError
의 서브 클래스입니다.
-
exception
sqlite3.
ProgrammingError
¶ 프로그래밍 에러에 대한 예외, 예를 들어, 테이블을 찾을 수 없거나 이미 존재 함, SQL 문의 문법 에러, 지정된 매개 변수 개수가 잘못됨 등.
DatabaseError
의 서브 클래스입니다.
-
exception
sqlite3.
OperationalError
¶ 데이터베이스 연산과 관련되고 프로그래머의 제어하에 있지 않은 에러에 관한 오류. 예를 들어, 예기치 않은 단절이 발생하거나, 데이터 소스 이름을 찾을 수 없거나, 트랜잭션이 진행될 수 없을 때 등.
DatabaseError
의 서브 클래스입니다.
-
exception
sqlite3.
NotSupportedError
¶ 데이터베이스에서 지원하지 않는 메서드나 데이터베이스 API가 사용될 때 발생하는 예외. 예를 들어, 트랜잭션을 지원하지 않는 연결에서
rollback()
메서드를 호출할 때.DatabaseError
의 서브 클래스입니다.
SQLite 와 파이썬 형¶
소개¶
SQLite는 기본적으로 다음 형을 지원합니다: NULL
, INTEGER
, REAL
, TEXT
, BLOB
.
따라서 다음과 같은 파이썬 형을 아무 문제 없이 SQLite로 보낼 수 있습니다:
파이썬 형 |
SQLite 형 |
---|---|
|
|
|
|
|
|
|
|
|
이것은 SQLite 형이 기본적으로 파이썬 형으로 변환되는 방법입니다:
SQLite 형 |
파이썬 형 |
---|---|
|
|
|
|
|
|
|
|
|
The type system of the sqlite3
module is extensible in two ways: you can
store additional Python types in an SQLite database via object adaptation, and
you can let the sqlite3
module convert SQLite types to different Python
types via converters.
어댑터를 사용하여 SQLite 데이터베이스에 추가 파이썬 형을 저장하기¶
앞에서 설명한 것처럼, SQLite는 기본적으로 제한된 형 집합만 지원합니다. SQLite에 다른 파이썬 형을 사용하려면, SQLite에 대해 sqlite3 모듈이 지원하는 형 중 하나로 어댑트 해야 합니다: NoneType, int, float, str, bytes 중 하나.
sqlite3
모듈이 사용자 정의 파이썬 형을, 지원되는 형 중 하나로 어댑트하도록 만드는 두 가지 방법이 있습니다.
객체가 스스로 어댑트하도록 하기¶
여러분이 스스로 클래스를 작성한다면 이것이 좋은 접근법입니다. 다음과 같은 클래스가 있다고 가정해 봅시다:
class Point:
def __init__(self, x, y):
self.x, self.y = x, y
이제 Point를 단일 SQLite 열에 저장하려고 합니다. 먼저 포인트를 나타내는데 사용할 지원되는 형 중 하나를 선택해야 합니다. str을 사용하고 좌표를 세미콜론으로 분리하기로 합시다. 그런 다음 여러분의 클래스에 변환된 값을 반환하는 __conform__(self, protocol)
메서드를 제공해야 합니다. 매개 변수 protocol은 PrepareProtocol
이 됩니다.
import sqlite3
class Point:
def __init__(self, x, y):
self.x, self.y = x, y
def __conform__(self, protocol):
if protocol is sqlite3.PrepareProtocol:
return "%f;%f" % (self.x, self.y)
con = sqlite3.connect(":memory:")
cur = con.cursor()
p = Point(4.0, -3.2)
cur.execute("select ?", (p,))
print(cur.fetchone()[0])
con.close()
어댑터 콜러블 등록하기¶
또 다른 가능성은 형을 문자열 표현으로 변환하는 함수를 만들고. 그 함수를 register_adapter()
로 등록하는 것입니다.
import sqlite3
class Point:
def __init__(self, x, y):
self.x, self.y = x, y
def adapt_point(point):
return "%f;%f" % (point.x, point.y)
sqlite3.register_adapter(Point, adapt_point)
con = sqlite3.connect(":memory:")
cur = con.cursor()
p = Point(4.0, -3.2)
cur.execute("select ?", (p,))
print(cur.fetchone()[0])
con.close()
sqlite3
모듈에는 파이썬의 내장 datetime.date
와 datetime.datetime
형에 대한 두 개의 기본 어댑터가 있습니다. 이제 datetime.datetime
객체를 ISO 표현이 아닌 유닉스 타임스탬프로 저장하려고 한다고 가정해 봅시다.
import sqlite3
import datetime
import time
def adapt_datetime(ts):
return time.mktime(ts.timetuple())
sqlite3.register_adapter(datetime.datetime, adapt_datetime)
con = sqlite3.connect(":memory:")
cur = con.cursor()
now = datetime.datetime.now()
cur.execute("select ?", (now,))
print(cur.fetchone()[0])
con.close()
SQLite 값을 사용자 정의 파이썬 형으로 변환하기¶
어댑터를 작성하면 사용자 정의 파이썬 형을 SQLite로 보낼 수 있습니다. 그러나 실제로 유용하게 사용하려면 파이썬에서 SQLite를 거쳐 다시 파이썬으로 돌아오는 순환이 동작하게 할 필요가 있습니다.
변환기를 사용하십시오.
Point
클래스로 돌아갑시다. 세미콜론으로 분리된 x와 y 좌표를 SQLite에 문자열로 저장했습니다.
먼저, 문자열을 매개 변수로 받아들이고 이것으로부터 Point
객체를 만드는 변환기 함수를 정의합니다.
참고
변환기 함수는 항상 SQLite로 보낸 값의 데이터형에 상관없이 bytes
객체로 호출됩니다.
def convert_point(s):
x, y = map(float, s.split(b";"))
return Point(x, y)
이제 sqlite3
모듈이 데이터베이스에서 select 한 것이 실제로 Point임을 알게 해야 합니다. 이렇게 하는 두 가지 방법이 있습니다:
선언된 형을 통해 묵시적으로
열 이름을 통해 명시적으로
두 가지 방법은 섹션 모듈 함수와 상수 의 상수 PARSE_DECLTYPES
와 PARSE_COLNAMES
에 대한 항목에서 설명합니다.
다음 예는 두 가지 접근법을 보여줍니다.
import sqlite3
class Point:
def __init__(self, x, y):
self.x, self.y = x, y
def __repr__(self):
return "(%f;%f)" % (self.x, self.y)
def adapt_point(point):
return ("%f;%f" % (point.x, point.y)).encode('ascii')
def convert_point(s):
x, y = list(map(float, s.split(b";")))
return Point(x, y)
# Register the adapter
sqlite3.register_adapter(Point, adapt_point)
# Register the converter
sqlite3.register_converter("point", convert_point)
p = Point(4.0, -3.2)
#########################
# 1) Using declared types
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES)
cur = con.cursor()
cur.execute("create table test(p point)")
cur.execute("insert into test(p) values (?)", (p,))
cur.execute("select p from test")
print("with declared types:", cur.fetchone()[0])
cur.close()
con.close()
#######################
# 1) Using column names
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_COLNAMES)
cur = con.cursor()
cur.execute("create table test(p)")
cur.execute("insert into test(p) values (?)", (p,))
cur.execute('select p as "p [point]" from test')
print("with column names:", cur.fetchone()[0])
cur.close()
con.close()
기본 어댑터와 변환기¶
datetime 모듈의 date와 datetime 형에 대한 기본 어댑터가 있습니다. 이것들은 ISO 날짜/ISO 타임스탬프로 SQLite로 보내집니다.
기본 변환기는 datetime.date
는 “date”라는 이름으로, datetime.datetime
은 “timestamp”라는 이름으로 등록됩니다.
이런 방법으로, 대부분 추가 작업 없이 파이썬의 날짜/타임스탬프를 사용할 수 있습니다. 어댑터의 형식은 실험적인 SQLite 날짜/시간 함수와도 호환됩니다.
다음 예제는 이를 보여줍니다.
import sqlite3
import datetime
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
cur = con.cursor()
cur.execute("create table test(d date, ts timestamp)")
today = datetime.date.today()
now = datetime.datetime.now()
cur.execute("insert into test(d, ts) values (?, ?)", (today, now))
cur.execute("select d, ts from test")
row = cur.fetchone()
print(today, "=>", row[0], type(row[0]))
print(now, "=>", row[1], type(row[1]))
cur.execute('select current_date as "d [date]", current_timestamp as "ts [timestamp]"')
row = cur.fetchone()
print("current_date", row[0], type(row[0]))
print("current_timestamp", row[1], type(row[1]))
con.close()
SQLite에 저장된 타임스탬프가 6자리보다 긴 소수부가 있으면, 그 값은 타임스탬프 변환기에 의해 마이크로초 정밀도로 잘립니다.
참고
The default “timestamp” converter ignores UTC offsets in the database and
always returns a naive datetime.datetime
object. To preserve UTC
offsets in timestamps, either leave converters disabled, or register an
offset-aware converter with register_converter()
.
트랜잭션 제어¶
하부 sqlite3
라이브러리는 기본적으로 autocommit
모드로 작동하지만, 파이썬 sqlite3
모듈은 기본적으로 그렇지 않습니다.
autocommit
모드는 데이터베이스를 수정하는 명령문이 즉시 적용됨을 뜻합니다. BEGIN
이나 SAVEPOINT
문은 autocommit
모드를 비활성화하고, 가장 바깥쪽 트랜잭션을 끝내는 COMMIT
, ROLLBACK
또는 RELEASE
는 autocommit
모드를 다시 켭니다.
기본적으로 파이썬 sqlite3
모듈은 데이터 조작 언어(DML - Data Modification Language) 문 (즉, INSERT
/UPDATE
/DELETE
/REPLACE
) 앞에 암묵적으로 BEGIN
문을 넣습니다.
connect()
호출의 isolation_level 매개 변수를 통해, 또는 연결의 isolation_level
프로퍼티를 통해, sqlite3
가 묵시적으로 실행하는 BEGIN
문의 종류를 제어할 수 있습니다. isolation_level을 지정하지 않으면, 단순한 BEGIN
이 사용되며, 이는 DEFERRED
를 지정하는 것과 같습니다. 가능한 다른 값은 IMMEDIATE
와 EXCLUSIVE
입니다.
isolation_level
를 None
로 설정하여 sqlite3
모듈의 묵시적 트랜잭션 관리를 비활성화할 수 있습니다. 그러면 하부 sqlite3
라이브러리가 autocommit
모드로 작동합니다. 그런 다음 코드에서 BEGIN
, ROLLBACK
, SAVEPOINT
및 RELEASE
문을 명시적으로 실행하여 트랜잭션 상태를 완전히 제어할 수 있습니다.
Note that executescript()
disregards
isolation_level
; any transaction control must be added explicitly.
버전 3.6에서 변경: sqlite3
는 DDL 문 앞에서 열린 트랜잭션을 묵시적으로 커밋했습니다. 더는 그렇지 않습니다.
효율적으로 sqlite3
사용하기¶
바로 가기 메서드 사용하기¶
Connection
객체의 비표준 execute()
, executemany()
및 executescript()
메서드를 사용하면, (종종 불필요한) Cursor
객체를 명시적으로 만들 필요가 없으므로, 코드를 더 간결하게 작성할 수 있습니다. 대신, Cursor
객체가 묵시적으로 만들어지며 이러한 바로 가기 메서드는 커서 객체를 반환합니다. 이런 방법으로, Connection
객체에 대한 단일 호출만 사용하여 SELECT
문을 실행하고 직접 이터레이트할 수 있습니다.
import sqlite3
langs = [
("C++", 1985),
("Objective-C", 1984),
]
con = sqlite3.connect(":memory:")
# Create the table
con.execute("create table lang(name, first_appeared)")
# Fill the table
con.executemany("insert into lang(name, first_appeared) values (?, ?)", langs)
# Print the table contents
for row in con.execute("select name, first_appeared from lang"):
print(row)
print("I just deleted", con.execute("delete from lang").rowcount, "rows")
# close is not a shortcut method and it's not called automatically,
# so the connection object should be closed manually
con.close()
인덱스 대신 이름으로 열 액세스하기¶
sqlite3
모듈의 유용한 기능 중 하나는 행 팩토리로 사용하도록 설계된 내장 sqlite3.Row
클래스입니다.
이 클래스로 감싼 행은 인덱스(튜플처럼)와 대소 문자를 구분하지 않는 이름으로 액세스할 수 있습니다:
import sqlite3
con = sqlite3.connect(":memory:")
con.row_factory = sqlite3.Row
cur = con.cursor()
cur.execute("select 'John' as name, 42 as age")
for row in cur:
assert row[0] == row["name"]
assert row["name"] == row["nAmE"]
assert row[1] == row["age"]
assert row[1] == row["AgE"]
con.close()
컨텍스트 관리자로 연결 사용하기¶
연결 객체는 트랜잭션을 자동으로 커밋하거나 롤백하는 컨텍스트 관리자로 사용할 수 있습니다. 예외가 발생하면, 트랜잭션이 롤백 됩니다; 그렇지 않으면 트랜잭션이 커밋 됩니다:
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("create table lang (id integer primary key, name varchar unique)")
# Successful, con.commit() is called automatically afterwards
with con:
con.execute("insert into lang(name) values (?)", ("Python",))
# con.rollback() is called after the with block finishes with an exception, the
# exception is still raised and must be caught
try:
with con:
con.execute("insert into lang(name) values (?)", ("Python",))
except sqlite3.IntegrityError:
print("couldn't add Python twice")
# Connection object used as context manager only commits or rollbacks transactions,
# so the connection object should be closed manually
con.close()
각주