比较 MySQL 中的列表

Comparing lists in MySQL

假设我有一部电影 table 和一种类型 table。通过多对多关系链接。

TABLE movie
id
name

_

TABLE movie_genre
movie_fk
genre_fk

_

TABLE genre
id
name

太好了,标准化了。但我还将 CSV 文件导入 table,格式为:

TABLE csv
name, genres 
'Die Hard', 'action~drama'

现在我想检查更改,csv 是否列出了我没有的流派,反之亦然,所以我向用户显示更改并稍后同步它们

我是这样做的:

SELECT * FROM movie 
JOIN movie_genre ON movie.id = movie_genre.movie_fk 
JOIN genre ON genre.id = movie_genre.genre_fk 
WHERE 
FIND_IN_SET(genre.name, REPLACE(csv.genres, '~', ',')) = 0 

问题是这只会以一种方式标记更改。例如。 如果在我的数据库中我有与类型相关的虎胆龙威: 动作、剧情

并且 CSV 包含 动作,剧情,恐怖

因为我数据库中的每个类型都包含在 csv 数据中,所以它不会被标记为更改。

请注意,csv 中列出的流派可能未按任何特定顺序列出。

希望我已经解释得够透彻了。

我怎样才能实现我想要做的事情?可以使用 REGEX 或自定义 MySQL 函数来完成吗?

FIND_IN_SET是判断一个元素是否在集合中。您还打算找到另一个 table 中缺少的元素。因此,我会将 csv table 修改为

的形式,而不是未规范化的 CSV 导入结果

csv(movie_id, genre_id)

并生成将插入它的导入代码。因此,您可以按如下方式检查差异(未经测试的代码):

(
select movie_id, genre_id, "missing" as status
from csv
where not exists (select 1 from movie_genre where movie_genre.movie_fk = csv.movie_id and movie_genre.genre_fk = csv.genre_id)
)
union
(
select movie_fk as movie_id, genre_fk as genre_id, "surplus" as status
from movie_genre
where not exists (select 1 from csv where movie_genre.movie_fk = csv.movie_id and movie_genre.genre_fk = csv.genre_id);
)

您也可以执行更改:

insert into movie_genre(movie_fk, genre_fk)
select movie_id, genre_id
from csv
where not exists (select 1 from movie_genre where movie_genre.movie_fk = csv.movie_id and movie_genre.genre_fk = csv.genre_id)

delete
from movie_genre
where where not exists (select 1 from csv where movie_genre.movie_fk = csv.movie_id and movie_genre.genre_fk = csv.genre_id);

如果有人感兴趣,这不是最优雅的解决方案,但我通过执行以下操作解决了这个问题:

  • 首先我更新了导入代码以确保导入的流派列表列按字母顺序排序。
  • 然后我更新了查询以对 group_concat
  • 的结果进行直接字符串比较

_

SELECT * FROM movie 
LEFT JOIN 
( 
SELECT GROUP_CONCAT(genre.name ORDER BY genre.name SEPERATOR "~") AS genres, movie_genre.movie_fk FROM genre 
JOIN movie_genre ON genre.id = movie_genre.genre_fk 
GROUP BY movie_genre.movie_fk
) AS sub_genres ON movie.id = sub_genres.movie_fk
WHERE sub_genres.genres != csv.genres