【问题标题】:How to use a CSV file to update all column values in a table?如何使用 CSV 文件更新表中的所有列值?
【发布时间】:2017-04-04 07:48:04
【问题描述】:

我希望使用我导入并命名为表 songsnew 的 CSV 文件替换名为 songs 的 sqlite3 (Clementine) 数据库表中的列值。

CSV 文件包含三列,其标题的字段名称与目标数据库中的字段名称相匹配。我希望它“索引”到的常见列是filename

使用 SQLiteBrowser,我尝试了从另一个答案中获取的这个 SQL:

update songs
set lastplayed = (select songsnew.lastplayed
where songsnew.filename = songs.filename)
where
exists (
select *
from songsnew
where songsnew.filename = songs.filename
)

它没有工作。错误消息说:

no such column: songsnew.lastplayed: update songs

...这很奇怪,因为当我在 SQLite 数据库浏览器中键入该 SQL 时,它会正确识别为 songsnew 表“弹出”列 filename

使用 SQLite3 和/或 bash,这只能通过将 CSV 作为表导入来完成吗?哪种方式最简单,它是如何完成的?我不希望一次手动更新数千条记录。

根据 cmets 的要求,这里首先是架构 songs

CREATE TABLE `songs` (
    `title` TEXT,
    `album` TEXT,
    `artist`    TEXT,
    `albumartist`   TEXT,
    `composer`  TEXT,
    `track` INTEGER,
    `disc`  INTEGER,
    `bpm`   REAL,
    `year`  INTEGER,
    `genre` TEXT,
    `comment`   TEXT,
    `compilation`   INTEGER,
    `length`    INTEGER,
    `bitrate`   INTEGER,
    `samplerate`    INTEGER,
    `directory` INTEGER NOT NULL,
    `filename`  TEXT NOT NULL,
    `mtime` INTEGER NOT NULL,
    `ctime` INTEGER NOT NULL,
    `filesize`  INTEGER NOT NULL,
    `sampler`   INTEGER NOT NULL DEFAULT '0',
    `art_automatic` TEXT,
    `art_manual`    TEXT,
    `filetype`  INTEGER NOT NULL DEFAULT '0',
    `playcount` INTEGER NOT NULL DEFAULT '0',
    `lastplayed`    INTEGER,
    `rating`    INTEGER,
    `forced_compilation_on` INTEGER NOT NULL DEFAULT '0',
    `forced_compilation_off`    INTEGER NOT NULL DEFAULT '0',
    `effective_compilation` TEXT NOT NULL DEFAULT '0',
    `skipcount` INTEGER NOT NULL DEFAULT '0',
    `score` INTEGER NOT NULL DEFAULT '0',
    `beginning` INTEGER NOT NULL DEFAULT '0',
    `cue_path`  TEXT,
    `unavailable`   INTEGER DEFAULT '0',
    `effective_albumartist` TEXT,
    `etag`  TEXT,
    `performer` TEXT,
    `grouping`  TEXT
);

...这是导入后 CSV 文件 songnew 的架构:

CREATE TABLE `songsnew` (
    `filename`  TEXT,
    `playcount` TEXT,
    `lastplayed`    TEXT
);

【问题讨论】:

  • 您是如何将数据导入 SQLiteBrowser 的?如果您已导入它,则它已经存在。在sqlite3 命令行shell 中显示.schema 的输出。
  • OK - 上面已经添加了。
  • 列在那里。您是否将其导入到同一个数据库中?
  • 是的,songsnew 表与songs 在同一个数据库中。
  • 好吧,我想出了一种使用 Excel(或 LibreCalc)的粗略方法。您必须为每条更新的记录编写一行 bash 脚本。如果您要更新两列,lastplayedplaycount,您可以使用公式“自动化”脚本编写过程。对于我来说,它是 13,000 行,每行看起来像:update songs set lastplayed = 1464776851, playcount = 9 where rowid = 13643; 在 Excel 中结合引用文本(对文本使用引号,对单元格引用使用“&”)和单元格引用,然后将所有行从 Excel 复制到 bash SQLite3 命令的脚本

标签: bash csv sqlite


【解决方案1】:

这里有一个更方便的方法:

with delta(fn, pc, lp) as
(select a.filename, a.playcount, a.lastplayed from songsnew a )
update songs set 
     lastplayed = ifnull((select lp from delta where fn = filename), lastplayed),
     playcount  = ifnull((select pc from delta where fn = filename), playcount)
where filename in ( select fn from delta);

它使用

  • 用于解决歧义的 CTE,
    with delta(fn, pc, lp) as ...
  • 一种用于填充歌曲中可能没有的值的构造new,
    ifnull(...)
  • 一个 where 子句来加速,
    (ifnull 结构也会阻止其他地方的更改,但速度要慢得多)

您可能希望通过songsnew.playcount 增加songs.playcount,在这种情况下使用 playcount = ifnull((select playcount+pc from delta where fn = filename), playcount).

在 SQLite 3.18.0 2017-03-28

【讨论】:

    猜你喜欢
    • 2020-07-25
    • 1970-01-01
    • 2021-12-14
    • 2020-08-30
    • 1970-01-01
    • 1970-01-01
    • 2017-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多