[python] MSSQL 서버와 pymysql 모듈 이용 한글 문제 Develop Tip

pymysql 을 연결하여 한글을 사용하려고 하는데,
처음에 한글이 제대로 나오지 않아 시간을 조금 들였습니다.

우선 MSSQL 이라는 클래스를 만들어 아래와 같이
open을 시키는 utf8 로 열어,

    # ==========================================================================
    def open(self):
        self.logger.debug('MSSQL.open: trying to open')
        self.conn = pymssql.connect(
            host=self.host,
            user=self.user,
            password=self.passwd,
            port=int(self.port),
            database=self.db,
            charset='utf8',
        )

MySQL 처럼 python으로 한글을 사용하려 합니다. 

select 에서 '홍길동' 결과를 가져오는데 '???' 이라고 나옵니다.
python 에서 encoding, decoding 문제인가 수정을 조금 해 보는데
답이 안 나옵니다.

결국은 다음과 같이 MSSQL 의 문제였음이 ..

우선 다음과 같이 CREATE TABLE을 합니다.

CREATE TABLE foo (
  id BIGINT IDENTITY(1,1) NOT NULL,
  name NVARCHAR(30) NOT NULL,
  age INT NOT NULL,
  PRIMARY KEY (id)
);

NVARCHAR 로 해 주어야 합니다.
MySQL에서 AUTO_INCREMENT 대신 MSSQL에서는 IDENTITY(1,1) 이라고 합니다.
(1부터 시작해서 1씩 증가하는 것입니다)

또 입력할 때 다음과 같이 해 주어야 합니다.

INSERT INTO foo (name, age)
values
('nobody me', 100),
(N'홍길동', 200)

N'홍길동' 과 같이 N 을 붙여주어야 합니다.

그러면 select 에서는 아무런 제한 없이 한글이 잘 나옵니다.

다음은 간단히 만들어 이용할 수 있는 MSSQL 클래스 입니다.


################################################################################
class MSSQL(object):
    # ==========================================================================
    def __init__(self, dbhost, dbport, dbuser, dbpass, dbname,
                 logger):
        self.host, self.port, self.user, self.passwd, self.db \
            = dbhost, dbport, dbuser, dbpass, dbname
        self.logger = logger
        # for internal
        self.is_opened = False
        self.conn = None

    # ==========================================================================
    def open(self):
        self.logger.debug('MSSQL.open: trying to open')
        self.conn = pymssql.connect(
            host=self.host,
            user=self.user,
            password=self.passwd,
            port=int(self.port),
            database=self.db,
            charset='utf8',
        )
        self.is_opened = True
        self.logger.debug('MSSQL.open: opened!')
        return self.is_opened

    # ==========================================================================
    def close(self):
        self.logger.debug('MSSQL.open: trying to close')
        if self.conn is not None:
            self.conn.close()
            self.conn = None
            self.is_opened = False
            self.logger.debug('MSSQL.close: closed!')

    # ==========================================================================
    def sql_execute(self, sql):
        self.logger.debug('MSSQL.sql_execute: sql=<%s>' % sql)
        with self.conn.cursor() as cursor:
            cursor.execute(sql)
            print('affected_row_count\n%s' % cursor.rowcount)
            self.logger.debug('affected_row_count=%s' % cursor.rowcount)
        self.conn.commit()

    # ==========================================================================
    def sql_select(self, sql):
        self.logger.debug('MSSQL.sql_select: sql=<%s>' % sql)
        with self.conn.cursor() as cursor:
            cursor.execute(sql)
            # num_fields = len(cursor.description)
            field_names = [x[0] for x in cursor.description]
            # noinspection PyUnusedLocal
            field_types = [x[1] for x in cursor.description]
            print('%s' % ','.join(field_names))
            cwr = csv.writer(sys.stdout)
            rows = cursor.fetchall()
            for row in rows:
                cwr.writerow(row)

    # ==========================================================================
    def sql_execute_with_csv(self, sql, csv_file, header_lines=0):
        self.logger.debug('MSSQL.sql_execute_with_csv: sql=<%s>, csv_file=%s'
                          % (sql, csv_file))
        if not os.path.exists(csv_file):
            raise IOError('CSV file "%s" not found' % csv_file)
        with open(csv_file, 'r', encoding='utf-8') as ifp:
            cooked = csv.reader(ifp)
            with self.conn.cursor() as cursor:
                cnt = 0
                for i, record in enumerate(cooked):
                    if i < header_lines:
                        continue
                    esql = sql.format(*record)
                    cursor.execute(esql)
                    cnt += 1
                self.conn.commit()
                print('affected_row_count\n%s' % cnt)
                self.logger.debug('affected_row_count=%s' % cnt)


어느 분께는 도움이 되셨기를..




핑백

덧글

댓글 입력 영역

구글애드텍스트