SQLite、Golang 和联结表
Posted
技术标签:
【中文标题】SQLite、Golang 和联结表【英文标题】:SQLite, Golang and junction table 【发布时间】:2016-02-15 13:22:42 【问题描述】:我想使用 Go 和 sqlite 创建一个小型图书数据库。我从这个建议SQLite foreign key examples 中提取了主要内容并重新开发了它。
package main
import (
"database/sql"
...
_ "github.com/mattn/go-sqlite3"
)
...
db, err := sql.Open("sqlite3", "./foo.db")
if err != nil
log.Fatal(err)
defer db.Close()
sqlStmt := `
create table books (
id integer primary key autoincrement,
title text
);
create table booksauthors (
bookid integer references books(id),
uthorid integer references authors(id) ON DELETE CASCADE ON UPDATE CASCADE
);
create table authors (
id integer primary key autoincrement,
fname text,
mname text,
lname text,
unique (fname, mname, lname) on conflict ignore
);
`
所以,我想保留唯一作者的列表并保持与书表的多对多连接(一本书可能有不止一个作者,而作者可能写不止一本书)。
然后我只是循环添加书籍,获取LastIndexID并将其放入连接表(代码为说明而减少,b为书籍结构):
tx, err := db.Begin()
if err != nil
log.Fatal(err)
res, err := db.Exec("Insert into books(title) values(?)", b.Title)
if err != nil
log.Fatal(err)
b_id, _ := res.LastInsertId()
for _, a := range b.Authors
res, err = db.Exec("Insert into authors(fname, mname, lname) values(?, ?, ?)", a.Fname, a.Mname, a.Lname)
if err != nil
log.Fatal(err)
a_id, _ := res.LastInsertId()
fmt.Println(a_id, b_id, a)
res, err = db.Exec("Insert into booksauthors(bookid, authorid) values(?, ?)", b_id, a_id)
if err != nil
log.Fatal(err)
tx.Commit()
麻烦来了 - 如果我添加多于一本同一作者的书,a_id 会增加,但联结表包含它的旧值。 例如:
Books:
id | Title
---|--------------------
1 | Atlas Shrugged pt.1
2 | Atlas Shrugged pt.2
3 | Atlas Shrugged pt.3
Authors:
id | Fname | Mname | Lname
---|-------|-------|------
702| Ayn | | Rand
Junction table:
BookId | AuthorID
-------|---------
1 | 700
2 | 701
3 | 702
What I want - Junction table:
BookId | AuthorID
-------|---------
1 | 702
2 | 702
3 | 702
我怎样才能修复它,以便正确的 AuthorId 会反映在桌子上?我不想使用 GORM 或任何 ORM 工具并尝试使用纯(嗯,或多或少)SQL 来解决它。
我现在看到的解决方案之一是我可以先 SELECT,然后如果没有找到,则 INSERT,然后再 SELECT 一次,但是我不确定这个想法有多惯用。请注意,我有大量记录要添加。
【问题讨论】:
【参考方案1】:我的建议是SELECT
您的作者列表和INSERT
缺少的那些。解决方案很幼稚,但它有效且简单。
我不是最新的 SQLite 关系特性,但使用它们并不总是处理外键的最简单方法......。
现在,如果您要处理大量数据,请执行相同的操作,但首先要合并您的图书作者,这样您就可以只处理一个 SELECT
和一个 INSERT
。
【讨论】:
【参考方案2】:作为一个快速的'n'dirty hack,我在添加作者后做了一个选择:
err = db.QueryRow("select id from authors where fname = ? and mname = ? and lname = ?", a.Fname, a.Mname, a.Lname).Scan(&a_id)
if err != nil
log.Fatal(err)
res, err = db.Exec("Insert into booksauthors(bookid, authorid) values(?, ?)", b_id, a_id)
if err != nil
enter code herelog.Fatal(err)
但我仍在寻找更好的答案...
【讨论】:
以上是关于SQLite、Golang 和联结表的主要内容,如果未能解决你的问题,请参考以下文章