【问题标题】:Automatically Load SQL table by reading data from text file通过从文本文件中读取数据自动加载 SQL 表
【发布时间】:2017-03-30 05:41:40
【问题描述】:

我正在尝试编写一个 python 脚本,该脚本将加载我使用 SQL 在 pyhton 中创建的表,并使用来自文本文件的数据自动填充它们。我被困在基本编码上。我确实有一个大致的想法,但是当我尝试运行这种方法时出现错误。我创建了 2 个表。我已阅读文件。该文件是一个逗号分隔的文本文件,没有标题。

文件的前 3 行如下所示。

+ ---- + ----- + -------------------- + -------- + - + --- + ----- +
| John | Smith | 111 N. Wabash Avenue | plumber  | 5 | 1.0 | 200   |
| John | Smith | 111 N. Wabash Avenue | bouncer  | 5 | 1.0 | 200   |
| Jane | Doe   | 243 S. Wabash Avenue | waitress | 1 | 5.0 | 10000 |
+ ---- + ----- + -------------------- + -------- + - + --- + ----- +

import sqlite3
conn= sqlite3.connect('csc455.db')
c = conn.cursor()

#Reading the data file
fd = open ('C:/Users/nasia/Documents/data_hw2.txt','r')
data = fd.readlines()

#Creating Tables
>>> L = """create table L
... (first text, last text, address text, job text, LNum integer,
... constraint L_pk
... primary key(first, last, address, job),
... constraint L_fk
... foreign key (LNum) references LN(LNum)
... );"""
>>> c.execute(L)

LN = """create table LN
... (
... LNum integer, Interest float, Amount, Integer,
... constraint LN_pk
 ... primary key (LNum)
... );"""
 c.execute(LN)

#Inserting into database
for elt in data:
...     currentRow = elt.split(", ")[:-1]
...     insert = """(insert into LN values (%s, %s, %s);, %(currentRow[4], currentRow[5], currentRow[6]))"""
...     c.execute(insert)

