ฉันมีไฟล์ CSV และต้องการนำเข้าไฟล์จำนวนมากไปยังฐานข้อมูล sqlite3 โดยใช้ Python คำสั่งคือ ".import ..... " แต่ดูเหมือนว่าจะไม่สามารถทำงานได้เช่นนี้ ใครช่วยยกตัวอย่างวิธีทำใน sqlite3 ให้หน่อยได้ไหม ฉันใช้ windows ในกรณีนี้ ขอบคุณ
ฉันมีไฟล์ CSV และต้องการนำเข้าไฟล์จำนวนมากไปยังฐานข้อมูล sqlite3 โดยใช้ Python คำสั่งคือ ".import ..... " แต่ดูเหมือนว่าจะไม่สามารถทำงานได้เช่นนี้ ใครช่วยยกตัวอย่างวิธีทำใน sqlite3 ให้หน่อยได้ไหม ฉันใช้ windows ในกรณีนี้ ขอบคุณ
คำตอบ:
import csv, sqlite3
con = sqlite3.connect(":memory:") # change to 'sqlite:///your_filename.db'
cur = con.cursor()
cur.execute("CREATE TABLE t (col1, col2);") # use your column names here
with open('data.csv','r') as fin: # `with` statement available in 2.5+
# csv.DictReader uses first line in file for column headings by default
dr = csv.DictReader(fin) # comma is default delimiter
to_db = [(i['col1'], i['col2']) for i in dr]
cur.executemany("INSERT INTO t (col1, col2) VALUES (?, ?);", to_db)
con.commit()
con.close()
not all arguments converted during string formatting
เรื่อย ๆ เมื่อพยายามใช้วิธีนี้
การสร้างการเชื่อมต่อ sqlite ไปยังไฟล์บนดิสก์ถูกปล่อยให้เป็นแบบฝึกหัดสำหรับผู้อ่าน ...
df = pandas.read_csv(csvfile)
df.to_sql(table_name, conn, if_exists='append', index=False)
df
ดังนั้นฉันจึงย่อตัวอย่างของคุณให้สั้นลงเป็น:pandas.read_csv(csvfile).to_sql(table_name, conn, if_exists='append', index=False)
2 เซ็นต์ของฉัน (ทั่วไปมากขึ้น):
import csv, sqlite3
import logging
def _get_col_datatypes(fin):
dr = csv.DictReader(fin) # comma is default delimiter
fieldTypes = {}
for entry in dr:
feildslLeft = [f for f in dr.fieldnames if f not in fieldTypes.keys()]
if not feildslLeft: break # We're done
for field in feildslLeft:
data = entry[field]
# Need data to decide
if len(data) == 0:
continue
if data.isdigit():
fieldTypes[field] = "INTEGER"
else:
fieldTypes[field] = "TEXT"
# TODO: Currently there's no support for DATE in sqllite
if len(feildslLeft) > 0:
raise Exception("Failed to find all the columns data types - Maybe some are empty?")
return fieldTypes
def escapingGenerator(f):
for line in f:
yield line.encode("ascii", "xmlcharrefreplace").decode("ascii")
def csvToDb(csvFile, outputToFile = False):
# TODO: implement output to file
with open(csvFile,mode='r', encoding="ISO-8859-1") as fin:
dt = _get_col_datatypes(fin)
fin.seek(0)
reader = csv.DictReader(fin)
# Keep the order of the columns name just as in the CSV
fields = reader.fieldnames
cols = []
# Set field and type
for f in fields:
cols.append("%s %s" % (f, dt[f]))
# Generate create table statement:
stmt = "CREATE TABLE ads (%s)" % ",".join(cols)
con = sqlite3.connect(":memory:")
cur = con.cursor()
cur.execute(stmt)
fin.seek(0)
reader = csv.reader(escapingGenerator(fin))
# Generate insert statement:
stmt = "INSERT INTO ads VALUES(%s);" % ','.join('?' * len(cols))
cur.executemany(stmt, reader)
con.commit()
return con
.import
คำสั่งเป็นคุณลักษณะของเครื่องมือบรรทัดคำสั่ง sqlite3 หากต้องการทำใน Python คุณควรโหลดข้อมูลโดยใช้สิ่งอำนวยความสะดวกใด ๆ ที่ Python มีเช่นโมดูล csvและแทรกข้อมูลตามปกติ
ด้วยวิธีนี้คุณยังสามารถควบคุมประเภทที่แทรกแทนที่จะอาศัยพฤติกรรมที่ดูเหมือนไม่มีเอกสารของ sqlite3
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys, csv, sqlite3
def main():
con = sqlite3.connect(sys.argv[1]) # database file input
cur = con.cursor()
cur.executescript("""
DROP TABLE IF EXISTS t;
CREATE TABLE t (COL1 TEXT, COL2 TEXT);
""") # checks to see if table exists and makes a fresh table.
with open(sys.argv[2], "rb") as f: # CSV file input
reader = csv.reader(f, delimiter=',') # no header information with delimiter
for row in reader:
to_db = [unicode(row[0], "utf8"), unicode(row[1], "utf8")] # Appends data from CSV file representing and handling of text
cur.execute("INSERT INTO neto (COL1, COL2) VALUES(?, ?);", to_db)
con.commit()
con.close() # closes connection to database
if __name__=='__main__':
main()
ขอบคุณมากสำหรับคำตอบของ Bernie ! ต้องปรับแต่งเล็กน้อย - นี่คือสิ่งที่ใช้ได้ผลสำหรับฉัน:
import csv, sqlite3
conn = sqlite3.connect("pcfc.sl3")
curs = conn.cursor()
curs.execute("CREATE TABLE PCFC (id INTEGER PRIMARY KEY, type INTEGER, term TEXT, definition TEXT);")
reader = csv.reader(open('PC.txt', 'r'), delimiter='|')
for row in reader:
to_db = [unicode(row[0], "utf8"), unicode(row[1], "utf8"), unicode(row[2], "utf8")]
curs.execute("INSERT INTO PCFC (type, term, definition) VALUES (?, ?, ?);", to_db)
conn.commit()
ไฟล์ข้อความของฉัน (PC.txt) มีลักษณะดังนี้:
1 | Term 1 | Definition 1
2 | Term 2 | Definition 2
3 | Term 3 | Definition 3
คุณคิดถูกที่.import
จะไป แต่นั่นเป็นคำสั่งจากเชลล์ SQLite3.exe คำตอบยอดนิยมสำหรับคำถามนี้เกี่ยวข้องกับ python loops แต่ถ้าไฟล์ของคุณมีขนาดใหญ่ (ของฉันคือ 10 ^ 6 ถึง 10 ^ 7 เร็กคอร์ด) คุณต้องการหลีกเลี่ยงการอ่านทุกอย่างเป็นแพนด้าหรือใช้ความเข้าใจ / ลูปรายการ python แบบเนทีฟ (แม้ว่าฉันจะไม่ได้เวลาเปรียบเทียบ)
สำหรับไฟล์ขนาดใหญ่ฉันเชื่อว่าตัวเลือกที่ดีที่สุดคือการสร้างตารางว่างไว้ล่วงหน้าโดยใช้sqlite3.execute("CREATE TABLE...")
แถบส่วนหัวจากไฟล์ CSV ของคุณจากนั้นใช้subprocess.run()
เพื่อดำเนินการคำสั่งนำเข้าของ sqlite เนื่องจากส่วนสุดท้ายคือฉันเชื่อว่าตรงประเด็นที่สุดฉันจะเริ่มต้นด้วยสิ่งนั้น
subprocess.run()
from pathlib import Path
db_name = Path('my.db').resolve()
csv_file = Path('file.csv').resolve()
result = subprocess.run(['sqlite3',
str(db_name),
'-cmd',
'.mode csv',
'.import '+str(csv_file).replace('\\','\\\\')
+' <table_name>'],
capture_output=True)
คำชี้แจงจากบรรทัดคำสั่งคำสั่งที่คุณกำลังมองหาอยู่
เรียกใช้กระบวนการบรรทัดคำสั่ง อาร์กิวเมนต์ถึงคือลำดับของสตริงที่ตีความเป็นคำสั่งตามด้วยอาร์กิวเมนต์ทั้งหมดsqlite3 my.db -cmd ".mode csv" ".import file.csv table"
subprocess.run()
subprocess.run()
sqlite3 my.db
เปิดฐานข้อมูล -cmd
แฟล็กหลังจากฐานข้อมูลอนุญาตให้คุณส่งคำสั่ง follow on หลายคำสั่งไปยังโปรแกรม sqlite ในเชลล์แต่ละคำสั่งจะต้องอยู่ในเครื่องหมายคำพูด แต่ที่นี่จำเป็นต้องเป็นองค์ประกอบของลำดับของตัวเอง'.mode csv'
ทำในสิ่งที่คุณคาดหวัง'.import '+str(csv_file).replace('\\','\\\\')+' <table_name>'
คือคำสั่งนำเข้า -cmd
เป็นสตริงที่ยกมาคุณจึงต้องเพิ่มแบ็กสแลชเป็นสองเท่าหากคุณมีพา ธ ไดเร็กทอรี windowsไม่ใช่ประเด็นหลักของคำถาม แต่นี่คือสิ่งที่ฉันใช้ อีกครั้งฉันไม่ต้องการอ่านไฟล์ทั้งหมดลงในหน่วยความจำ ณ เวลาใด:
with open(csv, "r") as source:
source.readline()
with open(str(csv)+"_nohead", "w") as target:
shutil.copyfileobj(source, target)
ขึ้นอยู่กับวิธีแก้ปัญหา Guy L (รักมัน) แต่สามารถจัดการช่องที่มีการหลีกเลี่ยงได้
import csv, sqlite3
def _get_col_datatypes(fin):
dr = csv.DictReader(fin) # comma is default delimiter
fieldTypes = {}
for entry in dr:
feildslLeft = [f for f in dr.fieldnames if f not in fieldTypes.keys()]
if not feildslLeft: break # We're done
for field in feildslLeft:
data = entry[field]
# Need data to decide
if len(data) == 0:
continue
if data.isdigit():
fieldTypes[field] = "INTEGER"
else:
fieldTypes[field] = "TEXT"
# TODO: Currently there's no support for DATE in sqllite
if len(feildslLeft) > 0:
raise Exception("Failed to find all the columns data types - Maybe some are empty?")
return fieldTypes
def escapingGenerator(f):
for line in f:
yield line.encode("ascii", "xmlcharrefreplace").decode("ascii")
def csvToDb(csvFile,dbFile,tablename, outputToFile = False):
# TODO: implement output to file
with open(csvFile,mode='r', encoding="ISO-8859-1") as fin:
dt = _get_col_datatypes(fin)
fin.seek(0)
reader = csv.DictReader(fin)
# Keep the order of the columns name just as in the CSV
fields = reader.fieldnames
cols = []
# Set field and type
for f in fields:
cols.append("\"%s\" %s" % (f, dt[f]))
# Generate create table statement:
stmt = "create table if not exists \"" + tablename + "\" (%s)" % ",".join(cols)
print(stmt)
con = sqlite3.connect(dbFile)
cur = con.cursor()
cur.execute(stmt)
fin.seek(0)
reader = csv.reader(escapingGenerator(fin))
# Generate insert statement:
stmt = "INSERT INTO \"" + tablename + "\" VALUES(%s);" % ','.join('?' * len(cols))
cur.executemany(stmt, reader)
con.commit()
con.close()
คุณสามารถทำได้โดยใช้blaze
& odo
อย่างมีประสิทธิภาพ
import blaze as bz
csv_path = 'data.csv'
bz.odo(csv_path, 'sqlite:///data.db::data')
Odo จะเก็บไฟล์ csv ไว้ที่data.db
(ฐานข้อมูล sqlite) ภายใต้สคีมาdata
หรือคุณใช้โดยตรงโดยไม่ต้องodo
blaze
ทั้งสองวิธีก็ใช้ได้ อ่านเอกสารนี้
หากต้องนำเข้าไฟล์ CSV เป็นส่วนหนึ่งของโปรแกรม python ดังนั้นเพื่อความเรียบง่ายและมีประสิทธิภาพคุณสามารถใช้os.system
ตามบรรทัดที่แนะนำโดยต่อไปนี้:
import os
cmd = """sqlite3 database.db <<< ".import input.csv mytable" """
rc = os.system(cmd)
print(rc)
ประเด็นก็คือการระบุชื่อไฟล์ของฐานข้อมูลข้อมูลจะถูกบันทึกโดยอัตโนมัติโดยสมมติว่าไม่มีข้อผิดพลาดในการอ่าน
import csv, sqlite3
def _get_col_datatypes(fin):
dr = csv.DictReader(fin) # comma is default delimiter
fieldTypes = {}
for entry in dr:
feildslLeft = [f for f in dr.fieldnames if f not in fieldTypes.keys()]
if not feildslLeft: break # We're done
for field in feildslLeft:
data = entry[field]
# Need data to decide
if len(data) == 0:
continue
if data.isdigit():
fieldTypes[field] = "INTEGER"
else:
fieldTypes[field] = "TEXT"
# TODO: Currently there's no support for DATE in sqllite
if len(feildslLeft) > 0:
raise Exception("Failed to find all the columns data types - Maybe some are empty?")
return fieldTypes
def escapingGenerator(f):
for line in f:
yield line.encode("ascii", "xmlcharrefreplace").decode("ascii")
def csvToDb(csvFile,dbFile,tablename, outputToFile = False):
# TODO: implement output to file
with open(csvFile,mode='r', encoding="ISO-8859-1") as fin:
dt = _get_col_datatypes(fin)
fin.seek(0)
reader = csv.DictReader(fin)
# Keep the order of the columns name just as in the CSV
fields = reader.fieldnames
cols = []
# Set field and type
for f in fields:
cols.append("\"%s\" %s" % (f, dt[f]))
# Generate create table statement:
stmt = "create table if not exists \"" + tablename + "\" (%s)" % ",".join(cols)
print(stmt)
con = sqlite3.connect(dbFile)
cur = con.cursor()
cur.execute(stmt)
fin.seek(0)
reader = csv.reader(escapingGenerator(fin))
# Generate insert statement:
stmt = "INSERT INTO \"" + tablename + "\" VALUES(%s);" % ','.join('?' * len(cols))
cur.executemany(stmt, reader)
con.commit()
con.close()
เพื่อความเรียบง่ายคุณสามารถใช้เครื่องมือบรรทัดคำสั่ง sqlite3 จาก Makefile ของโครงการของคุณ
%.sql3: %.csv
rm -f $@
sqlite3 $@ -echo -cmd ".mode csv" ".import $< $*"
%.dump: %.sql3
sqlite3 $< "select * from $*"
make test.sql3
จากนั้นสร้างฐานข้อมูล sqlite จากไฟล์ test.csv ที่มีอยู่พร้อมด้วย "test" ตารางเดียว จากนั้นคุณสามารถmake test.dump
ตรวจสอบเนื้อหาได้
ฉันพบว่าอาจจำเป็นต้องแยกการถ่ายโอนข้อมูลจาก csv ไปยังฐานข้อมูลเป็นกลุ่มเพื่อไม่ให้หน่วยความจำหมด สามารถทำได้ดังนี้:
import csv
import sqlite3
from operator import itemgetter
# Establish connection
conn = sqlite3.connect("mydb.db")
# Create the table
conn.execute(
"""
CREATE TABLE persons(
person_id INTEGER,
last_name TEXT,
first_name TEXT,
address TEXT
)
"""
)
# These are the columns from the csv that we want
cols = ["person_id", "last_name", "first_name", "address"]
# If the csv file is huge, we instead add the data in chunks
chunksize = 10000
# Parse csv file and populate db in chunks
with conn, open("persons.csv") as f:
reader = csv.DictReader(f)
chunk = []
for i, row in reader:
if i % chunksize == 0 and i > 0:
conn.executemany(
"""
INSERT INTO persons
VALUES(?, ?, ?, ?)
""", chunk
)
chunk = []
items = itemgetter(*cols)(row)
chunk.append(items)