Python& Sqlite3 - 如何从两个select语句中插入ID

时间:2014-01-27 20:36:54

标签: python sqlite sql-insert

我正在尝试将播放列表存储在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)

2 个答案:

答案 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)

您无需从rowidartists提取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中的每个titleplays分别对应artiststitles中的条目。< / 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()