我正在重构一点side project来使用SQLite而不是python数据结构,以便我可以学习SQLite。我一直在使用的数据结构是一个dicts列表,其中每个dict的键代表一个菜单项的属性。最终,这些键应该成为SQLite表中的列。
我首先想到我可以通过创建单列表,迭代字典键列表,并执行ALTER TABLE
,ADD 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
说
克雷比希说,p。 135 使用SQLite (ISBN 9780596521189):查询参数可与选择,插入和更新语句一起使用。它们可以出现在查询的任何部分,其中文字值是合法的。
但请注意,参数只能用于替换文字 值,例如引用的字符串或数值。参数 不能用于代替标识符,例如表名或 列名。以下SQL部分无效:
SELECT * FROM ?; -- INCORRECT: Cannot use a parameter as an identifier
我接受位置或命名参数不能以这种方式使用。他们为什么不能?我缺少一些一般原则吗?
类似的问题:
答案 0 :(得分:2)
标识符在语法上是重要的,而变量值则不是。
需要在SQL编译阶段识别标识符,以便编译的内部字节码表示知道相关的表,列,索引等。只更改SQL中的一个标识符可能会导致语法错误,或者至少是一种完全不同的字节码程序。
可以在运行时绑定文字值。无论绑定的值是什么,变量在编译的SQL程序中的行为基本相同。
答案 1 :(得分:0)
我不知道为什么,但我使用的每个数据库都有相同的限制。
我认为使用变量来保存另一个变量的名称类似。大多数语言不允许这样做,PHP是我所知道的唯一例外。
答案 2 :(得分:0)
无论技术原因如何,在SQL查询中动态选择表/列名称都是一种设计气味,这就是大多数数据库不支持它的原因。
想一想;如果您使用Python编写菜单,是否会为每个菜单项组合动态创建一个类?当然不是;您有一个包含菜单项列表的Menu类。它在SQL中也很相似。
大多数情况下,当人们询问动态选择表名时,因为他们将数据分成不同的表,例如collection1
,collection2
,. ..并使用名称来选择要查询的集合。这不是一个非常好的设计;它需要服务重复每个表的模式,包括索引,约束,权限等,并且还使得更难更改模式(需要添加字段?现在需要跨越数百个表而不是一个表)。
设计数据库的正确方法是使用单个collection
表并添加collection_id
列;您不是要查询collection4
,而是在WHERE collection_id = 4
次查询中添加SELECT
约束。请注意,4
现在是一个值,可以用查询参数替换。
对于您的情况,我会使用此架构:
CREATE TABLE menu_items (
item_id TEXT,
key TEXT,
value NONE,
PRIMARY KEY(item_id, key)
);
使用executemany
为字典中的每个条目插入一行。当您需要加载字典时,在SELECT
上运行item_id
过滤,并一次重新创建一行/条目字典。
(当然,与软件工程中的所有内容一样,也有例外。通常在模式上运行的工具(如ORM)需要动态指定表/列名。)