如何在Supabase中按关联流派过滤乐队并保留全部流派信息?
问题描述
假设存在bands表与genres表,二者通过关联表j_band_genres建立连接,现有数据如下:
| ID | 乐队名称 | 流派 |
|---|---|---|
| 1 | The Beatles | Pop, Rock |
| 2 | The Rolling Stones | Rock |
| 3 | Boney M. | Funk, Disco |
现需筛选出摇滚乐队,按Supabase文档编写的查询如下:
const { data, error } = await supabase .from('bands') .select(` *, genres:j_band_genres!inner ( name ) `) .eq('genres.name', 'Rock')
使用!inner关键字后,成功筛选出The Beatles和The Rolling Stones,但流派信息被过滤,The Beatles的Pop流派丢失,结果如下:
| ID | 乐队名称 | 流派 |
|---|---|---|
| 1 | The Beatles | Rock |
| 2 | The Rolling Stones | Rock |
请问在Supabase或PostgreSQL中,能否实现按流派过滤乐队的同时保留乐队的全部流派信息?
解决方案
完全可以实现,核心是先筛选出符合条件的乐队,再完整查询这些乐队的所有流派,而非直接通过内连接过滤关联数据。
方法1:Supabase JavaScript客户端实现
用exists子查询判断乐队是否关联摇滚流派,同时正常查询所有流派信息:
const { data, error } = await supabase .from('bands') .select(` *, genres:j_band_genres ( name ) `) .exists((q) => q.from('j_band_genres') .select('id') .eq('band_id', 'bands.id') .eq('genre_id', (q2) => q2.from('genres') .select('id') .eq('name', 'Rock') ) )
这个查询先通过exists确认乐队属于摇滚流派,再返回该乐队的完整信息(包括所有流派),最终The Beatles会同时显示Pop和Rock流派。
方法2:PostgreSQL原生SQL实现
直接写SQL的话,用EXISTS子查询结合关联聚合:
SELECT bands.*, ARRAY_AGG(genres.name) AS genres FROM bands JOIN j_band_genres ON bands.id = j_band_genres.band_id JOIN genres ON j_band_genres.genre_id = genres.id WHERE EXISTS ( SELECT 1 FROM j_band_genres jbg JOIN genres g ON jbg.genre_id = g.id WHERE jbg.band_id = bands.id AND g.name = 'Rock' ) GROUP BY bands.id;
该SQL先筛选出关联摇滚流派的乐队,再聚合这些乐队的所有流派名称,返回完整的流派列表。
原方法丢失流派的原因
之前用!inner关联并过滤genres.name = 'Rock',本质是内连接+过滤,只会保留关联表中匹配摇滚流派的记录,所以The Beatles的Pop流派被过滤掉。而exists仅做存在性判断,不影响后续关联查询的全部数据,因此能保留所有流派。
内容的提问来源于stack exchange,提问作者peperoli
相关产品推荐
相关产品推荐

