2015-10-08 94 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篩選,並一次重新創建字典中的一行/條目。

(當然,與軟件工程的一切,也有例外的工具,一般的模式進行操作,如奧姆斯,需要動態指定表/列名。)

相關問題