पायथन का उपयोग करके एक CSV फ़ाइल को एक sqlite3 डेटाबेस तालिका में आयात करना


106

मेरे पास एक CSV फ़ाइल है और मैं पायथन का उपयोग करके इस फ़ाइल को अपने sqlite3 डेटाबेस में थोक-आयात करना चाहता हूं। कमांड ".import ....." है। लेकिन ऐसा लगता है कि यह इस तरह काम नहीं कर सकता। क्या कोई मुझे sqlite3 में इसे करने का एक उदाहरण दे सकता है? मैं केवल मामले में विंडोज़ का उपयोग कर रहा हूं। धन्यवाद


3
कृपया वास्तविक कमांड प्रदान करें जो काम न करे और वास्तविक त्रुटि संदेश। "आयात ...." कुछ भी हो सकता है। "काम नहीं कर सकता" हमारे लिए अनुमान लगाने के लिए बहुत अस्पष्ट है। विवरण के बिना, हम मदद नहीं कर सकते।
एस.लॉट

2
जैसा कि मैंने कहा था कि वास्तविक कमांड ".import" है और यह सिंटैक्स त्रुटि नया ".import" कहता है
होसैन

10
कृपया वास्तव में प्रश्न में वास्तविक कमांड पोस्ट करें। कृपया वास्तव में प्रश्न में वास्तविक त्रुटि संदेश पोस्ट करें। कृपया उन टिप्पणियों को न जोड़ें जो बस चीजों को दोहराती हैं। कृपया वास्तविक कॉपी और पेस्ट के साथ प्रश्न को अपडेट करें जो आप वास्तव में कर रहे हैं।
22.10

जवाबों:


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

4
मामले में आपके पास वही समस्याएं थीं जो मैंने किया था: cs1 फ़ाइल में कॉलम हेडर में col1 और col2 को बदलना सुनिश्चित करें। और अंत में con.close () को कॉल करके डेटाबेस से कनेक्शन बंद करें।
जोनास

1
धन्यवाद, @ जोनास अपडेट की गई पोस्ट।
मैकेनिकल_मीट

not all arguments converted during string formattingजब मैं इस विधि का प्रयास करता हूं तो मैं मिलता रहता हूं।
वाइटेकैट

मैंने यह तरीका आजमाया, लेकिन यह मेरे लिए काम नहीं करता। क्या आप यहां मेरे डेटासेट देख सकते हैं (वे बहुत सामान्य हैं, कुछ स्तंभों को छोड़कर खाली मान हैं) और उन्हें अपने कोड के साथ आयात करने का प्रयास करें? stackoverflow.com/questions/46042623/…
user177196

