最近在工作中碰到一個問題,需要快速的將一些歷史數據導入到數據庫中(CSV格式),經過考慮決定使用python來實現。
主要需要解決以下兩個問題:
1、CSV格式的解釋
2、數據的批量寫入(性能考慮)
一、CSV格式的解釋
CSV格式其實就是文本文件,使用open函數打開文件,然後循環訪問就可以。
先將文件內容讀取到內存中。
def read(self):
"""讀取文件的內容,將文件內容作爲列表返回。"""
lines = []
with open(self.file_name,
'rt', -1,
encoding="GB2312")
as file:
lines = file.readlines()
count = len(lines)
if count > 0:
del lines[0]
#去掉第一行表頭內容。
return lines
二、批量更新數據庫內容
數據批量寫入數據庫有三種形式
1、方法1:將每一行要寫的數據轉爲insert的SQL語句,然後將這些語句拼接成一個長長的字符串,程序一次性的把長長的sQL串傳送到服務器上。
def execute(self,
sql):
"""批量處理SQL語句。"""
cursor = self.conn.cursor()
#cursor.execute("begin transaction") #這個語句不能要,會導致數據寫不到數據庫中。
cursor.execute(sql)
self.conn.commit()
#提交數據到服務器上。
2、方法2:將每一行要寫的數據轉爲insert的SQL語句,將這些SQL語句一句一句的送給服務器運行,但是不提交事務,到最後才一次性提交
def execute_batch(self,
sqls):
"""批量執行SQL語句
sqls => sql語句列表,每一個sql語句都是以分好結尾。
"""
cursor = self.conn.cursor()
for s in sqls:
cursor.execute(s)
self.conn.commit()
3、方法3:使用python庫的executemany方法
def execute_many(self,
sqlvalue):
"""參數化執行多個語句"""
cursor = self.conn.cursor()
cursor.executemany(sqlvalue[0], sqlvalue[1])
self.conn.commit()
三、例子
1、文件內容讀取
class TickFile():
"""tick數據文件"""
def __init__(self,
fileName):
self.file_name = fileName
def read(self):
"""讀取文件的內容,將文件內容作爲列表返回。"""
lines = []
with open(self.file_name,
'rt', -1,
encoding="GB2312")
as file:
lines = file.readlines()
count = len(lines)
if count > 0:
del lines[0]
#去掉第一行表頭內容。
return lines
2、數據庫訪問包裝類:
class SqlServerProxy():
"""SQL server數據庫訪問代理類。"""
def __init__(self,
server, user,
password, database):
self.server = server
self.user = user
self.password = password
self.database = database
self.conn = self.__create_connection()
def close(self):
self.conn.close()
def __create_connection(self):
conn = pymssql.connect(server=self.server,
user=self.user,
password=self.password,
database=self.database)
return conn
def execute(self,
sql):
"""批量處理SQL語句。"""
cursor = self.conn.cursor()
#cursor.execute("begin transaction") #這個語句不能要,會導致數據寫不到數據庫中。
cursor.execute(sql)
self.conn.commit()
#提交數據到服務器上。
def execute_many(self,
sqlvalue):
"""參數化執行多個語句"""
cursor = self.conn.cursor()
cursor.executemany(sqlvalue[0], sqlvalue[1])
self.conn.commit()
def execute_batch(self,
sqls):
"""批量執行SQL語句
sqls => sql語句列表,每一個sql語句都是以分好結尾。
"""
cursor = self.conn.cursor()
for s in sqls:
cursor.execute(s)
self.conn.commit()
3、解釋數據寫入類:
class SqlWriter():
"""SQL數據寫入類"""
def __init__(self,
sqlproxy):
if not
isinstance(sqlproxy, SqlServerProxy):
raise ReferenceError("參數sqlproxy不是SqlServerProxy類型。")
self.sql_proxy = sqlproxy
def write_many(self,
product, symbol,
lines):
sqlvalue = self.__lines_to_sqlmany(product, symbol, lines)
self.sql_proxy.execute_many(sqlvalue)
def write(self,
product, symbol,
lines):
"""將數據寫入到數據庫中。"""
sqls = []
for line in lines:
sql = self.__line_to_sql(product, symbol, line)
sqls.append(sql)
print(sql)
self.sql_proxy.execute_batch(sqls)
#將數據保存到數據庫中去。
def __lines_to_sqlmany(self,
product, symbol,
lines):
sql = "INSERT INTO Tick_" + product +
"(InfoSeq, Symbol, TradeTime, LastPrice, Volumne, AskPrice1, AskVolume1,BidPrice1,BidVolume1,OpenPosition) VALUES (\
%d ,%s ,%s ,%d ,%d ,%d ,%d ,%d ,%d ,0);"
values = []
for line in lines:
arr = line.split(",")
timestring = "%s %s.%s" % (arr[0], arr[1], arr[2])
sqldata = (0, symbol, timestring, arr[3], arr[8], arr[4], arr[5], arr[5],
arr[7])
values.append(sqldata)
return sql, values
def __line_to_sql(self,
product, symbol,
line):
"""將line的數據轉換爲SQL語句。"""
arr = line.split(",")
timestring = "%s %s.%s"%(arr[0], arr[1], arr[2])
print("timestring = %s"%(timestring))
sql = "INSERT INTO Tick_%s(InfoSeq, Symbol, TradeTime, LastPrice, Volumne, AskPrice1, AskVolume1,BidPrice1,BidVolume1,OpenPosition) VALUES (\
%d\
,'%s'\
,'%s'\
,%s\
,%s\
,%s\
,%s\
,%s\
,%s\
,0\
);"%(product,
0, symbol, timestring, arr[3], arr[8], arr[4], arr[5], arr[5], arr[7])
return sql
備註:需要引用的python包
import pymssql
import os
import pymssql