파이썬 sqlite3 테이블 이름 검색 질문

조회수 887회

db를 다를줄몰라서 json 형식으로 만들었다가 답변해주시는 분들이 db를 만들라고 추천해주셔서

db를 공부하면서 소스를 짜고 있는데요 일단 디비 저장하는것까지는 성공했습니다

크롤링하면서 데이터를 얻은 비제이 1명당 "db_아이디" 이름을 가진 테이블을 1개씩 만들어주고 있습니다 (현재 테이블 3천개정도)

테이블은 [고유번호,id,닉네임,날짜,제목,길이,링크,조회수] 이렇게 이루어져있구요

from telegram import InlineKeyboardButton, InlineKeyboardMarkup, parsemode
from telegram.ext import Updater, MessageHandler, Filters, CommandHandler, CallbackQueryHandler  
import time
from functools import partial
import logging
import sqlite3
import sys

formatter = logging.Formatter('[%(levelname)s] %(asctime)s > %(message)s')
file_handler = logging.FileHandler('./telegram_bot_db.log',encoding='utf-8')
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)

logger = logging.getLogger("logger")
logger.setLevel(logging.DEBUG)
logger.addHandler(file_handler)
logger.addHandler(stream_handler)



my_token = '#봇 토큰'

sys.setrecursionlimit(10000)    #오류나서 검색해보고 추가함
conn = sqlite3.connect('af.db')    # db연결
cur = conn.cursor()

print('start bot')


def search(bot, update):    # 봇에 bjid를 입력하면

    bjid = update.message.text    # bjid =봇에 검색한 bjid
    l=[]
    bjid = bjid.lower() #첫글자가 자동 대문자 되는 사람들이 있어서 소문자로 변환
    chat_id = update.message.chat_id    # chat_id =봇을 사용한 사람의 텔레그램id

    dbid = 'db_'+ bjid    # bj아이디가 숫자로 시작하는경우 에러가 발생해서 테이블생성시 아이디앞에 db_붙임

    cur.execute('select name from sqlite_master where type="table" and name="{}"'.format(dbid))
    # 테이블 이름이 dbid 인것 선택

    aa = cur.fetchall()    # 검색한 bjid 이름을 가진 테이블이 있으면 테이블 이름있는 리스트 주고 없으면 [] 리턴 
    # bjid당 1개의 테이블만 있어서 fetchall,one 아무거나써도 하나만 반환

    print(aa)  # 여기서 부터가 문제  print한 값이 아무것도 안나옴

    # if aa != '':           #print 결과가 안나오니 아래는 당연히 안되서 주석처리
    #     update.message.reply_text('테이블 있음')            
    # else:
    #     update.message.reply_text('테이블 없음')



def get_message(bot, update) :
    update.message.reply_text(time.time())
    #print(update.message)
    update.message.reply_text(update.message.text)


def help_command(bot, update) :
    update.message.reply_text("문의")

def start(bot, update):
    update.message.reply_text("시작")
updater = Updater(my_token)

message_handler = MessageHandler(Filters.text, search)
updater.dispatcher.add_handler(message_handler)

updater.dispatcher.add_handler(CommandHandler('start', start))
help_handler = CommandHandler('help', help_command)
updater.dispatcher.add_handler(help_handler)
updater.dispatcher.add_handler(CommandHandler('search', partial(search, offset=0)))

updater.start_polling(timeout=3, clean=True)

updater.idle()

아래 부분의 소스를 def search(bot, update): 함수안이 아닌 밖에서 실행하면 aa 값이 table이 있으면 테이블 이름을 print하고 없으면 [] 이 print 됩니다

    dbid = 'db_'+ bjid 
    cur.execute('select name from sqlite_master where type="table" and name="{}"'.format(dbid))

    aa = cur.fetchall() 

    print(aa) 

텔레그램 봇에 bjid를 입력하면 db에 검색한후 그이름을 가진 테이블이 있으면 그 값들을 주려고하는데요 (비제이의 데이터를 얻었을때 테이블을 생성하므로 테이블 조회해서 있으면 해당 비제이의 데이터가 있음)