2
यह कोड बहुत बड़ी सीएसवी फाइलों (
जीबी के

91

डिस्क पर एक फ़ाइल के लिए एक साइक्लाइट कनेक्शन बनाना पाठक के लिए एक अभ्यास के रूप में छोड़ दिया जाता है ... लेकिन अब पंडों के पुस्तकालय द्वारा संभव बनाया गया एक दो-लाइनर है

df = pandas.read_csv(csvfile)
df.to_sql(table_name, conn, if_exists='append', index=False)

धन्यवाद। मुझे पांडा के साथ एक मुद्दा मिला। मेरा csv ';' द्वारा सीमांकित है। और प्रविष्टियों में ',' है। पांडा read_csv पर त्रुटि देता है। अस्थायी रूप से बदलने के लिए अल्पविराम डब्ल्यू / आउट वाली प्रविष्टियों को पढ़ने के लिए कोई सेटिंग?
एलेक्सी मार्टीनोव

3
sep = 'का उपयोग करें।' पांडा प्रलेखन स्पष्ट रूप से यह बताता है कि इससे कैसे निपटा जाए।
टेनेसी लीवेनबर्ग

3
वहाँ एक तरीका है पांडा का उपयोग करने के लिए, लेकिन RAM का उपयोग किए बिना?, मैं एक बहुत बड़ा है .csv (7gb) मैं एक डेटाफ्रेम के रूप में आयात नहीं कर सकता और फिर DB में जोड़ा जा सकता है।
पाब्लो

1
हां, पंडों में एक विधि है जो एक ही बार में बजाय विखंडू में पढ़ेगी। मुझे डर है कि मैं अपने सिर के ऊपर से बिल्कुल याद नहीं कर सकता। मुझे लगता है कि आप chunksize = <number_of_rows> जोड़ते हैं, और फिर आपको एक पुनरावृत्तिकर्ता मिल जाता है, जिसे आप बाद में डेटाबेस के टुकड़े में जोड़ सकते हैं। मुझे बताएं कि क्या आपको इसे खोजने में परेशानी है और मैं एक नुस्खा खोद सकता हूं।
टेनेसी लीउवेनबर्ग

1
बहुत अच्छा, @TeneniLeeuwenburg। मुझे इसकी आवश्यकता नहीं थी dfइसलिए मैंने आपके उदाहरण को छोटा कर दिया:pandas.read_csv(csvfile).to_sql(table_name, conn, if_exists='append', index=False)
कीथजॉली

13

मेरे 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

1
अगर len (feildslLeft)> 0: हमेशा सच होता है, तो एक अपवाद को बढ़ाता है। कृपया इसकी समीक्षा करें और इसे सुधारें।
एमु ६६

बिना fseek () के ऐसा करने का कोई भी तरीका, ताकि इसे धाराओं पर इस्तेमाल किया जा सके?
mwag

1
@ mwag आप सिर्फ कॉलम टाइप चेकिंग को छोड़ सकते हैं और कॉलम को टेक्स्ट की तरह इम्पोर्ट कर सकते हैं।
user5359531

12

.importआदेश sqlite3 कमांड लाइन उपकरण की एक विशेषता है। पायथन में ऐसा करने के लिए, आपको सिर्फ़ उन सुविधाओं का उपयोग करके डेटा लोड करना चाहिए जो कि पाइथन के पास हैं, जैसे कि सीएसवी मॉड्यूल , और हमेशा की तरह डेटा सम्मिलित करना।

इस प्रकार, आपके पास यह भी नियंत्रण है कि sqlite3 के प्रतीत होने वाले अनिर्दिष्ट व्यवहार पर निर्भर होने के बजाय, किस प्रकार का डाला जाता है।


1
इंसर्ट तैयार करने की जरूरत नहीं है। SQL स्टेटमेंट और संकलित परिणामों के स्रोत को कैश में रखा जाता है।
जॉन मचिन

@ जॉन मैकिन: क्या कोई लिंक है कि SQLite यह कैसे करता है?
मार्सेलो कैंटोस

@ मार्सेलो: यदि आप HOW में रुचि रखते हैं तो यह (क्यों?) किया गया है, sqlite स्रोत में देखें या sqlite मेलिंग सूची पर पूछें।
जॉन माचिन

@ जॉन माचिन: ​​मुझे दिलचस्पी है क्योंकि सभी SQLite प्रलेखन में जो मैं भर आया हूं, बिना किसी बयान के स्वचालित कैशिंग के बारे में एक भी शब्द नहीं है। मुझे नहीं लगता कि कुछ को खोजने के लिए स्रोत कोड या जांच मेलिंग सूचियों को पढ़ना उचित है क्योंकि मुझे अपने एसक्यूएल स्टेटमेंट तैयार करने चाहिए या नहीं। इस पर आपकी जानकारी का स्रोत क्या है?
मार्सेलो कैंटोस

4
@ मार्सेलो: वास्तव में यह पायथन sqlite3 आवरण मॉड्यूल में किया गया है। docs.python.org/library/… का कहना है कि "" sqlite3 मॉड्यूल SQL पार्सिंग ओवरहेड से बचने के लिए आंतरिक रूप से एक स्टेटमेंट कैश का उपयोग करता है। यदि आप स्पष्ट रूप से कनेक्शन के लिए कैश किए गए स्टेटमेंट की संख्या सेट करना चाहते हैं, तो आप caked_statements पैरामीटर सेट कर सकते हैं। । वर्तमान में कार्यान्वित डिफ़ॉल्ट 100 स्टेटमेंट्स को कैश करना है। "" "
जॉन मैकिन

9
#!/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()

9

बर्नी के उत्तर के लिए बहुत धन्यवाद ! इसे थोड़ा मोड़ना था - यहाँ मेरे लिए क्या काम किया गया है:

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

7

आप सही हैं कि .importजाने का रास्ता है, लेकिन यह SQLite3.exe शेल से एक कमांड है। इस प्रश्न के बहुत से शीर्ष उत्तरों में देशी पायथन लूप शामिल हैं, लेकिन यदि आपकी फाइलें बड़ी हैं (मेरा 10 ^ 6 से 10 ^ 7 रिकॉर्ड है), तो आप पंडों में सब कुछ पढ़ने या देशी अजगर सूची बोध / पाश का उपयोग करने से बचना चाहते हैं। (हालांकि मैंने उनकी तुलना के लिए समय नहीं दिया)।

बड़ी फ़ाइलों के लिए, मेरा मानना ​​है कि सबसे अच्छा विकल्प पहले से खाली तालिका बनाना है 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डेटाबेस के बाद ध्वज आपको sqlite प्रोग्राम में कमांड पर कई फॉलो करने की अनुमति देता है। शेल में, प्रत्येक कमांड को उद्धरणों में होना चाहिए, लेकिन यहां, उन्हें अनुक्रम का अपना तत्व होना चाहिए
  • '.mode csv' आप क्या उम्मीद करेंगे
  • '.import '+str(csv_file).replace('\\','\\\\')+' <table_name>'आयात आदेश है।
    दुर्भाग्य से, चूंकि सबप्रोसेस सभी फॉलो-ऑन को -cmdउद्धृत स्ट्रिंग्स के रूप में पास करता है, अगर आपको विंडोज़ निर्देशिका पथ है तो आपको अपने बैकस्लैश को दोगुना करना होगा।

धारीदार हेडर

वास्तव में सवाल का मुख्य बिंदु नहीं है, लेकिन यहां मैंने जो उपयोग किया है। फिर, मैं किसी भी बिंदु पर पूरी फ़ाइलों को स्मृति में नहीं पढ़ना चाहता था:

with open(csv, "r") as source:
    source.readline()
    with open(str(csv)+"_nohead", "w") as target:
        shutil.copyfileobj(source, target)


4

गाइ एल सॉल्यूशन (इसे प्यार करें) पर आधारित है लेकिन बच गए खेतों को संभाल सकती है।

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

4

आप इसका उपयोग blazeऔर odoकुशलता से कर सकते हैं

import blaze as bz
csv_path = 'data.csv'
bz.odo(csv_path, 'sqlite:///data.db::data')

ओडो data.dbस्कीमा के तहत csv फ़ाइल को (sqlite डेटाबेस) स्टोर करेगाdata

या आप odoसीधे, बिना उपयोग करें blaze। किसी भी तरह से ठीक है। इस प्रलेखन पढ़ें


2
bz को परिभाषित नहीं किया गया: P
holms

और यह शायद बहुत पुराना पैकेज है क्योंकि उसकी आंतरिक त्रुटि: AttributeError: 'SubDiGraph' की कोई विशेषता 'बढ़त' नहीं है
होम्स

इसके अलावा एक ही विशेषता त्रुटि हो रही है: लगता है कि इसके लिए GitHub पर टिप्पणियां हैं, हालांकि
user791411

2

यदि CSV फ़ाइल को एक अजगर कार्यक्रम के हिस्से के रूप में आयात किया जाना चाहिए, तो सादगी और दक्षता के लिए, आप os.systemनिम्नलिखित द्वारा सुझाई गई लाइनों के साथ उपयोग कर सकते हैं :

import os

cmd = """sqlite3 database.db <<< ".import input.csv mytable" """

rc = os.system(cmd)

print(rc)

मुद्दा यह है कि डेटाबेस के फ़ाइल नाम को निर्दिष्ट करके, डेटा स्वचालित रूप से सहेज लिया जाएगा, यह मानते हुए कि इसे पढ़ने में कोई त्रुटि नहीं है।


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

2
कृपया अपने कोड को ठीक से प्रारूपित करें और
निष्पादन योग्य

1

सादगी के हित में, आप अपनी परियोजना के Makefile से sqlite3 कमांड लाइन टूल का उपयोग कर सकते हैं।

%.sql3: %.csv
    rm -f $@
    sqlite3 $@ -echo -cmd ".mode csv" ".import $< $*"
%.dump: %.sql3
    sqlite3 $< "select * from $*"

make test.sql3तब एक एकल परीक्षण "परीक्षण" के साथ एक मौजूदा test.csv फ़ाइल से sqlite डेटाबेस बनाता है। तब आप make test.dumpसामग्री को सत्यापित कर सकते हैं।


1

मैंने पाया है कि सीएसवी से डेटाबेस में डेटा के हस्तांतरण को विखंडित करना आवश्यक हो सकता है क्योंकि मेमोरी से बाहर न चला जाए। इसे इस तरह किया जा सकता है:

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)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.