Skip to content

Latest commit

 

History

History
340 lines (279 loc) · 11.9 KB

220313.md

File metadata and controls

340 lines (279 loc) · 11.9 KB

파이썬 SQLite

테이블 생성

# DB 생성 & Auto Commit(Rollback)
conn = sqlite3.connect('./python_sqlite/resource/database.db', isolation_level=None)

# Cursor
c = conn.cursor()
print('Cursor Type : ', type(c))

# 테이블 생성(Data Type : TEXT, NUMERIC INTEGER REAL BLOB)
c.execute("CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, username text, email text, phone text, website text, regdate text)")

실행하면 database.db라는 데이터베이스 파일이 생성되고, (id, username, email, phone, website, regdate)를 컬럼명으로 하는 테이블이 생성된다.

데이터 삽입

# 데이터 삽입
# ?는 format과 같이 매치해서 넣어주는 역할
# 마지막에 nowDatetime 다음의 콤마가 없으면 에러가 발생한다.
c.execute("INSERT INTO users VALUES(1, 'Kim', 'Email@naver.com', '010-0000-0000', 'Kim.com', ?)", (nowDatetime, ))

c.execute("INSERT INTO users(id, username, email, phone, website, regdate) VALUES (?,?,?,?,?,?)", (2, 'Park', 'Park@naver.com', '010-1111-1111', 'Park.com', nowDatetime))

# Many 삽입(튜플, 리스트)
usertuple = (
    (3, 'Lee', 'Lee@naver.com', '010-2222-2222', 'Lee.com', nowDatetime),
    (4, 'Cho', 'Cho@daum.net', '010-3333-3333', 'Cho.com', nowDatetime),
    (5, 'Yoo', 'Yoo@google.com', '010-4444-4444', 'Yoo.com', nowDatetime)
)

c.executemany("INSERT INTO users(id, username, email, phone, website, regdate) VALUES (?,?,?,?,?,?)", usertuple)

data

위의 그림처럼 데이터가 추가된다.

컬럼 순서대로 데이터를 추가할 때는 첫 번째처럼 해도 되지만 보통은 두 번째 방법을 사용하고, 여러 데이터를 한 번에 넣을 때에는 executemany를 사용한다.

데이터 삭제

# 테이블 데이터 삭제
conn.execute("DELETE FROM users")
# 삭제한 행 수 표시
print("users db deleted : ", conn.execute("DELETE FROM users").rowcount)

DELETE FROM users를 하면 테이블 내의 데이터 전체가 지워진다.
아래의 print처럼 rowcount까지 쓰면 몇 행이 지워졌는지 알 수 있어 유용하다.

커밋, 롤백, 접속 해제

# 커밋 : isolation_level = None일 경우 자동 반영(오토 커밋)
conn.commit()

# 롤백
conn.rollback()

# 접속 해제
conn.close()

위에서 DB를 생성할 때 옵션으로 준 isolation_level이 오토 커밋을 하게 해주는 옵션이다.
오토 커밋이 아니라면 commit()을 써야 DB에 적용이 된다.

데이터 조회

# DB 파일 조회(없으면 새로 생성)
conn = sqlite3.connect('python_sqlite/resource/database.db', isolation_level=None)

# 커서 바인딩
c = conn.cursor()

# 데이터 조회(전체)
c.execute("SELECT * FROM users")

# 커서 위치가 변경
# 1개 로우 선택
print('One -> \n', c.fetchone())

# 지정 로우 선택
print('Three - > \n', c.fetchmany(size=3))

# 전체 로우 선택
print('All -> \n', c.fetchall())

One ->
(1, 'Kim', 'Email@naver.com', '010-0000-0000', 'Kim.com', '2022-03-13 16:44:51')
Three - >
[(2, 'Park', 'Park@naver.com', '010-1111-1111', 'Park.com', '2022-03-13 16:44:51'), (3, 'Lee', 'Lee@naver.com', '010-2222-2222', 'Lee.com', '2022-03-13 16:44:51'), (4, 'Cho', 'Cho@daum.net', '010-3333-3333', 'Cho.com', '2022-03-13 16:44:51')]
All ->
[(5, 'Yoo', 'Yoo@google.com', '010-4444-4444', 'Yoo.com', '2022-03-13 16:44:51')]

커서가 iterator처럼 위치를 기억한다.
마지막에 커서가 이미 4개의 데이터를 읽어 왔기 때문에 전체를 가져와도 1개의 데이터 밖에 가져오지 못한다.

조회(순회)

# 순회1
rows = c.fetchall()
for row in rows:
    print('retrieve1 > ', row)

retrieve1 > (1, 'Kim', 'Email@naver.com', '010-0000-0000', 'Kim.com', '2022-03-13 16:44:51')
retrieve1 > (2, 'Park', 'Park@naver.com', '010-1111-1111', 'Park.com', '2022-03-13 16:44:51')
retrieve1 > (3, 'Lee', 'Lee@naver.com', '010-2222-2222', 'Lee.com', '2022-03-13 16:44:51')
retrieve1 > (4, 'Cho', 'Cho@daum.net', '010-3333-3333', 'Cho.com', '2022-03-13 16:44:51')
retrieve1 > (5, 'Yoo', 'Yoo@google.com', '010-4444-4444', 'Yoo.com', '2022-03-13 16:44:51')

