레이블이 sqlite3인 게시물을 표시합니다. 모든 게시물 표시
레이블이 sqlite3인 게시물을 표시합니다. 모든 게시물 표시

2023년 7월 31일 월요일

sql limit 를 이용해 page 단위로 보여주기

 SQL 에서 limit 는 SELECT 와 함께 아래와 같이 사용되어 집니다.

SELECT column FROM table ORDER BY somethingelse LIMIT 25, 50

select 되는 개수가 많을 수도 있습니다. 이때 page 단위로 얻을 수 있는 방법이 LIMIT를 이용하게 됩니다.

LIMIT [페이지 번호], [페이지당 결과 값의 갯수]

LIMIT 의 첫번째 값은 몇번째 페이지를 나타낼지를 뒤에 값은 페이지의 갯수를 의미합니다.

만약 인자가 하나라면 결과 값의 갯수가 제한되는 형태가 됩니다.

LIMIT [결과 값의 갯수]


예를 들어 살펴 보겠습니다.

아래 예제는 page_size와 page_number를 입력받아서 해당 페이지에 있는 dict_key를 list형태로 전달하는 함수입니다.

# 페이지 단위로 데이터를 얻는다.
# asc : True 이면 오래된 데이터 순으로 나온다.
def get_page_keys(self, page_number, page_size, asc=False):
if not self.is_connect:
self.connect()
cursor = self.con.cursor()
asc_str = "DESC"
page_from = page_size * page_number
if asc:
asc_str = "ASC"
try:
cursor.execute(f"SELECT dict_key FROM '{self.table_name}' ORDER BY timestamp {asc_str} LIMIT {page_from}, {page_size}")
except sqlite3.OperationalError as ex:
if str(ex).startswith("no such table:"):
cursor.close()
return None, None
rows = cursor.fetchall()
cursor.close()
if rows is None:
return None, None
ret = []
# print("debug:",rows)
for row in rows:
ret.append(row[0])
return ret


전체 예제는 아니지만 아래와 같이 실행시

sd.save_dict({"a": 1}, dupkey_process="forced")
time.sleep(0.1) # 시간 정보를 빼면 입력한 시간이 같아지는 경우가 발생하여 순서가 섞일 수 있음
sd.save_dict({"b": 2}, dupkey_process="forced")
time.sleep(0.1)
sd.save_dict({"c": 3}, dupkey_process="forced")
time.sleep(0.1)
sd.save_dict({"d": 4}, dupkey_process="forced")
time.sleep(0.1)
sd.save_dict({"e": 5}, dupkey_process="forced")
time.sleep(0.1)
sd.save_dict({"f": 6}, dupkey_process="forced")
time.sleep(0.1)
sd.save_dict({"g": 7}, dupkey_process="forced")

print("get_page_keys 0", sd.get_page_keys(0, 3))
print("get_page_keys 1", sd.get_page_keys(1, 3))
print("get_page_keys 2", sd.get_page_keys(2, 3))
print("get_page_keys 3", sd.get_page_keys(3, 3))

print("get_page_keys 0 asc", sd.get_page_keys(0, 3, asc=True))
print("get_page_keys 1 asc", sd.get_page_keys(1, 3, asc=True))
print("get_page_keys 2 asc", sd.get_page_keys(2, 3, asc=True))
print("get_page_keys 3 asc", sd.get_page_keys(3, 3, asc=True))

다음의 결과를 얻을 수 있습니다.

get_page_keys 0 ['g', 'f', 'e']
get_page_keys 1 ['d', 'c', 'b']
get_page_keys 2 ['a']
get_page_keys 3 []
get_page_keys 0 asc ['a', 'b', 'c']
get_page_keys 1 asc ['d', 'e', 'f']
get_page_keys 2 asc ['g']
get_page_keys 3 asc []

위 예제에서는 page 크기를 3으로 설정했으므로 list에 3개씩 결과가 돌아옴을 알 수 있습니다.

전체예제는 github 소스를 참고하시기 바랍니다.

sourcecode/python/example/_46_sqlite/dict_sqlite.py at main · donarts/sourcecode · GitHub


2022년 10월 8일 토요일

sqlite3 에서 unrecognized token 오류 해결

 

sqlite 에서 insert into 할때 오류가 나는 경우가 있습니다.

debugging을 해보면 예상치 못한 곳에서 발생합니다.


아래 코드를 보시기 바랍니다.

