我试图编写一个通用函数,该函数会将一行数据插入数据库的表中,但是我试图编写一个未知长度的数组。我的目标是能够在任何程序中调用此函数,并将任意长度的数据行写入表中(假设表和数组的长度相同。
我尝试添加数组,就像它是数据的奇异部分一样。
import sqlite3
def add2Db(dbName, tableName, data):
connection = sqlite3.connect(dbName)
cur = connection.cursor()
cur.execute("INSERT INTO "+ tableName +" VALUES (?)", (data))
connection.commit()
connection.close()
add2Db("items.db", "allItems", (1, "chair", 5, 4))
这只是崩溃,并给我一个错误,说它有4列,但只提供了一个值。
答案 0 :(得分:0)
SQLite不支持数组-您必须使用','。join()转换为TEXT才能将数组项连接为单个字符串并传递该字符串。
来源:SQLite网站 https://www.sqlite.org/datatype3.html
答案 1 :(得分:0)
我不是Python程序员,但是我从事SQL已有很长时间了。我什至写了自己的ORM。我的建议是不要编写自己的SQL查询生成器。有许多微妙的问题,尤其是安全性问题。我在下面详细说明其中的一些。
请使用完善的SQL查询生成器或ORM。他们已经处理了这些问题。这是使用SQLAlchemy的示例。
from datetime import date
from sqlalchemy import create_engine, MetaData
# Connect to the database with debugging on.
engine = create_engine('sqlite:///test.sqlite', echo=True)
conn = engine.connect()
# Read the schemas from the database
meta = MetaData()
meta.reflect(bind=engine)
# INSERT INTO users (name, birthday, state, country) VALUES (?, ?, ?, ?)
users = meta.tables['users']
conn.execute(
users.insert().values(name="Yarrow Hock", birthday=date(1977, 1, 23), state="NY", country="US")
)
SQLAlchemy可以执行所有范围的SQL操作,并将与不同的SQL变体一起工作。您还将获得类型安全性。
conn.execute(
users.insert().values(name="Yarrow Hock", birthday="in the past", state="NY", country="US")
)
sqlalchemy.exc.StatementError: (exceptions.TypeError) SQLite Date type only accepts Python date objects as input. [SQL: u'INSERT INTO users (name, birthday, state, country) VALUES (?, ?, ?, ?)']
insert into table values (...)
依赖列定义顺序这取决于在模式中定义的订单列。这留下了两个问题。首先是可读性问题。
add2Db(db, 'some_table', (1, 39, 99, 45, 'papa foxtrot', 0, 42, 0, 6)
那是什么意思?读者无法分辨。他们必须深入研究架构并计数列,以找出每个值的含义。
第二个是维护问题。如果出于任何原因更改了架构,并且列顺序 完全 不完全相同,则可能会导致某些极其难以发现的错误。例如...
create table users ( name text, birthday date, state text, country text );
vs
create table users ( name text, birthday date, country text, state text );
add2Db(db, 'users', ('Yarrow Hock', date(1977, 1, 23), 'NY', 'US'));
该插入将以任一列顺序静默“工作”。
您可以通过传入字典并使用列名称键来解决此问题。
add2Db(db, 'users', (name="Yarrow Hock", birthday=date(1977, 1, 23), state="NY", country="US"));
然后我们将生成一个查询,例如:
insert into users
(name, birthday, state, country)
values (?, ?, ?, ?)
这导致了下一个更大的问题。
现在,这提出了一个新问题。如果我们只是简单地将表名和列名粘贴到查询中,就使我们容易接触到最常见的安全漏洞之一,即SQL Injection Attack。在那里,有人可以设计一个值,而该值在SQL语句中天真地使用时会使查询执行其他操作。像Little Bobby Tables。
尽管?
可以防止SQL注入值,但仍然可以通过列名进行注入。不能保证列名可以信任。也许它们来自网络表单的参数?
Protecting table and column names is complicated,容易出错。
您编写的SQL越多,就越容易受到注入攻击。
好的,您已经完成insert
。现在update
吗? select
?不要忘记子查询,分组依据,联合,联接...
如果要编写SQL查询构建器,那就太好了!相反,如果您有使用SQL的工作要做,那么编写另一个SQL查询构建器也不是您的工作。
任何给定的Python程序员都有很大的机会知道SQLAlchemy的工作方式,如果没有,则有很多教程和文档。他们没有机会知道您的自家推出的SQL函数,因此您必须编写所有教程和文档。
答案 2 :(得分:0)
在没有争论的需求的情况下,您不应尝试编写自己的ORM。您将遇到很多问题,例如,这里有25个not to的简短原因。
请使用任何经过验证的流行ORM。我建议使用SQLAlchemy作为Django之外的工具。使用它,您可以映射值的字典以将其插入到模型中,就像insert(schema_name).values(**dict_name)
(这是插入/更新的example)一样。
答案 3 :(得分:-1)
将功能更改为此:
def add2Db(dbName, tableName, data):
num_qs = len(data)
qm = ','.join(list('?' * num_qs))
query = """
INSERT INTO {table}
VALUES ({qms})
""".format(table=tableName,
qms=qm)
connection = sqlite3.connect(dbName)
cur = connection.cursor()
cur.execute(query, data)
connection.commit()
connection.close()