2010-05-22 4 views
69

J'ai un fichier CSV et je veux importer en bloc ce fichier dans ma base de données sqlite3 en utilisant Python. la commande est ".import .....". mais il semble que cela ne puisse pas fonctionner comme ça. Quelqu'un peut-il me donner un exemple de la façon de le faire dans sqlite3? J'utilise Windows juste au cas où. MerciImporter un fichier CSV dans une table de base de données sqlite3 en utilisant Python

+3

Veuillez indiquer la commande ** réelle ** qui n'a pas fonctionné et le message d'erreur ** réelle **. "importer ...." pourrait être n'importe quoi. "ne peut pas travailler" est trop vague pour que nous devinions. Sans détails, nous ne pouvons pas aider. –

+1

la commande réelle comme je l'ai dit est ".import" et il dit erreur de syntaxe nouvelle ".import" – Hossein

+8

S'il vous plaît en fait publier la commande réelle dans la question. S'il vous plaît réellement poster le message d'erreur réel dans la question. S'il vous plaît ne pas ajouter des commentaires qui répètent simplement des choses. S'il vous plaît mettez à jour la question avec la copie réelle et la pâte de ce que vous faites réellement. –

Répondre

95
import csv, sqlite3 

con = sqlite3.connect(":memory:") 
cur = con.cursor() 
cur.execute("CREATE TABLE t (col1, col2);") # use your column names here 

with open('data.csv','rb') 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() 
+2

Dans le cas où vous avez eu les mêmes problèmes que j'ai: Assurez-vous de changer col1 et col2 aux en-têtes de colonne dans le fichier csv. Et fermez la connexion à la base de données en appelant con.close() à la fin. – Jonas

+0

Merci, @Jonas. Mise à jour post. – bernie

+0

Je n'obtiens pas 'tous les arguments convertis lors de la mise en forme des chaînes' quand j'essaye cette méthode. – Whitecat

10

La commande .import est une fonctionnalité de l'outil de ligne de commande sqlite3. Pour le faire en Python, vous devez simplement charger les données en utilisant toutes les fonctionnalités de Python, telles que le csv module, et en insérant les données comme d'habitude. De cette façon, vous avez également le contrôle sur les types qui sont insérés, plutôt que de s'appuyer sur le comportement apparemment non documenté de sqlite3.

+0

Il n'est pas nécessaire de préparer l'insert. La source des instructions SQL et les résultats compilés sont conservés dans un cache. –

+0

@John Machin: Y a-t-il un lien vers la façon dont SQLite fait cela? –

+0

@Marcelo: Si vous êtes intéressé par COMMENT cela est fait (pourquoi?), Regardez dans la source sqlite ou demandez sur la liste de diffusion sqlite. –

8

Un grand merci pour bernie de answer! Nous avons dû ruser un peu - voilà ce qui a fonctionné pour moi:

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

Mon fichier texte (PC.txt) ressemble à ceci:

1 | Term 1 | Definition 1 
2 | Term 2 | Definition 2 
3 | Term 3 | Definition 3 
6
#!/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() 
+0

Où est la fonction unicode()? –

49

Création d'une connexion SQLite dans un fichier sur disque est laissé comme un exercice pour le lecteur ... mais il est maintenant rendu possible de deux lignes par la bibliothèque de pandas géants

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

merci. J'ai un problème avec panda. mon csv est délimité par ';' et avoir ',' dans les entrées. panda donne une erreur sur read_csv. un paramètre pour lire les entrées avec des virgules sans remplacer temporairement? –

+3

utilisez sep = ';'. La documentation des pandas explique clairement comment gérer cela. –

+2

est-il un moyen d'utiliser, mais sans utiliser Pandas la RAM ?, j'ai un énorme .csv (7 Go) je ne peux pas importer en tant que trame de données, puis en annexe à la DB. –

9

Mes 2 cents (plus ge Neric):

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 
+0

si len (feildslLeft)> 0: toujours vrai, levant ainsi une exception. S'il vous plaît examiner et corriger cela. – shubham

+0

Toute façon de le faire sans avoir à fseek(), de sorte qu'il peut être utilisé sur les flux? – mwag

4

Vous pouvez le faire en utilisant blaze & odo efficacement

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

Odo va stocker le fichier csv à data.db (base de données SQLite) dans le cadre du schéma data

Ou vous utilisez odo directement, sans blaze. De toute façon est bien. Lire ceci documentation

Questions connexes