함수 안에서 작동을안하다가 함수밖에서 잘 작동을하니;; 어디가 잘못되었는지를 모르겠습니다

  • bj당 테이블을 생성하는 것 부터 문제가 있습니다. 기본적인 bj 정보가 있는 테이블이 있고 각 bj에 대한 상세정보가 있는 테이블, bj가 진행하는 방송에 대한 상세정보가 있는 테이블등으로 나누고 1-N 관계를 만들어야 합니다. 즉 마스터-디테일 구조가 되어야 합니다. 관계형 데이터베이스도 큰 분야입니다. 일단 기본적인 개론서라도 한권 읽고 프로그래밍을 했으면 합니다. 정영훈 2020.2.15 07:28
  • 감사합니다 디비구조를 바꿧습니다 처음이다보니 제가 생각자체를 잘못했더군요 nyw123 2020.2.16 05:48

1 답변

  • 좋아요

    1

    싫어요
    채택 취소하기

    일단 원인만 알려드리자면 참조 오류인데요.

    def search(bot, update):
        bjid = update.message.text
        l=[]
        bjid = bjid.lower()
        chat_id = update.message.chat_id
        dbid = 'db_'+ bjid
        cur.execute(어쩌구 저쩌구)
    

    이 소스를 잘 보시면, search()라는 메소드 안에서, cur는 제7행에 갑자기 툭 튀어나옵니다. 이게 무엇을 가리키는지 파이썬이 알 도리가 없어서 에러가 나는 것이지요. "함수" 밖에서야 보시다시피 cur이 있으니 그걸 참조할 수 있는 거구요.


    하지만 아무리 읽어봐도 이건 진짜 문제가 아닙니다. 윗분 댓글에도 나와 있지만 bj 한명한명에게 테이블이 있다는 것부터가 심각하게 문제입니다. 대부분의 경우 테이블의 '이름'을 '검색'해야 할 일은 없어요. 지금 현재의 그 설계는, 덜 긴밀한 관계를 가진 방대한 데이터를 축적하며 앞으로도 질문자님이 만들고 싶은 것을 끊임없이 가로막고 귀찮게 방해할 겁니다.

    전형적으로 다음과 같이 합니다.

    CREATE TABLE bj(
      bjid    INTEGER PRIMARY KEY, 
      bjname  TEXT,
      /* 더 있겠지만 생략 */
    );
    CREATE TABLE bjclip(
      clipid     INTEGER,
      cliptitle   TEXT, 
      clipbj INTEGER,
      /* 더 있겠지만 중간 생략하고 */
      FOREIGN KEY(clipbj) REFERENCES bj(bjid) /* 중요 */
    );
    

    테이블 자료 구조가 저렇게만 되어 있다면, 거기서부터는 얘기가 훨씬 쉽습니다.

    /* 사용자가 BJ 이름을 입력하면 그 BJ가 찍은 영상들을 그 BJ 이름과 함께 보여주기 */
    SELECT *
    FROM bjclip
    JOIN bj ON bj.bjid = bjclip.clipbj
    WHERE bj.bjname LIKE '%사용자입력%';
    
    /* 사용자가 영상 제목으로 검색했을 때 그 제목의 영상을 올린 BJ 들을 알려주기 */
    SELECT *
    FROM bj
    WHERE bjid IN (
        SELECT clipbj
        FROM bjclip
        WHERE cliptitle LIKE '%사용자입력%'
    );
    

    위 쿼리들은 항상 '결과셋'이 됩니다. 그 결과셋의 크기는 0일 수도 있고 1 이상일 수도 있습니다. 파이썬은 이 결과셋을 그냥 for 돌면서 뿌려주면 됩니다. "앗 님이 검색하신 이름을 가진 BJ는 0명인데요?"를 알려주기 위해 커서를 획득하고 재귀횟수 한계를 지정하고 익셉션 처리를 붙이는 난리부르스를 추실 필요가 없는 겁니다.

    지금이라도 데이터 구조 설계를 변경하시기를 강력히 권고 드립니다. 만들어져 있는 테이블들을 모두 하나의 테이블로 합치시고, BJ 정보만 모은 테이블을 따로 만들어서 서로 관계를 지어 주세요. 그게 빠른 길입니다.

    • 감사합니다 제가 디비를 배운적없이 포털사이트과 유튜브에서 보고 처음 만들다보니 생각을 이상하게했네요 디비를 저장하는 소스에서 재귀횟수 한계 오류가 떠서 해결방법을 찾으려 검색해보니 한계를 늘려주라고해서 했는데 혹시 다른 해결방법을 알수있을까요? 오류가 발생하는 디비저장하는 소스는 새글로 썼습니다 nyw123 2020.2.16 05:52

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)