json_dump = json.dumps(value)
print(f"{key}//{json_dump}")
try:
cur.execute(f"INSERT INTO '{self.table_name}' VALUES ('{nowtime}','{key}','{json_dump}')")

json_dump 는 str 형태이고 이것을 VALUES ('{json_dump}') 로 표현할때 해당 str내부에 작은 따옴표(') 가 존재한다면 unrecognized token 오류가 발생합니다.


해결책

https://www.sqlite.org/lang_expr.html#hexint 여기에 설명이 되어 있는데

A string constant is formed by enclosing the string in single quotes ('). A single quote within the string can be encoded by putting two single quotes in a row - as in Pascal.

문자열 상수는 문자열을 작은따옴표(')로 묶어서 형성됩니다. 문자열 내의 작은 따옴표는 Pascal에서와 같이 두 개의 작은 따옴표를 연속으로 넣어 인코딩할 수 있습니다. 


즉 ' => '' 로 변환하는 코드를 추가로 넣어야 합니다.


개선된 코드

json_dump = json.dumps(value)
json_dump = str(json_dump)
json_dump = json_dump.replace("'", "''")
print(f"{key}//{json_dump}")
try:
cur.execute(f"INSERT INTO '{self.table_name}' VALUES ('{nowtime}','{key}','{json_dump}')")


2022년 9월 17일 토요일

Sqlite3, python에서 DB사용, dict type db 저장 예제 2탄

앞에서 sqlite를 이용해서 python dict type을 저장하는 것을 만들어 봤는데...

https://swlock.blogspot.com/2022/07/sqlite3-python-db-dict-type-db.html

실제 프로젝트에선 몇 가지 기능이 더 필요해서 업그레이드 하였습니다.

추가로 필요했던 기능은 전체 레코드 갯수 와 오래된 레코드 삭제하는 기능입니다.

단순 db에 저장만 하는 것이 아닌 cache 형태로 관리하려면 일정한 갯수를 유지하기 위한 방법이 필요했습니다.

그래서 table에 timestamp정보를 넣고 오래된 항목을 삭제하는 기능을 넣었습니다.


아래 내용을 보기전에 기존 구현된 내용을 위 링크를 이용하여 먼저 읽기를 바랍니다.


table에 신규 timestamp 컬럼 추가

이건 간단합니다. timestamp REAL 타입을 추가했습니다.

def create_table(self):
cur = self.con.cursor()
cur.execute(f"CREATE TABLE {self.table_name} (timestamp REAL,"
f"dict_key text primary key,json_dump text)")
self.con.commit()


저장시 timestamp 추가

이것도 values 항목에 첫번째로 넣어주면 되고, datetime.now()의 timestamp() 메소드를 이용하였습니다.

def save_dict(self, dict_data, dupkey_process="error"):
nowtime = datetime.datetime.now().timestamp()
cur = self.con.cursor()
for key in dict_data:
value = dict_data[key]
json_dump = json.dumps(value)
print(f"{key}//{json_dump}")
try:
cur.execute(f"INSERT INTO '{self.table_name}' VALUES ('{nowtime}','{key}','{json_dump}')")

bug가 발견되어 변환 코드를 추가해야 합니다. 아래 링크 참고

https://swlock.blogspot.com/2022/10/sqlite3-unrecognized-token.html


timestamp 읽기

data를 읽어올때 timestamp도 같이 읽어 오도록 하였습니다.

sql select 명령에 timestamp를 붙였습니다.

cursor.execute(f"SELECT json_dump,timestamp FROM '{self.table_name}' WHERE dict_key='{find_key}'")


전체 레코드 갯수

sql의 COUNT를 이용하였습니다. 레코드의 전체 카운트를 리턴합니다.

# 전체 카운트 리턴
def get_count_all(self):
if not self.is_connect:
self.connect()
cursor = self.con.cursor()
result = 0
try:
cursor.execute(f"SELECT COUNT(*) FROM '{self.table_name}'")
result = cursor.fetchone()[0]
except sqlite3.OperationalError as ex:
if str(ex).startswith("no such table:"):
cursor.close()
return -1
cursor.close()
return result


오래된 레코드 가져오기

timestamp가 갱신할 때마다 저장되므로 order by timestamp 를 이용하여 마지막 레코드를 읽어오도록 구현하였습니다. 

# 가장 오래된 레코드 가져오기
# dict, timestamp
def get_old_record_one(self):
if not self.is_connect:
self.connect()
cursor = self.con.cursor()
try:
cursor.execute(f"SELECT * FROM '{self.table_name}' ORDER BY timestamp ASC LIMIT 1")
except sqlite3.OperationalError as ex:
if str(ex).startswith("no such table:"):
cursor.close()
return None, None
row = cursor.fetchone()
print(row)
cursor.close()
if row is None:
return None, None
ret = {row[1]: json.loads(row[2])}
return ret, row[0]


특정 시간 이전 레코드 삭제

구현 방법은 where 조건절에 timestamp정보를 넣어서 레코드를 얻어오고, 해당 레코드에서 키를 이용하여 기존 존재하는 del_key() 메소드로 삭제를 하도록 구현하였습니다.

# 특정 시간 이전 레코드 삭제하기
# -60 : -60 초 이전 레코드 삭제
def del_old_record(self, time_old_sec):
nowtime = datetime.datetime.now().timestamp()
print(nowtime+time_old_sec)
if not self.is_connect:
self.connect()
cursor = self.con.cursor()
try:
cursor.execute(f"SELECT * FROM '{self.table_name}' WHERE timestamp < {nowtime+time_old_sec}")
except sqlite3.OperationalError as ex:
if str(ex).startswith("no such table:"):
cursor.close()
return -1
rows = cursor.fetchall()
#print(rows)
cursor.close()
count = 0
if rows is not None:
for row in rows:
self.del_key(row[1])
count = count + 1
return count


python에서는 dict type을 정말 많이 이용하게 되고, 이것을 쉽게 sqlite를 이용하여 db를 저장하도록 구현한 내용입니다. 


sourcecode/dict_sqlite.py at main · donarts/sourcecode · GitHub



2022년 7월 10일 일요일

Sqlite3, python에서 DB사용, dict type db 저장 예제

SQLite3

SQLite는 별도의 서버 프로세스가 필요 없고 SQL 질의 언어의 비표준 변형을 사용하여 데이터베이스에 액세스할 수 있는 경량 디스크 기반 데이터베이스를 제공하는 라이브러리입니다. Python에서도 쉽게 사용이 가능합니다.

여기 예제에서는 dictinary type을 저장하는 예제로 만들어 보도록 하겠습니다.


설치

pip install pysqlite3 

python 3.8


SQL 기본 문법

SQL의 기본 명령에 대해서는 알고 있어야 합니다. 아래 링크에서 확인이 가능합니다.

https://www.w3schools.com/sql/

들어가기에 앞서 sqlite에서 db는 파일 이름 단위로 생성이 되며, db안에는 table이 여러개 존재할 수 있으며, 하나의 table에는 여러개의 레코드가 존재 가능합니다.

기본적으로 CREATE TABLE(테이블 생성), INSERT INTO(레코드 추가), UPDATE(레코드 업데이트), SELECT(레코드 검색), DELETE FROM (레코드 삭제)정도는 알아야 합니다.


python 에서 SQL 기본 명령 사용하기

최초 db를 connect 해야 합니다.

import sqlite3
con = sqlite3.connect('example.db')

connect되면 connect object가 생성되면 여기에서 cursor() 메소드를 이용하여 아래와 같이 sql command 이용이 가능합니다. 아래 예제에서 cur.execute() 입니다.

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()

db에 변경이 일어나면 마지막에 connect.commit() 메소드를 호출 하도록 합니다. commit전에 rollback이 일어나면 excute했던 동작들이 모두 취소됩니다.


dictionary 저장 하기 예제

dictionary를 저장하는것은 json으로 text형태로 쉽게 저장이 가능하지만 값이 빈번하게 저장이 될때 power fail이 발생하는 경우 손상될 가능성이 높습니다.

저장된 파일의 check sum을 기록한다던지 여러가지 방법이 있겠지만, 가장 간단하게 처리가 가능한 것이 db를 이용하여 처리하는 것이 가장 간단한 방법입니다.


예제코드

import os
import sqlite3
import json

# key must be str type
class sqlite_dict():
    def __init__(self, dbfilename):
        self.dbfilename = dbfilename
        self.table_name = "test"
        self.is_connect = False
        self.con = None

    def drop_db_file(self):
        if os.path.isfile(self.dbfilename):
            os.remove(self.dbfilename)
        self.is_connect = False

    def connect(self):
        self.con = sqlite3.connect(self.dbfilename)
        self.is_connect = True

    def close(self):
        if self.is_connect:
            self.con.close()
            self.is_connect = False
            self.con = None

    def set_table_name(self, table_name):
        self.table_name = table_name

    def create_table(self):
        cur = self.con.cursor()
        cur.execute(f"CREATE TABLE {self.table_name} ( dict_key text primary key, json_dump text)")
        self.con.commit()

    # dict를 하나 또는 여러개를 DB에 저장합니다.
    # dupkey_process
    # "ignore":에러가 안나는 것만 부분 업데이트
    # "forced":기존값 모두 업데이트
    # "error":하나가 에러나면 모두 업데이트 중지함
    # return 0 : 에러없음, -1:에러
    def save_dict(self,dict_data,dupkey_process="error"):
        cur = self.con.cursor()
        for key in dict_data:
            value = dict_data[key]
            json_dump = json.dumps(value)
            print(f"{key}//{json_dump}")
            try:
                cur.execute(f"INSERT INTO '{self.table_name}' VALUES ('{key}','{json_dump}')")
            except sqlite3.OperationalError as ex:
                if str(ex).startswith("no such table:"):
                    self.create_table()
                    cur.execute(f"INSERT INTO '{self.table_name}' VALUES ('{key}','{json_dump}')")
            except sqlite3.IntegrityError as ex:
                if str(ex).startswith("UNIQUE constraint failed:"):
                    if dupkey_process == "ignore":
                        pass
                    if dupkey_process == "error":
                        self.con.rollback()
                        return -1
                    if dupkey_process == "forced":
                        cur.execute(f"UPDATE '{self.table_name}' SET json_dump='{json_dump}' WHERE dict_key='{key}'")
        self.con.commit()
        return 0

    def get_data(self, find_key):
        if not self.is_connect:
            self.connect()
        cursor = self.con.cursor()
        try:
            cursor.execute(f"SELECT json_dump FROM '{self.table_name}' WHERE dict_key='{find_key}'")
        except sqlite3.OperationalError as ex:
            if str(ex).startswith("no such table:"):
                cursor.close()
                return None
        row = cursor.fetchone()
        cursor.close()
        if row is None:
            return None
        dict_data = json.loads(row[0])
        return dict_data

    def get_all_data(self):
        if not self.is_connect:
            self.connect()
        cursor = self.con.cursor()
        try:
            cursor.execute(f"SELECT * FROM '{self.table_name}'")
        except sqlite3.OperationalError as ex:
            if str(ex).startswith("no such table:"):
                cursor.close()
                return None
        rows = cursor.fetchall()
        cursor.close()
        if rows is None:
            return None
        ret = {}
        for row in rows:
            ret[row[0]] = json.loads(row[1])
        return ret

    def del_key(self, find_key):
        if not self.is_connect:
            self.connect()
        cursor = self.con.cursor()
        try:
            cursor.execute(f"DELETE FROM '{self.table_name}' WHERE dict_key='{find_key}'")
        except sqlite3.OperationalError as ex:
            if str(ex).startswith("no such table:"):
                cursor.close()
                return False
        cursor.close()
        self.con.commit()
        return True

if __name__ == "__main__":
    sd = sqlite_dict("test.db")
    sd.connect()
    sd.set_table_name("test_table")
    print("** add item")
    sd.save_dict({"abc" : [1, 2, 3, 4, 5,"abc"]})
    print("** add items 2")
    sd.save_dict({"abc" : [1, 2, "한글"], "kbz" : 2} , dupkey_process="forced")
    print("** alldata")
    print(sd.get_all_data())
    print("** read item")
    print(sd.get_data("abc"))
    print(sd.get_data("kbz"))
    print(sd.get_data("kcc"))
    print("** del item")
    print(sd.del_key("kca"))
    print(sd.del_key("kbz"))
    print("** alldata")
    print(sd.get_all_data())
    sd.close()


실행화면

** add item
abc//[1, 2, 3, 4, 5, "abc"]
** add items 2
abc//[1, 2, "\ud55c\uae00"]
kbz//2
** alldata
{'abc': [1, 2, '한글'], 'kbz': 2}
** read item
[1, 2, '한글']
2
None
** del item
True
True
** alldata
{'abc': [1, 2, '한글']}


bug가 발견되어 변환 코드를 추가해야 합니다. 아래 링크 참고

https://swlock.blogspot.com/2022/10/sqlite3-unrecognized-token.html





2019년 2월 19일 화요일

Python 에서 sqlite3 와 DataFrame 사용



Python을 이용한 sqlite3 사용 예제입니다. sqlite는 python을 설치하면 기본으로 설치되어있으며, db를 파일 형태로 저장하기 때문에 backup이나 관리가 쉬운 편입니다. 하지만 속도나 대용량 지원등 여러가지 제약 사항은 있습니다.
구현 하고자 하는 내용은 저장은 sqlite3로 하고 읽는 부분은 pandas dataframe을 이용하였습니다.
아래와 같이 테이블을 만들고 body 부분에 text를 넣는 예제입니다.

예제에서 입력을 원하는 db table 구조
table : maintbl

      date :  body
-----------+------
2019-02-18 : hello
2019-02-19 : nice

응용 해볼 수 있는 곳은 웹에서 자료를 읽어서 db에 읽어서 날짜별로 저장하고 읽을때는 DataFrame 사용하기 위한 용도입니다.

좀 더 단순화 위해서 database class를 제작하였습니다. 기본 idx 가 기본키로 지정되어 있습니다. pandas로 data를 읽는 부분은 다음 코드를 이용합니다. df = pd.read_sql_query("SELECT * FROM %s" % table, self.con)

database.py
import os
import sqlite3
import datetime
import pandas as pd
from pandas import Series, DataFrame

#print(str(sqlite3.version))

class SqliteDb():
    def __init__(self):
        super().__init__()

    def connect(self, name):
        self.con = sqlite3.connect(name)
        self.cursor = self.con.cursor()
        return self.cursor

    def make_table(self, table ):
        self.cursor.execute("CREATE TABLE "+ table + "(idx INTEGER PRIMARY KEY)")

    def exists_table(self, table):
        try :
            self.cursor.execute("SELECT * FROM " + table)
            return True
        except :
            return False

    def exists_table_column(self, table, coulumn) :
        try :
            self.cursor.execute("SELECT %s FROM %s "%(coulumn, table))
            return True
        except :
            return False

    def add_column(self, table, column_name_type) :
        # add column https://www.sqlite.org/datatype3.html
        # add_column(TABLE_NAME,'column_name float')
        sql = "ALTER TABLE %s ADD COLUMN %s" % (table, column_name_type)
        self.cursor.execute(sql)

    def insert_data(self, table, values):
        # column 순서 대로 입력됨
        #insert_data(TABLE_NAME,"'2018-01-01',1000")
        sql = "INSERT INTO %s VALUES(%s)" % (table, values)
        self.cursor.execute(sql)

    def insert_data_with_cols(self, table, cols, values):
        # 원하는 column 에 원하는 값을 넣을때 사용
        #insert_data_with_cols("table_name","column_name1,column_name2","value1,value2")
        sql = "INSERT INTO %s(%s) VALUES(%s)" % (table, cols, values)
        self.cursor.execute(sql)

    def get_value(self, table, cols, condition):
        #value = get_value("table_name","colname","idx=value")
        sql = "SELECT %s FROM %s WHERE %s" % (cols, table, condition)
        cursor = self.cursor.execute(sql)
        row = cursor.fetchone()
        if row==None : return None
        if len(row)==0 : return None
        return row[0]
    
    def update_value(self, table, setvalue, condition):
        #update_value("table_name","colname=value","idx=value")
        sql = "UPDATE %s SET %s WHERE %s" % (table, setvalue, condition)
        self.cursor.execute(sql)

    def get_dataframe(self, table):
        df = pd.read_sql_query("SELECT * FROM %s" % table, self.con)
        return df

    def close(self):
        self.con.commit()
        self.con.close()

컬럼을 추가할때 (db.add_column(PARAM_DB_TABLE_MAIN,"body TEXT")) db의 datatype은 https://www.sqlite.org/datatype3.html 링크를 참고합니다.
maintbl을 생성하는 예제 코드
import database

PARAM_DB_NAME = "dbname.db"
PARAM_DB_TABLE_MAIN = "maintbl"

db = database.SqliteDb()
db.connect(PARAM_DB_NAME)

# Table
if not db.exists_table(PARAM_DB_TABLE_MAIN):
 db.make_table(PARAM_DB_TABLE_MAIN)

# Columns
if not db.exists_table_column(PARAM_DB_TABLE_MAIN,"date"):
 db.add_column(PARAM_DB_TABLE_MAIN,"date TEXT")

if not db.exists_table_column(PARAM_DB_TABLE_MAIN,"body"):
 db.add_column(PARAM_DB_TABLE_MAIN,"body TEXT")

# insert update
idxvalue = db.get_value(PARAM_DB_TABLE_MAIN, "idx", "date='2019-02-18'")
if idxvalue==None:
 db.insert_data_with_cols(PARAM_DB_TABLE_MAIN,"date","'2019-02-18'")
 db.insert_data_with_cols(PARAM_DB_TABLE_MAIN,"body","'hello'")
else:
 db.update_value(PARAM_DB_TABLE_MAIN,"body='hello'","idx=%d"%idxvalue)

# insert update
idxvalue = db.get_value(PARAM_DB_TABLE_MAIN, "idx", "date='2019-02-19'")
if idxvalue==None:
 db.insert_data_with_cols(PARAM_DB_TABLE_MAIN,"date","'2019-02-19'")
 db.insert_data_with_cols(PARAM_DB_TABLE_MAIN,"body","'nice'")
else:
 db.update_value(PARAM_DB_TABLE_MAIN,"body='nice'","idx=%d"%idxvalue)

db.close()

db2 = database.SqliteDb()
db2.connect(PARAM_DB_NAME)
df = db2.get_dataframe(PARAM_DB_TABLE_MAIN)
print(df)

db에서 insert data를 할때 주의할점
insert data를 하면 row가 하나 증가됩니다.
즉, 위 실행 예제로 하면 아래와 같이 나옵니다.

실행예제1)
   idx        date   body
0    1  2019-02-18   None
1    2        None  hello
2    3  2019-02-19   None
3    4        None   nice

다시 동작시키면 아래와 같이 날짜 뒤 body 컬럼이 채워집니다.

실행예제2)
   idx        date   body
0    1  2019-02-18  hello
1    2        None  hello
2    3  2019-02-19   nice
3    4        None   nice

원했던 내용이 아닙니다.
insert를 하게되면 row가 하나 생겨나기 때문에 idx를 얻어서 나머지 컬럼은 update를 하는 방식을 사용하였습니다. 아래 부분이 변경되었습니다.
idxvalue = db.get_value(PARAM_DB_TABLE_MAIN, "idx", "date='2019-02-18'")
if idxvalue==None:
db.insert_data_with_cols(PARAM_DB_TABLE_MAIN,"date","'2019-02-18'")
idxvalue = db.get_value(PARAM_DB_TABLE_MAIN, "idx", "date='2019-02-18'")

db.update_value(PARAM_DB_TABLE_MAIN,"body='hello'","idx=%d"%idxvalue)


변경된 소스
import database

PARAM_DB_NAME = "dbname.db"
PARAM_DB_TABLE_MAIN = "maintbl"

db = database.SqliteDb()
db.connect(PARAM_DB_NAME)

# Table
if not db.exists_table(PARAM_DB_TABLE_MAIN):
 db.make_table(PARAM_DB_TABLE_MAIN)

# Columns
if not db.exists_table_column(PARAM_DB_TABLE_MAIN,"date"):
 db.add_column(PARAM_DB_TABLE_MAIN,"date TEXT")

if not db.exists_table_column(PARAM_DB_TABLE_MAIN,"body"):
 db.add_column(PARAM_DB_TABLE_MAIN,"body TEXT")

# insert update
idxvalue = db.get_value(PARAM_DB_TABLE_MAIN, "idx", "date='2019-02-18'")
if idxvalue==None:
 db.insert_data_with_cols(PARAM_DB_TABLE_MAIN,"date","'2019-02-18'")
 idxvalue = db.get_value(PARAM_DB_TABLE_MAIN, "idx", "date='2019-02-18'")

db.update_value(PARAM_DB_TABLE_MAIN,"body='hello'","idx=%d"%idxvalue)

# insert update
idxvalue = db.get_value(PARAM_DB_TABLE_MAIN, "idx", "date='2019-02-19'")
if idxvalue==None:
 db.insert_data_with_cols(PARAM_DB_TABLE_MAIN,"date","'2019-02-19'")
 idxvalue = db.get_value(PARAM_DB_TABLE_MAIN, "idx", "date='2019-02-19'")

db.update_value(PARAM_DB_TABLE_MAIN,"body='nice'","idx=%d"%idxvalue)

db.close()

db2 = database.SqliteDb()
db2.connect(PARAM_DB_NAME)
df = db2.get_dataframe(PARAM_DB_TABLE_MAIN)
print(df)

최종 실행결과
   idx        date   body
0    1  2019-02-18  hello
1    2  2019-02-19   nice


주의 : clean 테스트를 위해서는 현재 폴더에 있는 dbname.db 삭제해야합니다.