SQLite:为什么不能使用参数来设置标识符?

时间:2015-10-08 15:08:11

标签: python sqlite

我正在重构一点side project来使用SQLite而不是python数据结构,以便我可以学习SQLite。我一直在使用的数据结构是一个dicts列表,其中每个dict的键代表一个菜单项的属性。最终,这些键应该成为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

  

查询参数可与选择插入更新语句一起使用。它们可以出现在查询的任何部分,其中文字值是合法的。

克雷比希说,p。 135 使用SQLite (ISBN 9780596521189):

  

但请注意,参数只能用于替换文字   值,例如引用的字符串或数值。参数   不能用于代替标识符,例如表名或   列名。以下SQL部分无效:

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

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

类似的问题:

3 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

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

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

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

设计数据库的正确方法是使用单个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)需要动态指定表/列名。)

相关问题