2015-10-08 45 views
2

我重构了一点点side project使用SQLite而不是Python数据结构,以便我可以学习SQLite。我一直使用的数据结构是一个字典列表,其中每个字典的键代表一个菜单项的属性。最终,这些键应该成为SQLite表中的列。SQLite:为什么不能使用参数来设置标识符?

我首先想到的是我可能会创建一个单列表,遍历字典的键列表,以及执行ALTER TABLEADD COLUMN命令,像这样以编程方式创建表:

# Various import statements and initializations 

conn = sqlite3.connect(database_filename) 
cursor = conn.cursor() 
cursor.execute("CREATE TABLE menu_items (item_id text)") 

# Here's the problem: 
cursor.executemany("ALTER TABLE menu_items ADD COLUMN ? ?", [(key, type(value)) for key, value in menu_data[0].iteritems()]) 

再过了些阅读,我意识到参数不能用于标识符,只能用于字面值。该PyMOTW on sqlite3

查询参数可使用选择插入,并更新语句。它们可以出现在字面值合法的查询的任何部分。

Kreibich在p。的使用SQLite(ISBN 9780596521189)135:然而

注意的是,参数只能用于替换文字 值,如引用的字符串或数值。参数 不能用于代替标识符,如表名称或 列名称。 SQL的下列位是无效的:

SELECT * FROM ?; -- INCORRECT: Cannot use a parameter as an identifier 

我接受位置或命名参数不能以这种方式使用。他们为什么不能呢?是否有一些我缺少的一般原则?

相似,所以问题:

+0

您可能会发现的https:/感兴趣的/www.sqlite.org/optoverview.html,并考虑如何更改列名影响是否可以使用索引,从而影响编译的字节码的性质。 – Duncan

回答

0

我不知道为什么,但我每次用过数据库有相同的限制。

我认为这将类似于使用变量来保存名称的另一个变量。大多数语言都不允许,PHP是我所知道的唯一例外。

2

标识符在语法上很重要,而变量值不是。

需要在SQL编译阶段识别标识符,以便编译的内部字节码表示知道相关的表,列,索引等。只是在SQL中更改一个标识符可能会导致语法错误,或者至少是一种完全不同的字节码程序。

文字值可以在运行时绑定。无论绑定的值如何,变量在编译的SQL程序中的行为基本相同。

+0

我知道基本的答案,但我不知道如何把它写成文字......你的解释是一个守护者 - 谢谢!应该指出的是,这个问题和你的答案超越了SQLite。 – Hambone

0

无论技术原因如何,在SQL查询中动态选择表/列名都是一种设计怪味,这就是大多数数据库不支持它的原因。

想一想;如果你使用Python编写菜单,你会为每个菜单项组合动态创建一个类吗?当然不是;你会有一个包含菜单项列表的菜单类。它在SQL中也很相似。

大多数情况下,当人们询问动态选择表名时,这是因为他们已将数据分成不同的表,如collection1,collection2,...并使用名称来选择要查询的集合。这不是一个很好的设计;它需要服务为每个表重复模式,包括索引,约束,权限等,并且还会使模式变得更难(需要添加字段?现在您需要在数百个表中而不是一个中执行)。

设计数据库的正确方法是使用单个collection表并添加collection_id列;而不是查询collection4,您会为您的SELECT查询添加WHERE collection_id = 4约束。请注意,4现在是一个值,可以替换为查询参数。

对于你的情况,我会用这个模式:

CREATE TABLE menu_items (
    item_id TEXT, 
    key TEXT, 
    value NONE, 
    PRIMARY KEY(item_id, key) 
); 

使用executemany插入一行在字典中的每个条目。当您需要加载字典时,请在item_id上运行SELECT筛选,并一次重新创建字典中的一行/条目。

(当然,与软件工程的一切,也有例外的工具,一般的模式进行操作,如奥姆斯,需要动态指定表/列名。)

相关问题