2015-10-08 3 views
2

Я реорганизую немного side project, чтобы использовать SQLite вместо структуры данных python, чтобы я мог изучать SQLite. Структура данных, которую я использовал, - это список dicts, где ключи каждого dict представляют свойства элемента меню. В конечном итоге эти ключи должны стать столбцами в таблице SQLite.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 говорит

параметры запроса могут быть использованы с выбрать, вставки и обновление заявления. Они могут отображаться в любой части запроса, где буквальное значение является законным.

Kreibich говорит на с. 135 Использование SQLite (ISBN 9780596521189):

Однако следует отметить, что параметры могут быть использованы только для замены буквенных значения, такие как строк в кавычках или числовых значений. Параметры не могут использоваться вместо идентификаторов, таких как имена таблиц или имена имен . Следующий бит SQL недопустим:

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

Я принимаю, что позиционные или именованные параметры не могут быть использованы таким образом. Почему они не могут? Есть ли какой-то общий принцип, который мне не хватает?

Похожие SO вопрос:

+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, вы должны добавить ограничение 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 и заново создайте словарь по одной строке/записи за раз.

(. Конечно, как и все в программной инженерии, существуют исключения инструменты, которые работают на схемах в общем, такие как ORMs, нужно будет указать имена таблиц/столбцов динамически.)

Смежные вопросы