奇怪的 org.sqlite.SQLiteException: [SQLITE_ERROR] SQL 错误或缺少数据库(外键不匹配 -

Posted

技术标签:

【中文标题】奇怪的 org.sqlite.SQLiteException: [SQLITE_ERROR] SQL 错误或缺少数据库(外键不匹配 -【英文标题】:Strange org.sqlite.SQLiteException: [SQLITE_ERROR] SQL error or missing database (foreign key mismatch - 【发布时间】:2021-04-25 15:27:41 【问题描述】:

我正在运行into org.sqlite.SQLiteException: [SQLITE_ERROR] SQL error or missing database (foreign key mismatch - ... 的语句,使用普通的 SQLite 前端没有任何抱怨。这将创建我的数据库的关键部分:

CREATE TABLE IF NOT EXISTS artists (
    aid INTEGER PRIMARY KEY AUTOINCREMENT,
    aname VARCHAR(200) NOT NULL,
    CONSTRAINT one UNIQUE(aname)
);

CREATE TABLE IF NOT EXISTS discs (
    did INTEGER PRIMARY KEY AUTOINCREMENT,
    testAddCD1 BIGINT(10) NOT NULL,
    dtitle VARCHAR(125) NOT NULL,
    dreleaseyear YEAR(4) DEFAULT NULL,
    dlang VARCHAR(3) DEFAULT NULL
);

CREATE TABLE IF NOT EXISTS tracks (
    discs_did INTEGER NOT NULL,
    tnumber INT(4) NOT NULL,
    ttitle VARCHAR(125) NOT NULL,
    tseconds INT(4) NOT NULL,
    CONSTRAINT pk PRIMARY KEY(discs_did, tnumber),
    CONSTRAINT fk FOREIGN KEY(discs_did) REFERENCES discs(did) ON DELETE RESTRICT ON UPDATE RESTRICT,
    CONSTRAINT val CHECK(tseconds> 0)
);

CREATE TABLE IF NOT EXISTS track_by_artist (
    discs_did INTEGER NOT NULL,
    tracks_tnumber INT(4) NOT NULL,
    artists_aid INTEGER NOT NULL,
    CONSTRAINT pk PRIMARY KEY(discs_did, tracks_tnumber, artists_aid),
    CONSTRAINT fk1 FOREIGN KEY(discs_did) REFERENCES discs(did) ON DELETE RESTRICT ON UPDATE RESTRICT,
    CONSTRAINT fk2 FOREIGN KEY(tracks_tnumber) REFERENCES tracks(tnumber) ON DELETE RESTRICT ON UPDATE RESTRICT,
    CONSTRAINT fk3 FOREIGN KEY(artists_aid) REFERENCES artists(aid) ON DELETE RESTRICT ON UPDATE RESTRICT

数据库被创建并且 JDBC 驱动程序插入艺术家、光盘和光盘的曲目 - 一切都很好。最后的插入应该为曲目分配艺术家,看起来像

INSERT INTO track_by_artist (discs_did, tracks_tnumber, artists_aid) VALUES (1, 1, 1);

使用 JDBC 这会产生

SQLite-Error #1
org.sqlite.SQLiteException: [SQLITE_ERROR] SQL error or missing database (foreign key mismatch - "track_by_artist" referencing "tracks")
    at org.sqlite.core.DB.newSQLException(DB.java:1012)
    at org.sqlite.core.DB.newSQLException(DB.java:1024)
    at org.sqlite.core.DB.throwex(DB.java:989)
    at org.sqlite.core.NativeDB.prepare_utf8(Native Method)
    at org.sqlite.core.NativeDB.prepare(NativeDB.java:134)
    at org.sqlite.core.DB.prepare(DB.java:257)
    at org.sqlite.core.CorePreparedStatement.<init>(CorePreparedStatement.java:45)
    at org.sqlite.jdbc3.JDBC3PreparedStatement.<init>(JDBC3PreparedStatement.java:30)
    at org.sqlite.jdbc4.JDBC4PreparedStatement.<init>(JDBC4PreparedStatement.java:25)
    at org.sqlite.jdbc4.JDBC4Connection.prepareStatement(JDBC4Connection.java:35)
    at org.sqlite.jdbc3.JDBC3Connection.prepareStatement(JDBC3Connection.java:241)
    at org.sqlite.jdbc3.JDBC3Connection.prepareStatement(JDBC3Connection.java:205)

使用 SQLite 的文本前端发出相同的 SQL-Insert 就像奶油一样。

我有点迷茫,不知道如何处理我的 Java 代码。

请给点建议好吗?

克里斯

【问题讨论】:

【参考方案1】:

问题是你在track_by_artist 中定义了这个外键约束:

CONSTRAINT fk2 FOREIGN KEY(tracks_tnumber) REFERENCES tracks(tnumber) ON DELETE RESTRICT ON UPDATE RESTRICT

虽然tracks 中的tnumber 不是UNIQUE(也不应该是)。 外键的父级必须定义为 UNIQUE

tracks 中,PRIMARY KEY 被定义为discs_didtnumber 的组合,这是有道理的,因此这两列的组合是唯一的。

您可以做的是在track_by_artist 中为引用discs_didtrackstracks_tnumberdiscs_didtracks_tnumber 定义一个复合外键:

CREATE TABLE IF NOT EXISTS track_by_artist (
    discs_did INTEGER NOT NULL,
    tracks_tnumber INT(4) NOT NULL,
    artists_aid INTEGER NOT NULL,
    CONSTRAINT pk PRIMARY KEY(discs_did, tracks_tnumber, artists_aid),
    CONSTRAINT fk1 FOREIGN KEY(discs_did, tracks_tnumber) REFERENCES tracks(discs_did, tnumber) ON DELETE RESTRICT ON UPDATE RESTRICT,
    CONSTRAINT fk2 FOREIGN KEY(artists_aid) REFERENCES artists(aid) ON DELETE RESTRICT ON UPDATE RESTRICT
);

这样您就不需要为discs_did 单独定义外键。

【讨论】:

以上是关于奇怪的 org.sqlite.SQLiteException: [SQLITE_ERROR] SQL 错误或缺少数据库(外键不匹配 -的主要内容,如果未能解决你的问题,请参考以下文章

很奇怪,谁知道这是啥编码???

奇怪的443端口?请专家释疑……

比较奇怪的数学问题 (很好理解)

在spark中遇到了奇怪的错误,找到了奇怪的解决方法

Node JS telnet 服务器奇怪的输入和奇怪的输出

奇怪的Andy,奇怪的旅行(无向图——邻接链表)