2

我的应用程序使用 SQLite,并且我已经整理了创建表语句。这个想法是表 A 和 B 具有一对多(或一个)关系,因此外键将在表 B 中。现在我知道用于创建主键的自动增量,但是这将如何用于外键? 如果我为表 A 添加一行,为表 B 添加 5 行(理想情况下,所有这些都链接到表 A 中的那一行)怎么办?它不会只是从表 B 中的 001-005 自动递增吗?

4

3 回答 3

10

是的,如果 A 和 B 之间是一对多的,并且当您在 B 中添加记录时,您将自动增加 B 的主键,但不会自动增加 A 的外键(假设您将其设置INTEGER为没有的普通旧键AUTOINCREMENT)。给定您的示例,是的,B 将有 5 条记录 1-5,它们都指向 A 中的记录 1。因此,当您在 A 中添加记录时,您可以通过 FMDB lastInsertRowId(或 sqlite 的sqlite3_last_insert_rowid())获取其 ID,并将其存储在一个变量,然后在 B 中填充外键时使用它。因此,简而言之,您不会“自动”设置外键,而是手动设置,但这并不难。

在如何配置表格方面,如果我们看一个作者和书籍之间的一对多关系的例子可能会有所帮助(忽略共同作者的可能性,但关注一个作者可以写多本书的事实) . 因此,您有两个实体,一个author(A) 实体和一个book(B) 实体。是book.book_author_id一个外键引用author.author_id

因此,看起来像:

CREATE TABLE author
(
    author_id INTEGER PRIMARY KEY AUTOINCREMENT,
    author_last_name TEXT,
    author_first_name TEXT
);

CREATE TABLE book
(
    book_id INTEGER PRIMARY KEY AUTOINCREMENT,
    title TEXT,
    book_author_id INTEGER,
    FOREIGN KEY (book_author_id) REFERENCES author (author_id)
);

INSERT INTO author (author_last_name, author_first_name) VALUES ('William', 'Shakespeare');

INSERT INTO book (title, book_author_id) VALUES ('Hamlet', 1);
INSERT INTO book (title, book_author_id) VALUES ('Macbeth', 1);
INSERT INTO book (title, book_author_id) VALUES ('Othello', 1);
INSERT INTO book (title, book_author_id) VALUES ('King Lear', 1);
INSERT INTO book (title, book_author_id) VALUES ('Henry V', 1);

如果我们查看结果,它看起来像:

$ sqlite3 test.db
SQLite version 3.7.12 2012-04-03 19:43:07
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .mode column
sqlite> .headers on
sqlite> 
sqlite> CREATE TABLE author
   ...> (
   ...>     author_id INTEGER PRIMARY KEY AUTOINCREMENT,
   ...>     author_last_name TEXT,
   ...>     author_first_name TEXT
   ...> );
sqlite> 
sqlite> CREATE TABLE book
   ...> (
   ...>     book_id INTEGER PRIMARY KEY AUTOINCREMENT,
   ...>     title TEXT,
   ...>     book_author_id INTEGER,
   ...>     FOREIGN KEY (book_author_id) REFERENCES author (author_id)
   ...> );
sqlite> 
sqlite> INSERT INTO author (author_last_name, author_first_name) VALUES ('William', 'Shakespeare');
sqlite> 
sqlite> SELECT * FROM author;
author_id   author_last_name  author_first_name
----------  ----------------  -----------------
1           William           Shakespeare      
sqlite> 
sqlite> INSERT INTO book (title, book_author_id) VALUES ('Hamlet', 1);
sqlite> INSERT INTO book (title, book_author_id) VALUES ('Macbeth', 1);
sqlite> INSERT INTO book (title, book_author_id) VALUES ('Othello', 1);
sqlite> INSERT INTO book (title, book_author_id) VALUES ('King Lear', 1);
sqlite> INSERT INTO book (title, book_author_id) VALUES ('Henry V', 1);
sqlite> 
sqlite> SELECT * FROM book;
book_id     title       book_author_id
----------  ----------  --------------
1           Hamlet      1             
2           Macbeth     1             
3           Othello     1             
4           King Lear   1             
5           Henry V     1             
sqlite> .quit

或者,如果您想以编程方式执行此操作(我正在使用FMDB,这使得这变得更简单,但如果您正在执行自己的 sqlite3 调用,显然相同的逻辑可以工作,但它只需要更多代码):

- (void)createAuthorTable
{
    BOOL result = [_db executeUpdate:
                     @"CREATE TABLE IF NOT EXISTS author "
                      "("
                          "author_id INTEGER PRIMARY KEY AUTOINCREMENT, "
                          "author_last_name TEXT, "
                          "author_first_name TEXT "
                      ");"];
    NSAssert(result, @"%s - Unable to create author table", __FUNCTION__);
}

- (void)createBookTable
{
    BOOL result = [_db executeUpdate:
                     @"CREATE TABLE IF NOT EXISTS book "
                      "("
                          "book_id INTEGER PRIMARY KEY AUTOINCREMENT, "
                          "title TEXT, "
                          "book_author_id INTEGER, "
                          "FOREIGN KEY (book_author_id) REFERENCES author (author_id) "
                      ");"];
    NSAssert(result, @"%s - Unable to create book table", __FUNCTION__);
}

- (sqlite_int64)createAuthorWithFirstName:(NSString *)firstName lastName:(NSString *)lastName
{
    BOOL result = [_db executeUpdate:@"INSERT INTO author (author_first_name, author_last_name) VALUES (?, ?)", firstName, lastName];
    NSAssert(result, @"%s - Unable to insert author record", __FUNCTION__);

    return [_db lastInsertRowId];
}

- (sqlite_int64)createBookWithTitle:(NSString *)title authorId:(sqlite_int64)authorId
{
    BOOL result = [_db executeUpdate:@"INSERT INTO book (title, book_author_id) VALUES (?, ?)", title, [NSNumber numberWithInt:authorId]];
    NSAssert(result, @"%s - Unable to insert book record", __FUNCTION__);

    return [_db lastInsertRowId];
}

- (void)testInsert
{
    [self openDatabase];

    NSArray *bookTitles = [NSArray arrayWithObjects:@"Hamlet", @"Macbeth", @"Othello", @"King Lear", @"Henry V", nil];
    [self createAuthorTable];
    [self createBookTable];

    sqlite_int64 authorId = [self createAuthorWithFirstName:@"William" lastName:@"Shakespeare"];

    sqlite_int64 bookId;
    for (NSString *bookTitle in bookTitles)
        bookId = [self createBookWithTitle:bookTitle authorId:authorId];

    [self closeDatabase];
}
于 2012-07-30T16:39:39.153 回答
1

但在设置外键之前,您必须先将其打开。而是先这样做,

PRAGMA foreign_keys=ON;
于 2013-02-05T05:30:31.070 回答
0

具有外键约束的列通常不是自动递增值,而是引用另一个表中的(预先存在的)键值。因此,如果您的 AUTHORS 表有一个自动递增的整数主键,那么您的 TITLES.AuthorID 列将只是一个没有自动递增功能的整数。

顺便说一句,整数值没有前导零:001-005- 这通常意味着必须用 text/varchar 数据类型表示的零填充。

于 2012-07-30T18:14:51.457 回答