sql - INSERT ... 在发生冲突时什么都不做 - 读取 csv 并生成外键表

标签 sql postgresql insert duplicates conflict

我正在尝试读取包含艺术家、专辑、歌曲和标签列的 csv 文件。

我希望像这样填充 artist_album_song 表:

|artist_id|album_id|song_id|
|---------|--------|-------|
|   1     |     1  |     1 |
|   1     |     1  |     2 |
|   1     |     2  |     1 |
...
|  12     |     1  |     1 |
...

我已经设计并正在尝试填充以下表格。当我在 csv 中阅读时,问题是在 artist_album_song 表中填充外键。

将 INSERT 插入此表的最佳方法是什么,以实现我在下面使用的 INSERT 语句(返回语法错误)中尝试执行的操作?谢谢。

create table artists (
    artist_id SERIAL PRIMARY KEY,
    artist VARCHAR(100) NOT NULL UNIQUE
);

create table albums (
    album_id SERIAL PRIMARY KEY,
    album VARCHAR(100) NOT NULL UNIQUE
);

create table songs (
    song_id SERIAL PRIMARY KEY,
    song VARCHAR(250) NOT NULL UNIQUE
);

create table tags (
    tag_id SERIAL PRIMARY KEY,
    tag VARCHAR(100) NOT NULL UNIQUE
);

create table artists_albums_songs (
    artist_id INTEGER NOT NULL,
    album_id INTEGER NOT NULL,
    song_id INTEGER NOT NULL,
    FOREIGN KEY (artist_id) REFERENCES artists(artist_id),
    FOREIGN KEY (album_id) REFERENCES albums(album_id),
    FOREIGN KEY (song_id) REFERENCES songs(song_id),
    PRIMARY KEY (artist_id, album_id, song_id)
);

create table songs_tags (
    song_id INTEGER NOT NULL,
    tag_id INTEGER NOT NULL,
    FOREIGN KEY (song_id) REFERENCES songs(song_id),
    FOREIGN KEY (tag_id) REFERENCES tags(tag_id),
    PRIMARY KEY (song_id, tag_id)
);

在尝试了来自以下链接的各种声明变体之后,我仍然无法让它工作。

我已经尝试了以下语句,但我不断收到错误。第一个返回错误:

org.postgresql.util.PSQLException: ERROR: syntax error at or near "ON" Position: 161;

161是指下面SQL语句中的第161个字符吗?

INSERT INTO artists_albums_songs
SELECT artist_id, album_id, song_id 
FROM artists a 
    JOIN albums b
        ON a.artist = ?
        AND b.album = ?
    JOIN songs c
        ON c.song = ?
    ON DUPLICATE (artist_id, album_id, song_id) DO NOTHING;

INSERT INTO artists_albums_songs
SELECT artist_id, album_id, song_id 
FROM artists a 
    JOIN albums b
        ON a.artist = ?
        AND b.album = ?
    JOIN songs c
        ON c.song = ?
    WHERE NOT EXISTS (
        SELECT * 
        FROM artists_albums_songs
        WHERE * = ?, ?, ?)

INSERT INTO artists_albums_songs
SELECT artist_id, album_id, song_id 
FROM artists a 
    JOIN albums b
        ON a.artist = ?
        AND b.album = ?
    JOIN songs c
        ON c.song = ?
    ON CONFLICT (song_id) IGNORE;

编辑:如果我删除上面 3 个 INSERT 语句的最后一行,它会起作用,但是当它遇到重复项时,它会说:

org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "artists_albums_songs_pkey"
  Detail: Key (artist_id, album_id, song_id)=(1, 1, 1) already exists.

Insert, on duplicate update in PostgreSQL?

Use INSERT ... ON CONFLICT DO NOTHING RETURNING failed rows

How to UPSERT (MERGE, INSERT ... ON DUPLICATE UPDATE) in PostgreSQL?

最佳答案

编辑 1: 我刚刚意识到我可以用 Java 处理这些错误!所以我的解决方案只涉及添加一个 catch 语句来处理 Duplicate SQLException

private <T> void insertIntoArtistAlbumSong(T artist, T album, T song) throws SQLException {

    try {

        String artString = artist.toString();
        String albString = album.toString();
        String songString = song.toString();

        // Create SQL insert statement
        String stm =
                "INSERT INTO artists_albums_songs " +
                        "SELECT artist_id, album_id, song_id " +
                        "FROM artists a " +
                        "JOIN albums b " +
                        "ON a.artist = ? " +
                        "AND b.album = ? " +
                        "JOIN songs c " +
                        "ON c.song = ? ;";


        PreparedStatement pstmt = connection.prepareStatement(stm);

        // Set values in prepared statement
        pstmt.setString(1, artString);
        pstmt.setString(2, albString);
        pstmt.setString(3, songString);

        // Insert into table
        pstmt.executeUpdate();

    // ADDED THIS CATCH STATEMENT!
    } catch (SQLException e){
        System.out.println(e.getSQLState());
    }
}

好的,所以我找到了一个解决方案,但它只适用于填充表格(这是我实际要做的)。

  1. 删除原始 artists_albums_songs[1] 表
  2. 创建 artists_albums_songs[2] 表没有约束:

    CREATE TABLE artists_albums_songs (
        artist_id INTEGER NOT NULL,
        album_id INTEGER NOT NULL,
        song_id INTEGER NOT NULL
    );
    
  3. 然后我使用以下语句(通过 JDBC)填充表[2]:

    INSERT INTO artists_albums_songs
    SELECT artist_id, album_id, song_id 
    FROM artists a 
        JOIN albums b
            ON a.artist = ?
            AND b.album = ?
        JOIN songs c
            ON c.song = ?;
    
  4. 创建一个 tmp[3] 表具有约束(通过 psql 命令行):

    CREATE TABLE tmp (
        artist_id INTEGER NOT NULL,
        album_id INTEGER NOT NULL,
        song_id INTEGER NOT NULL,
        FOREIGN KEY (artist_id) REFERENCES artists(artist_id),
        FOREIGN KEY (album_id) REFERENCES albums(album_id),
        FOREIGN KEY (song_id) REFERENCES songs(song_id),
        PRIMARY KEY (artist_id, album_id, song_id)
    );
    
  5. 仅将新 artists_albums_songs[2] 中的 distinct 行插入 tmp[3](通过 psql):

    INSERT INTO tmp SELECT DISTINCT * FROM artists_albums_songs
    ORDER BY artist_id, album_id, song_id ASC;
    
  6. 删除新的 artists_albums_songs[2] 并将 tmp[3] 重命名为 artists_albums_songs(通过 psql):

    DROP TABLE artists_albums_songs;
    ALTER TABLE tmp RENAME TO artists_albums_songs;
    

关于sql - INSERT ... 在发生冲突时什么都不做 - 读取 csv 并生成外键表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42451093/

相关文章:

mysql - 想要 mysql 中给定表的所有列的唯一值

python - 找不到页面 (404) 请求方法 : POST Request URL: http://127. 0.0.1:8000/accounts/signup/signup

javascript - 通过 JavaScript 在 ins 标签内更改值

sql - PostgreSQL 中的 "ORDER BY ... USING"子句

mysql - 使用触发器在插入时使用另一个表中的随机行集填充表

c - 从队列中提取元素然后打印元素 - 在最后一个元素上不起作用

mysql - 错误代码 : 1111. 无效使用组函数 (SQL)

php - 是否可以在选择值后添加添加数字?

php - 仅获取表中重复项的最小值

java - 如何通过eclipse将postgres连接到heroku?