# 순회2
for row in c.fetchall():
    print('retrieve2 > ', row)

retrieve2 > (1, 'Kim', 'Email@naver.com', '010-0000-0000', 'Kim.com', '2022-03-13 16:44:51')
retrieve2 > (2, 'Park', 'Park@naver.com', '010-1111-1111', 'Park.com', '2022-03-13 16:44:51')
retrieve2 > (3, 'Lee', 'Lee@naver.com', '010-2222-2222', 'Lee.com', '2022-03-13 16:44:51')
retrieve2 > (4, 'Cho', 'Cho@daum.net', '010-3333-3333', 'Cho.com', '2022-03-13 16:44:51')
retrieve2 > (5, 'Yoo', 'Yoo@google.com', '010-4444-4444', 'Yoo.com', '2022-03-13 16:44:51')

순회1과 순회2는 같은 문장으로 변수를 사용하냐 마냐의 차이이다.

# 순회3
for row in c.execute("SELECT * FROM users ORDER BY id desc"):
    print('retrieve3 > ', row)

retrieve3 > (5, 'Yoo', 'Yoo@google.com', '010-4444-4444', 'Yoo.com', '2022-03-13 16:44:51')
retrieve3 > (4, 'Cho', 'Cho@daum.net', '010-3333-3333', 'Cho.com', '2022-03-13 16:44:51')
retrieve3 > (3, 'Lee', 'Lee@naver.com', '010-2222-2222', 'Lee.com', '2022-03-13 16:44:51')
retrieve3 > (2, 'Park', 'Park@naver.com', '010-1111-1111', 'Park.com', '2022-03-13 16:44:51')
retrieve3 > (1, 'Kim', 'Email@naver.com', '010-0000-0000', 'Kim.com', '2022-03-13 16:44:51')

순회3은 조회하고 내림차순으로 정렬한 것이다.

조건 조회

# WHERE Retrieve1
param1 = (3,)
c.execute('SELECT * FROM users WHERE id=?', param1)
print('param1', c.fetchone())
print('param1', c.fetchall()) # 데이터 없음

param1 (3, 'Lee', 'Lee@naver.com', '010-2222-2222', 'Lee.com', '2022-03-13 16:44:51')
param1 []

id가 3인 데이터를 가져온 것이다.

# WHERE Retrieve2
param2 = 4
c.execute('SELECT * FROM users WHERE id="%s"' % param2)
print('param2', c.fetchone())
print('param2', c.fetchall()) # 데이터 없음

param2 (4, 'Cho', 'Cho@daum.net', '010-3333-3333', 'Cho.com', '2022-03-13 16:44:51')
param2 []

%s를 사용하여 id가 4인 데이터를 가져온 것이다.

# WHERE Retrieve3
c.execute('SELECT * FROM users WHERE id=:Id', {"Id": 5})
print('param3', c.fetchone())
print('param3', c.fetchall()) # 데이터 없음

param3 (5, 'Yoo', 'Yoo@google.com', '010-4444-4444', 'Yoo.com', '2022-03-13 16:44:51')
param3 []

딕셔너리를 사용해서 키 값으로 조회해서 value를 가져와 사용한다.

# WHERE Retrieve4
param4 = (3, 5)
c.execute("SELECT * FROM users WHERE id IN(?,?)", param4)
print('param4', c.fetchall())

param4 [(3, 'Lee', 'Lee@naver.com', '010-2222-2222', 'Lee.com', '2022-03-13 16:44:51'), (5, 'Yoo', 'Yoo@google.com', '010-4444-4444', 'Yoo.com', '2022-03-13 16:44:51')]

id가 3이나 5인 데이터를 가져온 것이다.

# WHERE Retrieve5
c.execute("SELECT * FROM users WHERE id IN('%d', '%d')" % (3, 4))
print('param5', c.fetchall())

param5 [(3, 'Lee', 'Lee@naver.com', '010-2222-2222', 'Lee.com', '2022-03-13 16:44:51'), (4, 'Cho', 'Cho@daum.net', '010-3333-3333', 'Cho.com', '2022-03-13 16:44:51')]

WHERE Retrieve4와 다르게 IN에 '?' 대신 '%d'를 사용한 것이다.

# WHERE Retrieve6
c.execute("SELECT * FROM users WHERE id=:id1 OR id=:id2", {"id1": 2, "id2": 5})
print('param6', c.fetchall())

param6 [(2, 'Park', 'Park@naver.com', '010-1111-1111', 'Park.com', '2022-03-13 16:44:51'), (5, 'Yoo', 'Yoo@google.com', '010-4444-4444', 'Yoo.com', '2022-03-13 16:44:51')]

딕셔너리와 OR 조건을 사용한 것이다.

Dump 생성

# Dump 출력
with conn:
    with open('python_sqlite/resource/dump.sql', 'w') as f:
        for line in conn.iterdump():
            f.write('%s\n' % line)
        print('Dump Print Complete')
