我正在尝试将播放列表存储在sqlite表中。为了节省存储空间,我希望将歌曲艺术家和标题保存在表格中,并使用两个表格的rowid来存储剧本。
数据库的结构如下所示:
conn = sqlite3.connect('playlist.db')
c = conn.cursor()
sqlcommand= 'CREATE TABLE if not EXISTS artists(artist text PRIMARY KEY)'
c.execute(sqlcommand)
sqlcommand= 'CREATE TABLE if not EXISTS titles(title text PRIMARY KEY)'
c.execute(sqlcommand)
sqlcommand= 'CREATE TABLE if not EXISTS plays(PlayDate date, PlayTime datetime, ArtistID integer, TitleID integer )'
c.execute(sqlcommand)
每个歌曲播放事件都像这样存储
sqlcommand= 'INSERT or IGNORE INTO artists VALUES ("' + FoundArtist + '")'
c.execute(sqlcommand)
sqlcommand= 'INSERT or IGNORE INTO titles VALUES ("' + FoundTitle + '")'
c.execute(sqlcommand)
sqlcommand= 'SELECT ROWID from artists where artist = "'+FoundArtist+'"'
c.execute(sqlcommand)
ArtistID = str(c.fetchone()[0])
sqlcommand= 'SELECT ROWID from titles where title = "'+FoundTitle+'"'
c.execute(sqlcommand)
TitleID = str(c.fetchone()[0])
sqlcommand= 'INSERT or IGNORE INTO plays VALUES ("' + FoundPlayDate + '",' + \
'"'+ FoundPlayTime + '",' + \
ArtistID + ',' + \
TitleID + ')'
c.execute(sqlcommand)
这有效,但速度很慢。
如何组合两个select和最后一个insert命令以便它们同时运行?
我正在使用覆盆子pi运行Python 2.7.6(使用Raspian / Debian wheezy)
答案 0 :(得分:1)
当此列未出现在表定义中时,您不能依赖rowid
值;任何VACUUM都可能会改变它们。
所以你的表应该这样定义:
CREATE TABLE artists(ID INTEGER PRIMARY KEY, name TEXT UNIQUE);
CREATE TABLE titles(ID INTEGER PRIMARY KEY, name TEXT UNIQUE);
CREATE TABLE plays(
PlayDate DATE,
PlayTime DATETIME,
/* ... */
ArtistID INTEGER REFERENCES artists(ID),
TitleID INTEGER REFERENCES titles(ID)
);
理论上,ID查找可以使用子查询来完成,如下所示:
INSERT INTO plays VALUES('...', '...',
(SELECT ID FROM artists WHERE name = '...'),
(SELECT ID FROM titles WHERE name = '...'));
但是,当您尝试插入名称时,数据库必须已对名称进行查找。 对于已存在的名称,如果在插入ID之前尝试读取ID(并检查其是否存在),则可以避免这些查找之一:
c.execute("SELECT ID FROM artists WHERE name = ?", (FoundArtist,))
row = c.fetchone()
if row is None:
c.execute("INSERT INTO artists(name) VALUES(?)", (FoundArtist,))
artistID = c.lastrowid
else:
artistID = row[0]
c.execute("SELECT ID FROM titles WHERE name = ?", (FoundTitle,))
row = c.fetchone()
if row is None:
c.execute("INSERT INTO titles(name) VALUES(?)", (FoundTitle,))
titleID = c.lastrowid
else:
titleID = row[0]
c.execute("INSERT INTO plays VALUES(?,?,?,?)",
(FoundPlayDate, FoundPlayTime, artistID, titleID))
答案 1 :(得分:0)
您无需从rowid
和artists
提取titles
。您已将艺术家和标题名称设置为主键。他们是 ids,你不需要查询它们,因为你已经拥有它们。
您真正需要做的就是改变您的plays
架构:
CREATE TABLE plays (
id INTEGER PRIMARY KEY AUTOINCREMENT,
founddatetime TEXT DEFAULT CURRENT_TIMESTAMP,
artist TEXT,
title TEXT,
FOREIGN KEY(artist) REFERENCES artists(artist),
FOREIGN KEY(title) REFERENCES titles(title)
);
FOREIGN KEY
指令确保artist
中的每个title
和plays
分别对应artists
和titles
中的条目。< / p>
然后添加记录看起来有点像这样:
c.execute('INSERT OR IGNORE INTO artists(artist) VALUES ?', [FoundArtist])
c.execute('INSERT OR IGNORE INTO titles(title) VALUES ?', [FoundTitle])
c.execute('INSERT INTO plays(founddatetime, artist, title) VALUES (?, ?, ?)',
[FoundPlayDateTime, FoundArtist, FoundTitle])
c.commit()