私のアプリは SQLite を使用しており、create table ステートメントを整理しました。テーブル A と B には 1 対多 (または 1) の関係があるため、外部キーはテーブル B にあるという考えです。主キーを作成するための自動インクリメントについてはわかりましたが、これは外部キーに対してどのように機能するのでしょうか。 ? テーブル A に 1 行、テーブル B に 5 行を追加するとどうなりますか? テーブル B の 001 から 005 まで自動インクリメントしないのでしょうか?
3 に答える
はい、A と B の間が 1 対多であり、B にレコードを追加すると、B の主キーは自動インクリメントされますが、A の外部キーはインクリメントされません ( INTEGER
noを使用して単純な古いものにすると仮定しますAUTOINCREMENT
)。あなたの例を考えると、はい、B には 1 ~ 5 の 5 つのレコードがあり、これらはすべて A のレコード 1 を指します。したがって、A にレコードを追加すると、FMDB lastInsertRowId
(または sqlite sqlite3_last_insert_rowid()
) を介してその ID を取得し、それをつまり、外部キーを「自動的に」設定するのではなく、手動で設定するだけですが、難しくはありません。
テーブルの構成方法に関しては、著者と本の間の 1 対多の関係の例を見ると役立つかもしれません (共著の可能性は無視しますが、1 人の著者が複数の本を書くことができるという事実に焦点を当てます)。 . したがって、author
(A) エンティティとbook
(B) エンティティの 2 つのエンティティがあります。は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];
}
ただし、外部キーを設定する前に、まずそれをオンにする必要があります。代わりにこれを最初に行います。
PRAGMA foreign_keys=ON;
通常、外部キー制約のある列は自動インクリメント値ではありませんが、別のテーブルの (既存の) キー値を参照します。したがって、AUTHORS テーブルに自動インクリメント整数主キーがある場合、TITLES.AuthorID 列は、自動インクリメント機能のない単純な整数になります。
ところで、整数値には先行ゼロがありません001-005
: -- これは通常、text/varchar データ型で表現する必要があるゼロ パディングを意味します。