sqlite3.OperationalError: no such table은 코드에 적은 테이블이 현재 연결된 데이터베이스에 없다는 뜻입니다. 먼저 PRAGMA database_list로 실제 연결된 DB 파일을 확인한 뒤, sqlite_master 또는 sqlite_schema로 테이블 존재 여부를 확인해야 합니다. 그 결과에 따라 경로 문제인지, 초기화 누락인지, 테이블명·스키마 참조 문제인지 나누어 조치하면 됩니다.
1. 예외 문구보다 연결된 파일을 먼저 확인합니다
sqlite3.connect("data/app.db")처럼 상대 경로를 넘기면 경로는 현재 작업 폴더를 기준으로 해석됩니다. 지정한 파일이 없을 때 SQLite가 새 데이터베이스 파일을 만들 수 있으므로, 수동 실행에서는 정상인데 예약 실행에서만 오류가 난다면 실행 위치가 달라졌는지부터 의심할 만합니다.
다음처럼 연결 직후 파일 목록을 출력해 보십시오.
import sqlite3
db_path = "data/app.db"
with sqlite3.connect(db_path) as con:
print(con.execute("PRAGMA database_list").fetchall())
PRAGMA database_list는 현재 연결에 붙어 있는 데이터베이스와 파일명을 반환합니다. 출력된 경로가 예상한 파일과 다르면 테이블을 새로 만드는 것보다 먼저 경로를 고쳐야 합니다. 특히 상대 경로를 절대 경로로 바꾸는 과정에서 파일 위치가 달라진 것은 아닌지, 예약 실행 프로세스의 작업 폴더를 로그에 남기는 것이 좋습니다.
반대로 경로가 예상한 파일이라면 그때부터 스키마를 확인합니다. 이 순서를 지키면 엉뚱한 빈 DB에 테이블을 생성해 원래 문제를 가리는 일을 피할 수 있습니다.
2. 현재 연결에 테이블이 실제로 있는지 조회합니다
SQLite의 스키마 테이블에는 테이블·인덱스·뷰·트리거 같은 객체 정보가 저장됩니다. sqlite_master는 sqlite_schema와 호환되는 이름이므로, 간단한 진단에는 다음 조회를 사용할 수 있습니다.
with sqlite3.connect(db_path) as con:
tables = con.execute(
"""
SELECT name, type
FROM sqlite_master
WHERE type IN ('table', 'view')
ORDER BY name
"""
).fetchall()
for name, object_type in tables:
print(object_type, name)
여기서 기대한 테이블이 목록에 없다면 SELECT 문법을 고치는 문제가 아닙니다. 다음 세 가지를 구분해 보십시오.
- 목록이 비어 있고 파일도 예상과 다르다: 잘못된 경로로 새 DB에 연결했을 가능성이 큽니다.
- 파일은 예상한 것이지만 목록에 테이블이 없다: 테이블 생성 또는 초기화 단계가 실행되지 않았을 수 있습니다.
- 비슷한 이름의 테이블은 있다: 코드의 테이블명, 대소문자·철자, 또는 스키마 지정이 맞는지 확인해야 합니다.
SQLite 버전과 진단 목적에 따라 PRAGMA table_list로 테이블·뷰 목록과 소속 스키마를 확인할 수도 있습니다.
with sqlite3.connect(db_path) as con:
for row in con.execute("PRAGMA table_list"):
print(row)
이 조회는 이름만 맞춰 보는 데서 그치지 않고 main, temp 등 어느 스키마에 객체가 있는지 살피는 데 도움이 됩니다.
3. 초기화 코드가 실행됐는지 확인합니다
경로와 테이블명이 모두 맞는데도 목록에 테이블이 없다면, 조회 코드보다 앞서 실행되어야 할 스키마 초기화 단계를 확인합니다. 예를 들어 새 환경에서 CREATE TABLE을 수행하는 함수가 호출되는지, 배포·예약 작업의 시작 순서가 초기화 이후 조회로 되어 있는지 로그로 구분해야 합니다.
CREATE_SQL = """
CREATE TABLE IF NOT EXISTS jobs (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
)
"""
with sqlite3.connect(db_path) as con:
con.execute(CREATE_SQL)
con.commit()
con.execute("SELECT id, name FROM jobs").fetchall()
위 코드는 예시 구조일 뿐, 현재 프로젝트의 테이블 설계나 마이그레이션 절차를 대신하지 않습니다. 이미 운영 중인 DB라면 테이블을 무조건 새로 만들거나 파일을 삭제하기보다, 해당 환경에서 준비된 초기화·마이그레이션 명령을 먼저 확인해야 합니다. 예상하지 못한 DB 파일이라면 데이터를 덮어쓰지 말고 작업을 중단해 파일 경로와 배포 설정을 확인하는 편이 안전합니다.
4. 테이블명과 스키마 범위를 확인합니다
SQLite 객체는 main, temp 또는 ATTACH로 연결한 데이터베이스에 속할 수 있습니다. 스키마명을 생략한 객체 참조는 SQLite의 이름 해석 규칙에 따라 검색되므로, 같은 이름의 객체가 여러 스키마에 있을 때는 의도한 범위를 명시하는 것이 진단에 유리합니다.
with sqlite3.connect(db_path) as con:
con.execute("ATTACH DATABASE ? AS archive", ("data/archive.db",))
print(con.execute(
"SELECT name FROM main.sqlite_master WHERE type = 'table'"
).fetchall())
print(con.execute(
"SELECT name FROM archive.sqlite_master WHERE type = 'table'"
).fetchall())
main.jobs와 archive.jobs는 서로 다른 스키마의 객체입니다. 따라서 테이블이 archive에만 있는데 main.jobs를 조회하면 no such table이 발생할 수 있습니다. 임시 테이블을 사용했다면 연결이 새로 만들어진 뒤에도 남아 있을 것이라고 기대하지 않았는지도 함께 확인하십시오.
5. 진단 결과에 따라 다음 조치를 선택합니다
운영 관점에서는 예외를 없애는 것보다 잘못된 DB에 쓰지 않는 것이 먼저입니다. 다음 순서로 판단하면 됩니다.
PRAGMA database_list의 파일이 예상과 다르면 실행 위치·상대 경로·환경 설정을 수정합니다.- 파일이 맞지만 테이블이 없으면 초기화 또는 마이그레이션 단계가 해당 실행 경로에서 수행되는지 확인합니다.
- 테이블은 있지만 이름이나 스키마가 다르면 SQL의 객체명과
main·temp·attached 스키마 범위를 고칩니다. - 파일과 스키마가 모두 예상과 다르면 테이블을 임의로 생성하거나 DB를 삭제하지 말고 실행을 중단한 뒤 배포 설정을 확인합니다.
이 오류는 database is locked와도 구분해야 합니다. no such table은 현재 연결에서 객체를 찾지 못한 상황을 먼저 보여 주고, 잠금 문제는 별도의 동시 접근·트랜잭션 진단이 필요한 주제입니다. 문제의 종류를 섞지 않고 파일, 스키마, 초기화 순서부터 확인하면 수정 범위를 좁힐 수 있습니다.
출처
- Python
sqlite3공식 문서 — 상대 경로 연결, 파일 생성,sqlite_master조회 - SQLite 공식
PRAGMA문서 —database_list,table_list - SQLite 공식 Schema Table 문서 —
sqlite_schema와sqlite_master - SQLite 공식 Database Object Name Resolution 문서 —
main,temp, attached 스키마와 객체명 해석