BEGIN TRANSACTION;
CREATE TABLE users(id INTEGER PRIMARY KEY, username text, email text, phone text, website text, regdate text);
INSERT INTO "users" VALUES(1,'Kim','Email@naver.com','010-0000-0000','Kim.com','2022-03-13 16:44:51');
INSERT INTO "users" VALUES(2,'Park','Park@naver.com','010-1111-1111','Park.com','2022-03-13 16:44:51');
INSERT INTO "users" VALUES(3,'Lee','Lee@naver.com','010-2222-2222','Lee.com','2022-03-13 16:44:51');
INSERT INTO "users" VALUES(4,'Cho','Cho@daum.net','010-3333-3333','Cho.com','2022-03-13 16:44:51');
INSERT INTO "users" VALUES(5,'Yoo','Yoo@google.com','010-4444-4444','Yoo.com','2022-03-13 16:44:51');
COMMIT;

이와 같은 sql 파일을 생성한다.
이렇게 해두면 다른 환경에서 똑같은 DB를 생성할 수 있다.

데이터 수정

# 데이터 수정1
# 기본키가 있다면 기본키 사용하는 것이 좋다.
c.execute('UPDATE users SET username = ? WHERE id = ?', ('niceman', 2))

# 데이터 수정2
c.execute('UPDATE users SET username = :name WHERE id = :id', {'name': 'goodman', 'id': 5})

# 데이터 수정3
c.execute('UPDATE users SET username = "%s" WHERE id = "%s"' % ('badboy', 3))

# 중간 데이터 확인1
for user in c.execute("SELECT * FROM users"):
    print(user)

(1, 'Kim', 'Email@naver.com', '010-0000-0000', 'Kim.com', '2022-03-13 16:44:51')
(2, 'niceman', 'Park@naver.com', '010-1111-1111', 'Park.com', '2022-03-13 16:44:51')
(3, 'badboy', 'Lee@naver.com', '010-2222-2222', 'Lee.com', '2022-03-13 16:44:51')
(4, 'Cho', 'Cho@daum.net', '010-3333-3333', 'Cho.com', '2022-03-13 16:44:51')
(5, 'goodman', 'Yoo@google.com', '010-4444-4444', 'Yoo.com', '2022-03-13 16:44:51')

데이터 삭제(조건)

# Row Delete1
c.execute("DELETE FROM users WHERE id = ?", (2, ))

# Row Delete2
c.execute("DELETE FROM users WHERE id = :id", {"id":5})

# Row Delete3
c.execute("DELETE FROM users WHERE id = '%s'" % 4)

# 중간 데이터 확인 2
for user in c.execute("SELECT * FROM users"):
    print(user)

# 테이블 전체 데이터 삭제
print("users db deleted : ", conn.execute("DELETE FROM users").rowcount, " rows")

조건에 맞는 데이터를 삭제하는 구문들이다.

파이썬 클래스 복습

선언

# 선언
class UserInfo:
    def __init__(self, name):
        self.name = name
        print("Initiallize")
    
    def user_info_p(self):
        print("Name : ", self.name)

user1 = UserInfo("Kim")
user1.user_info_p()
user2 = UserInfo("Park")
user2.user_info_p()

print(user1.__dict__)
print(user2.__dict__)

Initiallize
Name : Kim
Initiallize
Name : Park
{'name': 'Kim'}
{'name': 'Park'}

네임스페이스는 인스턴스가 사용하는 자기자신의 저장공간을 말하고, .__dict__로 접근할 수 있다.

self

class SelfTest:
    # 클래스 메소드
    def function1():
        print('function1 called')

    # 인스턴스 메소드
    def function2(self):
        print('function2 called')

self_test = SelfTest()
self_test.function1() # 에러, function1은 self 인자가 없어서 인스턴스에서 호출할 수 없다.
SelfTest.function1()  # 성공

SelfTest.function2()          # 에러
SelfTest.function2(self_test) # 성공

클래스와 인스턴스를 구분짓는 것이라고 생각하면 될 것 같다.

클래스 변수, 인스턴스 변수

class WareHouse:
    # 클래스 변수
    stock_num = 0
    def __init__(self, name):
        self.name = name
        WareHouse.stock_num += 1
    
    def __del__(self):
        WareHouse.stock_num -= 1

user1 = WareHouse('Kim')
user2 = WareHouse('Park')
user3 = WareHouse('Lee')

# 클래스 변수는 나오지 않는다.
print(user1.__dict__)
print(user2.__dict__)
print(user3.__dict__)

# 클래스의 네임 스페이스에서 확인할 수 있다.
# 클래스 변수는 공유된다.
print(WareHouse.__dict__)

# 자신의 네임스페이스에 없으면 클래스의 네임스페이스에 가서 찾는다.
print(user1.stock_num)

클래스 변수는 직접 사용 가능하고, 객체보다 먼저 생성된다.
인스턴스 변수는 객체마다 별도로 존재하고 인스턴스 생성 후 사용할 수 있다.