【问题标题】:INSERT ... on conflict do nothing - reading in a csv and generating foreign key tableINSERT ... 冲突时什么都不做 - 读取 csv 并生成外键表
【发布时间】:2017-07-16 00:29:42
【问题描述】:

我正在尝试读取包含艺术家、专辑、歌曲和标签列的 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 语句中插入此表的最佳方法是什么(返回语法错误)?谢谢。

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?

【问题讨论】:

    标签: sql postgresql insert duplicates conflict


    【解决方案1】:

    编辑 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)填充 new 表[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] 中的不同 行插入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;
      

    【讨论】:

      【解决方案2】:

      此行有错误:

       ON DUPLICATE (artist_id, album_id, song_id) DO NOTHING;
      

      Postgtresql 使用ON CONFLICT 关键字 https://www.postgresql.org/docs/current/static/sql-insert.html

      【讨论】:

        猜你喜欢
        • 2014-01-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多