获取"sqlite3.OperationalError: no such column:"

3

我刚开始学习Python(从我的代码你可以看出来),我基本上写了一个示例脚本来测试一些核心命令,以便更好地理解它们的工作原理。除了最后一个“insert”命令之外,我已经将所有东西都运行得很好 - 经过数小时的谷歌和实验,我无法弄清楚哪里有问题,所以如果有人能向我展示需要更改什么并帮助我理解为什么(我确信这是基础知识,但我被卡住了!),我会非常感激。

下面是让我困扰的那一行:

c.execute("INSERT OR IGNORE INTO {tn} ({cn1}, {cn2}, {cn3}, {cn4}) VALUES ({VID}, {VSnu}, {VIN}, {VName})".\
        format(tn=table_name, cn1=column1, cn2=column2, cn3=column3, cn4=column4, VID=ID, VSnu=Snu, VIN=IN, VName=Name))

很抱歉,我只能用英语回答您的问题。如果您有任何需要翻译的内容,请告诉我,我会尽力帮助您。
import sqlite3

sqlite_file = '/test_database.sqlite'    # name of the sqlite database   file
table_name = 'test_table'
column1 = 'my_1st_column'
column2 = 'my_2nd_column'
column3 = 'my_3rd_column'
column4 = 'my_4th_column'
ID = int(123456)
Base = 'Arnold'
Snu = 'test'

conn = sqlite3.connect(sqlite_file)
c = conn.cursor()

c.execute("UPDATE {tn} SET {cn2}=('Snu'), {cn3}=('Muh'), {cn4}=('Arnold_A') WHERE {cn1}=({NID})".\
    format(tn=table_name, cn1=column1, cn2=column2, cn3=column3, cn4=column4, NID=ID))

i = 1
while(i<15):
if i == 1: IN = 'B'
if i == 2: IN = 'C'
if i == 3: IN = 'D'
if i == 4: IN = 'E'
if i == 5: IN = 'F'
if i == 6: IN = 'G'
if i == 7: IN = 'H'
if i == 8: IN = 'I'
if i == 9: IN = 'J'

ID = ID+1
i = i+1
Name = Base + '_' + IN
params = (Snu, IN, Name)

c.execute("INSERT OR IGNORE INTO {tn} ({cn1}, {cn2}, {cn3}, {cn4}) VALUES ({VID}, {VSnu}, {VIN}, {VName})".\
        format(tn=table_name, cn1=column1, cn2=column2, cn3=column3, cn4=column4, VID=ID, VSnu=Snu, VIN=IN, VName=Name))

if(i == 10): break

conn.commit()
conn.close()

它可以成功地写入“VID”项(它是一个整数列和表的主键),但是在此之后,它将一切解释为列,并出现“没有这样的列:[值]”错误。无论在“VID”之后出现什么(如上面的命令中演示的任何变量),或者如果我尝试插入一个直接的字符串值,我都会遇到此错误。这些其他列只是文本列,如果有帮助的话。

尝试使用 '{Vsnu}'{'Vsnu'} -> SQL中的字符串字面量需要用单引号括起来。您应该真的研究一下使用查询参数的价值。 - Mark Benningfield
1个回答

1

我知道你正在学习,所以不要被我接下来要说的话吓到 :-)

你正在错误地形成SQL命令。许多数据库API中都有一个特殊功能,叫做参数替换,包括Python中SQLite的API。

你不想像你现在这样连接值,因为它会导致SQL注入的问题。在像你这样简单的场景中,它可能不是一个问题,但当人们在互联网上公开服务时这样做,就会造成巨大的损失(数据盗窃、数据丢失、数据损坏等)。这个漫画说明了这个问题:https://xkcd.com/327/

在你的情况下,使用参数替换编写SQL命令不仅会使你的代码更安全易读,而且还会解决你看到的问题。

请参考下面的示例:

import sqlite3
conn = sqlite3.connect(":memory:")
c = conn.cursor()

# Here we don't need parameter substitution
c.execute("CREATE TABLE mytable (name text, quantity int)")

# We set the values somewhere else. For example, this could come from a web 
# form
entry = ("myname", 2)

# Now we execute the query, with the proper parameter substitution.
# Note the `?` characters. Python will automatically replace those with the 
# values in `entry`, making sure that things are right when forming the 
# command before passing to SQLite.
c.execute("INSERT OR IGNORE INTO mytable VALUES (?, ?)", entry)

print(c.execute("SELECT * from mytable").fetchall())

上面的示例假设您不需要参数化列名。在您的情况下,您显然正在读取所有列,因此您实际上不需要传递所有名称,只需像我在上面的示例中所做的那样,它将读取所有列。如果您确实需要将列名作为参数以读取数据子集,则必须采用类似于您使用的连接机制。但在这种情况下,一如既往,请非常小心地处理用户输入,以确保它不会形成错误的查询和命令。
更多详细信息请参见:https://docs.python.org/3/library/sqlite3.html

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接