比较 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
假设我有一部电影 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(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