HOWTO · SQLite

SQLite의 변수

이 문서에서는 SQLite에서 변수의 선언 및 사용에 대해 설명합니다.

이 페이지의 내용

SQLite SQL에는 여러 문장에 걸쳐 선언하고 값을 대입하는 절차형 로컬 변수가 없습니다. 애플리케이션에서는 일반적으로 바인드 매개변수로 바뀌는 값을 전달합니다. 같은 연결에서 여러 문장이 재사용할 값은 임시 테이블에 SQL 상태로 저장할 수 있습니다. 공통 테이블 식(CTE)은 한 문장에서 사용할 값에 이름을 붙입니다. 각 방법의 범위가 다르므로 값이 필요한 기간에 맞춰 선택하세요.

SQLite는 변수를 지원하나요?

SQLite는 준비된 문장에서 매개변수를 지원하지만, 그 값은 애플리케이션이나 데이터베이스 드라이버가 전달합니다. 매개변수는 문장에서 값을 나타내는 자리표시자입니다. SQL에서 선언하는 변수가 아니며 테이블 이름이나 열 이름을 대신할 수도 없습니다. 예를 들어 SELECT * FROM products WHERE price >= ?에서 값을 바인딩할 수 있습니다. 드라이버의 매개변수 API를 사용해 입력값을 자리표시자에 연결하세요.

바인딩을 사용하면 데이터와 SQL 구문을 분리할 수 있습니다. 사용자 입력, 설정 또는 그 밖의 애플리케이션 데이터에서 가져온 값에는 바인딩을 기본으로 사용하세요. 테이블 이름이나 열 이름을 바꾸려면 애플리케이션이 관리하는 허용 목록에서 이름을 선택해 별도로 구성하세요. 이런 식별자를 바인딩 가능한 값으로 취급하면 안 됩니다.

값에는 바인드 매개변수 사용하기

다음 Python 예제는 표준 sqlite3 모듈로 샘플 행을 만들고 가격 기준값을 바인딩합니다. 정상 경로를 다루는 완결된 예제로, SQL 자리표시자에는 문자열을 이어 붙인 값이 아니라 Python에서 전달한 값이 들어갑니다. 이 예제는 기준 가격 이상의 제품명과 가격을 표시합니다. 코드와 실행 결과에 표시되는 제품명은 예제의 바이트 동일성을 유지하므로 영어로 남습니다.

이 예제를 실행하세요:

이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

import sqlite3

connection = sqlite3.connect(":memory:")
connection.execute("CREATE TABLE products (name TEXT, price REAL)")
connection.executemany(
    "INSERT INTO products (name, price) VALUES (?, ?)",
    [("Notebook", 4.5), ("Keyboard", 25.0), ("Monitor", 180.0)],
)
minimum_price = 20
rows = connection.execute(
    "SELECT name, price FROM products WHERE price >= ? ORDER BY price",
    (minimum_price,),
).fetchall()
for name, price in rows:
    print(f"{name}: {price:.2f}")
connection.close()

위치 기반 자리표시자에는 ?를 사용합니다. 이름 기반 자리표시자는 :minimum 같은 형식과 {"minimum": 20} 같은 드라이버 매핑을 사용할 수 있습니다. 드라이버가 지원하는 자리표시자 형식과 바인딩 방법을 사용하고, 모든 입력값을 SQL 문자열에 끼워 넣는 대신 바인딩하세요.

재사용할 SQL 상태에는 임시 테이블 사용하기

같은 연결에서 여러 문장이 같은 값 집합을 읽거나 갱신해야 한다면 임시 테이블이 유용합니다. CREATE TEMP TABLE settings (name TEXT, value INTEGER)로 테이블을 만들고, 일반 INSERT 문으로 행을 추가한 다음 다른 테이블처럼 조회할 수 있습니다. 문장 사이에 행을 갱신할 수도 있고, 사용을 마치면 DROP TABLE settings로 테이블을 삭제할 수 있습니다.

임시 테이블은 이를 만든 연결에 속합니다. 삭제하거나 연결이 닫힐 때까지 해당 연결의 문장에서 사용할 수 있지만, 다른 연결에서는 공유되지 않습니다. 트랜잭션은 변경 사항을 커밋할지 롤백할지를 제어하며, 임시 테이블의 연결 범위는 이와 별개의 문제입니다. 임시 테이블은 절차형 변수를 선언하는 대신 SQL 상태를 행으로 나타냅니다. 바인드 매개변수로 값을 직접 전달할 수 있다면 임시 테이블은 필요하지 않습니다.

한 문장 안에서 사용할 값에는 CTE 사용하기

CTE는 뒤따르는 문장에서 사용할 결과에 이름을 붙입니다. 예를 들어 WITH limits AS (SELECT 20 AS minimum_price) SELECT name FROM products, limits WHERE products.price >= limits.minimum_price;는 값 하나를 정의하고 같은 쿼리에서 사용합니다. CTE가 뒤이은 문장에서 읽을 수 있는 변수를 만드는 것은 아닙니다. 쿼리의 입력값이나 중간 결과를 더 읽기 쉽게 정리할 때 CTE를 사용하세요. 데이터가 같은 연결의 여러 문장에 걸쳐 필요하다면 임시 테이블을 사용하세요.

SQLite 저장 클래스와 CAST

SQLite 값은 NULL, INTEGER, REAL, TEXT, BLOB의 다섯 저장 클래스를 사용합니다. 이는 선언된 변수의 유형이 아니라 실행 중 저장되는 값의 유형을 나타냅니다. 열에는 선호도를 부여하는 선언 유형을 지정할 수 있으며, 이 선호도는 SQLite가 값을 저장하고 비교하는 방식에 영향을 줍니다. 하지만 SQLite의 유형 체계는 절차형 변수 선언의 집합이 아닙니다.

CAST(expression AS type)는 SQLite의 변환 규칙에 따라 식을 변환합니다. 이 변환은 해당 식의 결과에 적용되며, 매개변수를 바꾸거나 변수를 만들거나 다른 곳에 저장된 값을 영구적으로 변경하지 않습니다. 예를 들어 CAST('42' AS INTEGER)는 텍스트 값을 정수로 표현합니다. 변환 결과는 입력과 대상 유형에 따라 달라질 수 있으므로, 허용되는 형식이 중요하다면 CAST를 입력값 검증으로 여기지 말고 애플리케이션에서 입력을 검증하세요. 값을 캐스팅하는 것은 문자의 ASCII 코드를 얻는 일반적인 방법도 아닙니다.

적절한 방법 선택하기

애플리케이션에서 전달하는 값, 특히 사용자 입력에는 바인드 매개변수를 사용하세요. 바인드 매개변수는 값을 SQL 텍스트와 분리하며 추가 상태를 관리하지 않고 한 문장에서 사용할 수 있습니다. 같은 연결에서 여러 문장이 재사용하거나 변경할 수 있는 행 집합을 사용해야 한다면 임시 테이블을 선택하세요. 값이나 중간 결과가 한 문장에서만 필요하다면 CTE를 사용하세요. 이 방법들은 사용 기간이 서로 다른 상호 보완적인 도구이지, 지속적으로 유지되는 SQLite 변수를 선언하는 세 가지 방법이 아닙니다.