这里有一些语法错误。代码停止工作。我无法弄清楚我做错了什么。 错误是 回溯(最近一次通话最后): 文件“”,第 4 行,在 OperationalError:靠近“(”:语法错误

我不知道我做错了什么

【问题讨论】:

  • data_hw2.txt 是什么样的?你的数据库架构是什么?你想如何从一个映射到另一个?
  • 在未来,知道哪个语句引发了错误而不是让我们猜测真的很有帮助!
  • 附带说明,您不必将; 放在传递给execute 的各个SQL 语句上;仅当您使用命令行工具或执行 SQL 脚本时才需要。

标签: python sqlite


【解决方案1】:

您还没有解释数据的格式,或者您的表结构是什么,或者您希望如何映射它们,这使得这个问题难以回答。但我会自己编一个答案,希望对您有所帮助:

infile.txt:

CommonName,Species,Location,Color
Black-headed spider monkey,Ateles fusciceps,Ecuador,black
Central American squirrel monkey,Saimiri oerstedii,Costa Rica,orange
Vervet,Chlorocebus pygerythrus,South Africa,white

脚本.py

import csv
import sqlite3

db = sqlite3.connect('outfile.db')
cursor = db.cursor()
cursor.execute('CREATE TABLE Monkeys (Common Name, Color, Species)')
cursor.execute('''CREATE TABLE MonkeyLocations (Species, Location,
                  FOREIGN KEY(Species) REFERENCES Monkeys(Species))''')
with open('infile.txt') as f:
    for row in csv.DictReader(f):
        cursor.execute('''INSERT INTO Monkeys 
                          VALUES (:CommonName, :Color, :Species)''', row)
        cursor.execute('''INSERT INTO MonkeyLocations 
                          VALUES (:Species, :Location)''', row)
db.commit()
db.close()

当然,如果您的真实数据是 CSV 以外的其他格式,您将使用不同的代码来解析输入文件。

我还让事情变得比您的真实数据可能需要处理的稍微复杂一些 - CSV 列的名称与 SQL 列的名称不同。

在其他方面,您的数据可能更复杂——例如,如果您的架构具有引用自动递增行 ID 而不是文本字段的外键,则您需要在第一次插入后获取 rowid。

但这应该足以让你有这个想法。


现在您已经显示了更多详细信息……您走在了正确的轨道上(尽管调用 readlines 而不是直接迭代 fd 很浪费,而且您应该关闭数据库和文件,最好使用 @ 987654326@ 声明,...),但您在接近尾声时遇到了一个简单的错误,使您无法继续前进:

insert = """(insert into LN values (%s, %s, %s);, %(currentRow[4], currentRow[5], currentRow[6]))"""
c.execute(insert)

您已将格式化% 表达式直接放入字符串中,而不是在字符串上使用运算符。我想你想做的是:

insert = """insert into LN values (%s, %s, %s);""" % (currentRow[4], currentRow[5], currentRow[6])
c.execute(insert)

但是,您不应该这样做。而是这样做:

insert = """insert into LN values (?, ?, ?);"""
c.execute(insert, (currentRow[4], currentRow[5], currentRow[6]))

有什么区别?

好吧,第一个只是将值作为 Python 字符串插入到语句中。这意味着您必须自己处理转换为正确的格式、引用、转义等,而不是让数据库引擎决定如何处理每个值。当您尝试保存布尔值或忘记引用字符串时,除了会导致令人沮丧的错误之外,除非您非常小心,否则这还会使您容易受到SQL injection 攻击。

除此之外还有其他问题。例如,大多数数据库会尝试缓存重复的语句,并且告诉insert into LN values (?, ?, ?) 的 3000 个实例都是相同的语句是微不足道的,但告诉insert into LN values (5, 1.0, 200)insert into LN values (1, 5.0, 5000) 是相同的语句就更少了。

【讨论】:

  • ".txt 格式" 并不能告诉您如何解析它。这是某种文本。每条记录是否都是一行,字段用逗号分隔,并带有标题行?每条记录是否由空行分隔,字段为 Key: Value 行?或者…?这里有无限的可能,你必须知道你有什么才能读进去。
  • 我得到下表:(First,Last,Address,Job,LNumber,Amount,Interest),PK 为(First,Last,Jon,LNumber。FD 是 First,Last 确定地址。 LNumber 确定金额,利息。我必须将其分解为 3NF,然后编写 python 来加载表并通过字典或 for 循环用文本文件中的数据填充它们。数据的前 3 行是这样的。约翰, Smith, 111 N. Wabash Avenue, 水管工, 5, 1.0, 200 John, Smith, 111 N. Wabash Avenue, 保镖, 5, 1.0, 200 Jane, Doe, 243 S. Wabash Avenue, waitress, 1, 5.0, 10000。请帮忙。
  • @abarnet,感谢您昨天帮助我。我是该网站的新手,所以 d=没有足够清楚地说明我的问题。你能看看代码并指出我错的地方吗?谢谢。
【解决方案2】:

如果您可以使用标准的sqlite3 实用程序,您可以更轻松地做到这一点:

sqlite3 -init mydata.sql mydatabase.db ""

只需从你的 python 脚本中调用这一行,你就完成了。

这将读取任何包含有效 SQL 语句的文本文件,如果 mydatabase.db 不存在,则会创建它。更重要的是,它支持跨越多行的语句,并且还可以正确忽略使用--comment 语法和 C/C++(如/*comment*/ 语法)的 SQL cmets。

通常,您的 mydata.sql 内容应如下所示:

BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS table1 (
    id INTEGER PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(32)
);
INSERT INTO table1 (name) VALUES
('John'),
('Jack'),
('Jill');
-- more statements ...
COMMIT;

【讨论】:

  • 我对 Python 和 sqlite3 非常陌生。我们不能手动插入值,而是将其放入循环中。像这样: for elt in data: currentRow = elt.split(',')[:-1] #insert for tableA using first 3 entries normalizedTableA = [currentRow[0], currentRow[1], currentRow[3]) newInsert = "插入表 A 值 ('%s', '%s', '%s');" % (normalizedTableA[0], normalizedTableA[1], normalizedTableA[2]) # 使用第 4 个和第 5 个条目为 tableB 插入 normalizedTableB = [currentRow[4], currentRow[5]) newInsert = "INSERT INTO TableB VALUES ('%s ', '%s');" %(标准化表B[0],标准化表B[1])
  • 我现在已经详细解释了这个问题。你能看看并帮助我吗?非常感谢您昨天的意见。
  • 练习的重点是他们有一些其他格式的数据(在这种情况下,是一种奇怪的 CSV 方言)并且需要将其加载到数据库中。生成 SQL 语句是困难的部分,而不是执行它们。
猜你喜欢
  • 2015-07-14
  • 2017-10-31
  • 2013-10-15
  • 1970-01-01
  • 1970-01-01
  • 2018-03-19
  • 1970-01-01
  • 2015-09-11
  • 1970-01-01
相关资源
最近更新 更多