4. Table 생성

1. 목표
더보기
- 데이터베이스와 테이블의 차이를 구분할 수 있다.
- MySQL 클라이언트에서 USE, CREATE TABLE, SHOW TABLES, DESCRIBE 기본 명령을 사용할 수 있다.
- users 테이블 구조를 설계한다.
id, username, password 컬럼과 타입 의미를 이해한다. - PySide6 애플리케이션에서 버튼 클릭으로 users 테이블을 생성하는 코드를 작성하고,
MySQL 수업에서 사용한 모델링과 비교하여 학습한다. - QFile, QTextStream으로 테이블 생성 로그를 남겨 보고, MySQL 클라이언트로 테이블이 생성되었는지 확인한다.
- 이후 단계인 데이터 INSERT, SELECT에서 이 users 테이블을 재사용할 수 있는 기반을 만든다.
2. 전체 로직
더보기
1단계: 연결 테스트
2단계: 데이터베이스 생성
3단계: users 테이블 생성
import sys
from PySide6.QtWidgets import (
QApplication,
QWidget,
QLabel,
QLineEdit,
QPushButton,
QVBoxLayout,
QFormLayout,
QMessageBox,
QGroupBox,
)
from PySide6.QtCore import QFile, QIODevice, QTextStream
import mysql.connector as mc
class MySqlDemoWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("PySide6 MySQL 연동 기초 데모")
self.resize(520, 420)
self.host_edit = QLineEdit()
self.user_edit = QLineEdit()
self.password_edit = QLineEdit()
self.password_edit.setEchoMode(QLineEdit.Password)
self.db_edit = QLineEdit()
self.host_edit.setText("localhost")
self.user_edit.setText("root")
conn_form = QFormLayout()
conn_form.addRow("호스트", self.host_edit)
conn_form.addRow("사용자", self.user_edit)
conn_form.addRow("비밀번호", self.password_edit)
conn_form.addRow("데이터베이스 이름", self.db_edit)
conn_group = QGroupBox("1·2단계 연결 설정 및 데이터베이스 생성")
conn_group.setLayout(conn_form)
self.btn_connect = QPushButton("연결 테스트")
self.btn_create_db = QPushButton("데이터베이스 생성 (users)")
table_info_label = QLabel(
"이 단계에서 생성할 테이블\n"
"테이블 이름: users\n"
"컬럼: id(INT, 자동 증가, 기본키), username(VARCHAR(150)), password(VARCHAR(150))"
)
table_info_label.setWordWrap(True)
self.btn_create_table = QPushButton("users 테이블 생성")
table_layout = QVBoxLayout()
table_layout.addWidget(table_info_label)
table_layout.addWidget(self.btn_create_table)
table_group = QGroupBox("3단계 데이터베이스 선택 후 users 테이블 만들기")
table_group.setLayout(table_layout)
self.result_label = QLabel("결과 메시지가 여기에 표시됩니다.")
main_layout = QVBoxLayout(self)
main_layout.addWidget(conn_group)
main_layout.addWidget(self.btn_connect)
main_layout.addWidget(self.btn_create_db)
main_layout.addWidget(table_group)
main_layout.addWidget(self.result_label)
self.btn_connect.clicked.connect(self.connect_to_database)
self.btn_create_db.clicked.connect(self.create_database)
self.btn_create_table.clicked.connect(self.create_users_table)
def connect_to_database(self):
host = self.host_edit.text().strip()
user = self.user_edit.text().strip()
password = self.password_edit.text()
db_name = self.db_edit.text().strip()
if not host or not user:
QMessageBox.warning(self, "입력 오류", "호스트와 사용자 이름은 반드시 입력해야 합니다.")
return
try:
if db_name:
conn = mc.connect(
host=host,
user=user,
password=password,
database=db_name,
)
else:
conn = mc.connect(
host=host,
user=user,
password=password,
)
if conn.is_connected():
if db_name:
msg = f"MySQL 서버에 연결되었습니다.\n사용 중인 데이터베이스: {db_name}"
else:
msg = "MySQL 서버에 연결되었습니다.\n데이터베이스 이름은 지정되지 않았습니다."
self.result_label.setText(msg)
QMessageBox.information(self, "연결 성공", msg)
else:
self.result_label.setText("MySQL 서버에 연결하지 못했습니다.")
QMessageBox.warning(self, "연결 실패", "MySQL 서버에 연결하지 못했습니다.")
except mc.Error as e:
self.result_label.setText("연결 중 오류가 발생했습니다.")
QMessageBox.critical(
self,
"연결 오류",
f"MySQL 연결에 실패했습니다.\n오류 내용: {e}",
)
self.write_log_with_qt(f"연결 실패, 오류: {e}")
finally:
try:
if conn.is_connected():
conn.close()
except Exception:
pass
def create_database(self):
host = self.host_edit.text().strip()
user = self.user_edit.text().strip()
password = self.password_edit.text()
db_name = self.db_edit.text().strip()
if not host or not user or not db_name:
QMessageBox.warning(self, "입력 오류", "호스트, 사용자, 데이터베이스 이름을 모두 입력해야 합니다.")
return
try:
conn = mc.connect(
host=host,
user=user,
password=password,
)
cursor = conn.cursor()
cursor.execute(f"CREATE DATABASE {db_name}")
conn.commit()
msg = f"{db_name} 데이터베이스가 생성되었습니다."
self.result_label.setText(msg)
QMessageBox.information(self, "생성 완료", msg)
self.write_log_with_qt(f"데이터베이스 생성: {db_name}")
except mc.Error as e:
self.result_label.setText("데이터베이스 생성에 실패했습니다.")
QMessageBox.critical(
self,
"생성 오류",
f"데이터베이스 생성에 실패했습니다.\n오류 내용: {e}",
)
self.write_log_with_qt(f"데이터베이스 생성 실패: {db_name}, 오류: {e}")
finally:
try:
if conn.is_connected():
conn.close()
except Exception:
pass
def create_users_table(self):
host = self.host_edit.text().strip()
user = self.user_edit.text().strip()
password = self.password_edit.text()
db_name = self.db_edit.text().strip()
if not host or not user or not db_name:
QMessageBox.warning(self, "입력 오류", "먼저 데이터베이스 이름까지 포함한 연결 정보를 모두 입력해야 합니다.")
return
create_table_sql = """
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(150) NOT NULL,
password VARCHAR(150) NOT NULL
)
"""
try:
conn = mc.connect(
host=host,
user=user,
password=password,
database=db_name,
)
cursor = conn.cursor()
cursor.execute(create_table_sql)
conn.commit()
msg = f"{db_name} 데이터베이스에 users 테이블이 생성되었습니다."
self.result_label.setText(msg)
QMessageBox.information(self, "테이블 생성 완료", msg)
self.write_log_with_qt(f"테이블 생성: {db_name}.users")
except mc.Error as e:
self.result_label.setText("테이블 생성 중 오류가 발생했습니다.")
QMessageBox.critical(
self,
"테이블 생성 오류",
f"users 테이블 생성에 실패했습니다.\n오류 내용: {e}",
)
self.write_log_with_qt(f"테이블 생성 실패: {db_name}.users, 오류: {e}")
finally:
try:
if conn.is_connected():
conn.close()
except Exception:
pass
def write_log_with_qt(self, message):
file = QFile("db_steps_log.txt")
if not file.open(QIODevice.Append | QIODevice.Text):
return
stream = QTextStream(file)
stream << message << "\n"
file.close()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MySqlDemoWindow()
window.show()
sys.exit(app.exec())
# main.py
import sys
from PySide6.QtWidgets import QApplication
from mainwindow import DbConnectWindow
if __name__ == "__main__":
app = QApplication(sys.argv)
w = DbConnectWindow()
w.show()
sys.exit(app.exec())
3. 필요한 import + 주석 설명
더보기
from PySide6.QtCore import (
QFile, # 파일을 열고 닫는 등 입출력을 담당하는 Qt 파일 클래스이다.
QIODevice, # 파일 열기 모드(읽기, 쓰기, 추가 등)를 지정하기 위한 기반 클래스이다.
QTextStream, # 텍스트를 파일에 쓰고 읽기 위한 스트림 클래스이다.
)
로그를 남기기 위해 Qt의 QFile, QTextStream를 가져왔다.
4. GUI 구현부 소스코드와 주석
더보기
class MySqlDemoWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
# 윈도우 제목과 크기를 설정한다.
self.setWindowTitle("PySide6 MySQL 연동 기초 데모")
self.resize(520, 420)
# 이전 단계에서 사용한 MySQL 접속 정보 입력 필드들이다.
self.host_edit = QLineEdit()
self.user_edit = QLineEdit()
self.password_edit = QLineEdit()
self.password_edit.setEchoMode(QLineEdit.Password) # 비밀번호 입력값을 숨김 모드로 표시한다.
self.db_edit = QLineEdit()
# 학습 편의를 위해 기본값을 미리 채워 둔다.
self.host_edit.setText("localhost")
self.user_edit.setText("root")
# 접속 정보를 한 줄씩 라벨과 함께 배치하는 폼 레이아웃을 만든다.
conn_form = QFormLayout()
conn_form.addRow("호스트", self.host_edit)
conn_form.addRow("사용자", self.user_edit)
conn_form.addRow("비밀번호", self.password_edit)
conn_form.addRow("데이터베이스 이름", self.db_edit)
# 1단계, 2단계 관련 입력 필드를 묶는 그룹 박스이다.
conn_group = QGroupBox("1·2단계 연결 설정 및 데이터베이스 생성")
conn_group.setLayout(conn_form)
# 1단계에서 구현한 연결 테스트 버튼이다.
self.btn_connect = QPushButton("연결 테스트")
# 2단계에서 구현한 데이터베이스 생성 버튼이다.
self.btn_create_db = QPushButton("데이터베이스 생성 (users)")
# 3단계에서 만들 테이블 구조를 눈으로 확인하기 위한 테이블 속성 안내다.
table_info_label = QLabel(
"이 단계에서 생성할 테이블\n"
"테이블 이름: users\n"
"컬럼: id(INT, 자동 증가, 기본키), username(VARCHAR(150)), password(VARCHAR(150))"
)
table_info_label.setWordWrap(True) # 긴 텍스트가 줄바꿈되도록 설정한다.
# users 테이블을 실제로 생성할 버튼이다.
self.btn_create_table = QPushButton("users 테이블 생성")
# 안내 라벨과 버튼을 세로로 배치하는 레이아웃이다.
table_layout = QVBoxLayout()
table_layout.addWidget(table_info_label)
table_layout.addWidget(self.btn_create_table)
# 3단계 영역을 묶는 그룹 박스이다.
table_group = QGroupBox("3단계 데이터베이스 선택 후 users 테이블 만들기")
table_group.setLayout(table_layout)
# 전체 동작 결과를 간단히 표시할 라벨이다.
self.result_label = QLabel("결과 메시지가 여기에 표시됩니다.")
# 메인 레이아웃을 세로 방향으로 구성한다.
main_layout = QVBoxLayout(self)
main_layout.addWidget(conn_group) # 접속 정보 그룹
main_layout.addWidget(self.btn_connect) # 연결 테스트 버튼
main_layout.addWidget(self.btn_create_db) # 데이터베이스 생성 버튼
main_layout.addWidget(table_group) # 테이블 생성 그룹
main_layout.addWidget(self.result_label) # 결과 표시 라벨
# 시그널 연결은 다음 단계에서 설명한다.
self.btn_connect.clicked.connect(self.connect_to_database)
self.btn_create_db.clicked.connect(self.create_database)
self.btn_create_table.clicked.connect(self.create_users_table)
- 접속 정보 입력 UI는 1·2단계와 동일하게 유지한다.
- 3단계용 QGroupBox를 추가하고, 그 안에
테이블 구조 안내 라벨 + 테이블 생성 버튼을 배치한다. - 일반적이지 않지만,
이번 단계 목표가 users 테이블 생성임을 직관적으로 이해할 수 있도록 구현다.
5. 시그널과 슬롯 연결 부분
더보기
# users 테이블 생성 버튼 클릭 시, CREATE TABLE을 실행하는 함수와 연결한다.
self.btn_create_table.clicked.connect(self.create_users_table)
동일한 패턴
6. <Table 생성> 주요 구조
더보기
6.1 <Table 생성> 핵심 요약
# 1. 연결
conn = mc.connect(서버_및_DB_접속_정보)
# 2. 확인
if conn.is_connected():
성공_처리()
# 3. SQL 실행
cursor = conn.cursor()
cursor.execute(CREATE_TABLE_SQL)
conn.commit()
# 4. 종료
conn.close()
6.2 <Table 생성> 흐름
import mysql.connector as mc
def users_table_create_flow():
# 1. DB 서버 및 데이터베이스 접속 정보 준비
host = "localhost"
user = "root"
password = "password"
database = "test_db"
# 2. users 테이블 생성을 위한 SQL 준비
create_table_sql = """
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(150) NOT NULL,
password VARCHAR(150) NOT NULL
)
"""
# 3. 지정된 데이터베이스에 연결
conn = mc.connect(
host=host,
user=user,
password=password,
database=database
)
# 4. 서버와의 연결 상태 확인
if conn.is_connected():
print("DB 연결 성공")
# 5. SQL 실행을 위한 커서 생성
cursor = conn.cursor()
# 6. CREATE TABLE SQL 실행
cursor.execute(create_table_sql)
# 7. 테이블 생성은 DB 구조 변경이므로 커밋 필요
conn.commit()
# 8. 모든 DB 작업이 끝난 후 연결 종료
conn.close()
# users 테이블 생성 흐름 실행
users_table_create_flow()
- DB 접속 정보 준비
- CREATE TABLE SQL 작성
- 데이터베이스까지 포함하여 연결
- 연결 상태 확인
- 커서 생성
- CREATE TABLE 실행
- commit으로 변경 사항 반영
- 연결 종료
7. 기능 구현 소스코드
더보기
7.1 데이터베이스 선택 후 users 테이블 생성 함수
def create_users_table(self):
# 1단계: 접속 정보 읽기
host = self.host_edit.text().strip()
user = self.user_edit.text().strip()
password = self.password_edit.text()
db_name = self.db_edit.text().strip()
# 데이터베이스 이름까지 지정돼 있어야 테이블을 만들 수 있다.
if not host or not user or not db_name:
QMessageBox.warning(self, "입력 오류", "먼저 데이터베이스 이름까지 포함한 연결 정보를 모두 입력해야 합니다.")
return
# 2단계: 생성할 테이블 구조를 정의하는 SQL을 문자열로 준비한다.
# 이 SQL이 바로 3.3에서 말한 CREATE TABLE users 직접 작성해 보기의 예시이다.
create_table_sql = """
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(150) NOT NULL,
password VARCHAR(150) NOT NULL
)
"""
try:
# 3단계: 지정된 데이터베이스에 연결한다.
# mysql.connector에서는 database 인자에 db_name을 넘기는 것이
# USE db_name 명령과 같은 효과를 낸다고 이해하면 된다.
conn = mc.connect(
host=host,
user=user,
password=password,
database=db_name,
)
cursor = conn.cursor()
# 4단계: CREATE TABLE 문을 실행한다.
cursor.execute(create_table_sql)
conn.commit()
# 5단계: 성공 메시지 출력
msg = f"{db_name} 데이터베이스에 users 테이블이 생성되었습니다."
self.result_label.setText(msg)
QMessageBox.information(self, "테이블 생성 완료", msg)
# 6단계: Qt 기반 파일 입출력으로 로그 기록
self.write_log_with_qt(f"테이블 생성: {db_name}.users")
except mc.Error as e:
# 이미 같은 이름의 테이블이 있는 경우 등에서 예외가 발생한다.
self.result_label.setText("테이블 생성 중 오류가 발생했습니다.")
QMessageBox.critical(
self,
"테이블 생성 오류",
f"users 테이블 생성에 실패했습니다.\n오류 내용: {e}",
)
self.write_log_with_qt(f"테이블 생성 실패: {db_name}.users, 오류: {e}")
finally:
# 7단계: 연결 자원 정리
try:
if conn.is_connected():
conn.close()
except Exception:
pass
- 3.1 MySQL 클라이언트에서 생성된 DB 선택하기
코드에서는 mc.connect(database=db_name)으로 구현된다.
MySQL 클라이언트에서는 USE db_name과 동일한 의미를 갖는다. - 3.2 사용자 테이블 구조 설계하기
create_table_sql 문자열 안에 id, username, password 컬럼과 타입을 정의했다.
7.2 동작 로그 기록 함수
def write_log_with_qt(self, message):
# QFile을 사용해 db_steps_log.txt 파일을 연다.
# Append 모드와 Text 모드를 함께 사용하여, 기존 내용 뒤에 텍스트를 추가한다.
file = QFile("db_steps_log.txt")
if not file.open(QIODevice.Append | QIODevice.Text):
# 파일을 열 수 없는 경우에는 조용히 반환한다.
return
# QTextStream을 사용해 파일에 문자열을 기록한다.
stream = QTextStream(file)
stream << message << "\n"
# 작업이 끝났으면 파일을 닫는다.
file.close()
- 파이썬 open 대신 Qt의 QFile, QTextStream을 사용했다.
- 데이터베이스 생성, 테이블 생성, 연결 실패 등 중요한 단계마다
이 함수를 호출해 어떤 작업이 수행되었는지 한 줄씩 기록한다. - 일반적으로 이와 같이 모든 동작의 로그가 기록된다.
8. 실행
더보기
(1) 데이터베이스 생성
- 호스트: localhost
- 사용자: root
- 비밀번호: 본인 환경 비밀번호
- 데이터베이스 이름: pyqtdb
- 데이터베이스 생성 버튼 클릭
- 생성 완료 메시지 확인
- db_steps_log.txt에 기록 확인
(2) 테이블 생성
- 데이터베이스 이름이 pyqtdb로 설정돼 있는 상태에서
- users 테이블 생성 버튼 클릭
- pyqtdb 안에 users 테이블이 생성되었다는 메시지가 표시된다.
- db_steps_log.txt에 테이블 생성 로그가 기록된다.
(3) MySQL 클라이언트에서 확인
USE pyqtdb; -- 3.1 데이터베이스 선택
SHOW TABLES; -- 3.4 테이블 목록 확인
DESCRIBE users; -- 3.4 users 테이블 구조 확인
9.학습 주요 포인트
더보기
- 데이터베이스와 테이블의 관계를 명확히 이해해야 한다.
- MySQL 클라이언트에서의 USE dbname 명령은
PySide6 코드에서는 mc.connect에 database=db_name을 넘기는 것과 같은 의미이다. - users 테이블 구조 설계는 이후 모든 단계의 기반이 된다.
id 컬럼은 AUTO_INCREMENT PRIMARY KEY로 두어 자동 번호를 사용하고,
username과 password는 NOT NULL로 설정해 비어 있는 값이 들어가지 않도록 한다. - CREATE TABLE, SHOW TABLES, DESCRIBE 명령을
코드 안의 문자열로만 보지 말고,
실제 MySQL 클라이언트에서 직접 실행해 보는 경험이 중요하다. - PySide6 애플리케이션 안에서
데이터베이스 생성 → 테이블 생성까지 버튼 단위로 단계적으로 실행할 수 있게 구현하면서
전체 흐름을 눈으로 따라간다. - QFile과 QTextStream을 활용한 로그 기록을 실습한다.
- 이 단계까지 완료되면,
다음 단계에서 INSERT 쿼리를 안전하게 실습할 수 있다.
단계별 완성 파일