【问题标题】:Select many-to-many relation with "owns" column使用“拥有”列选择多对多关系
【发布时间】:2017-08-25 17:34:38
【问题描述】:

我努力解决以下问题: 我的数据库中有 2 个表: 视频和 users_videos 作为视频和用户之间的枢纽(我从令牌接收 user_id,因此 users 表在另一个数据库中)

拥有一个用户 ID,我想选择所有视频并附加包含 true 或 false 的列,无论用户是否拥有视频。

到目前为止,我通过以下查询实现了这一点:

 SELECT v.*, TRUE AS has_video FROM users_videos AS uv
 RIGHT JOIN videos AS v
 ON uv.video_id = v.id 
 WHERE (uv.user_id = 1)
 UNION
 (
    SELECT v.*, FALSE AS has_video FROM videos AS v

    EXCEPT

    SELECT v.*, FALSE AS has_video FROM users_videos AS uv
    RIGHT JOIN videos AS v
    ON uv.video_id = v.id 
    WHERE (uv.user_id = 1) 
  )

虽然它选择了所有视频 3 次。此类问题有没有更优的解决方案?

@编辑---

表格结构

users_videos:
id integer
user_id integer
video_id integer

videos:
id: integer
title: string

示例数据:

users_videos

| id | user_id | video_id 
-------------------------
  1    1          1

视频

| id | title   | 
----------------
  1  | Example 1  
-----------------   
  2  | Example 2  
-----------------   

想要的结果:

| id | title      | has_video
------------------------------
  1  | Example 1  |   true
------------------------------   
  2  | Example 2  |   false
------------------------------

@UPDATE --

使用@Stefano Zanini 方法:

SELECT DISTINCT
        v.*,
        CASE
            WHEN uv.user_id IS NULL OR uv.user_id <> 1 THEN FALSE
            ELSE TRUE
        END has_video
FROM    videos v
LEFT JOIN
        users_videos uv
ON      uv.video_id = v.id

但我又想到了一个问题:

如果我想显示特定类别的视频怎么办? 假设这是另一个多对多关系

带有枢轴视频类别的视频和类别表

【问题讨论】:

  • 添加一些示例表数据和预期的结果 - 以及所有格式化文本。
  • 那些 RIGHT JOIN 执行为常规 INNER JOIN...
  • 更新了样本数据和结构
  • 更新问题
  • 您的意思是过滤特定类别的结果吗?还是显示每个视频的所有类别?

标签: sql postgresql many-to-many


【解决方案1】:

没有UNIONEXCEPT 也可以这样做

select distinct
        v.*,
        case
            when uv.user_id is null or uv.user_id <> 1 then false
            else true
        end has_video
from    videos v
left join
        user_videos uv
on      uv.video_id = v.id

由于您将此描述为many-to-many 关系,因此多个用户可以拥有同一视频,因此需要distinct

right 交换到left 加入只是因为我认为它更容易阅读。

编辑

要过滤特定类别的结果(根据问题编辑),您可以在where 中添加几个join 和一个条件

select distinct
        v.*,
        case
            when uv.user_id is null or uv.user_id <> 1 then false
            else true
        end has_video
from    videos v
join    videos_categories vc
on      v.id = vc.video_id
join    categories c
on      vc.category_id = c.id
left join
        user_videos uv
on      uv.video_id = v.id
where   c.category = 'someCategory'

【讨论】:

  • @StefanoZanini 我更新了我的问题,你能看看吗?
  • 用改进的解决方案编辑
  • 谢谢@StefanoZanini :)
【解决方案2】:

您想选择所有视频并为每个视频说明用户 1 是否拥有它。所以从视频中选择并查找用户的视频:

select 
  v.*,
  id in (select video_id from users_videos where user_id = 1) as has_video
from videos v;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-31
    • 1970-01-01
    • 2017-09-26
    • 2012-06-21
    • 1970-01-01
    • 2023-03-23
    • 2014-07-22
    相关资源
    最近更新 更多