SQL使用union在三个表之间保持连接

时间:2013-09-12 08:25:00

标签: sql postgresql join

我有许多品牌的产品,用户可以喜欢(多对多),用户也可以关注品牌。对于主页,我需要用户添加到收藏夹的所有产品以及用户跟随的品牌产品。

我已经提供了以下SQL查询,但是它的工作方式并不像预期的那样 - 它只返回来自后续品牌并且在收藏夹中同时出现的产品。

SELECT * FROM products
INNER JOIN favorites ON products.id = favorites.favorable_id
INNER JOIN followings ON products.merchant_id = followings.followable_id
WHERE favorites.favorable_type = 'Product' AND favorites.user_id = ?
AND followings.followable_type = 'Merchant' AND followings.user_id = ?

如何正确修复查询? 提前谢谢。

编辑: 我将拥有10k +产品,1k +用户。所以我需要最快的执行时间查询。

5 个答案:

答案 0 :(得分:3)

一种“简单”方法(仅修改现有查询)可能是将INNER JOIN转换为LEFT JOIN并检查at least one of the two joined successfully中的WHERE子句...

SELECT
  *
FROM
  products
LEFT JOIN
  favorites
    ON  products.id = favorites.favorable_id
    AND favorites.favorable_type = 'Product'
    AND favorites.user_id = ?
LEFT JOIN
  followings
    ON  products.merchant_id = followings.followable_id
    AND followings.followable_type = 'Merchant'
    AND followings.user_id = ?
WHERE
      favorites.user_id IS NOT NULL
  OR followings.user_id IS NOT NULL

这样做的缺点是product表中的 每条 记录都必须由WHERE子句检查。

如果该表很小,或者您通常以任何方式返回表的“大”部分,这可能没问题。但是,如果您只返回表格的“小”部分,则可能需要对此进行优化,例如使用UNION的两个查询,如问题标题所暗示的那样......

SELECT
  products.*
FROM
  products
INNER JOIN
  favorites
    ON  products.id = favorites.favorable_id
    AND favorites.favorable_type = 'Product'
    AND favorites.user_id = ?

UNION

SELECT
  products.*
FROM
  products
INNER JOIN
  followings
    ON  products.merchant_id = followings.followable_id
    AND followings.followable_type = 'Merchant'
    AND followings.user_id = ?

此处的INNER JOIN每个LEFT JOIN可能明显快于基于followings(user_id, followable_type)的整个查询,因为可能会使用favorites(user_id, favorable_type)和{{1}}上的索引。

答案 1 :(得分:0)

尝试替换

 INNER JOIN followings ON products.merchant_id = followings.followable_id

left JOIN followings ON favorites.favorable_id = followings.followable_id

答案 2 :(得分:0)

select p.*
from products as p
where
    exists (
       select *
       from favorites as f
       where f.favorable_id = p.id and f.favorable_type = 'Product' and f.user_id = ?
    ) or
    exists (
       select *
       from followings as f
       where f.followable_id = p.merchant_id and f.followable_type = 'Merchant' and f.user_id = ?
    )

答案 3 :(得分:0)

SELECT * FROM products p
LEFT JOIN favorites ON products.id = favorites.favorable_id and favorites.favorable_type = 'Product' AND favorites.user_id = ?
LEFT JOIN followings ON products.merchant_id = followings.followable_id and followings.followable_type = 'Merchant' AND followings.user_id = ?
WHERE favorites.user_id is not null or followings.user_id is not null

答案 4 :(得分:0)

你可以试试这个:

select p.*
from products as p
where
p.id in (
       select f.favorable_id
       from favorites as f
       where  f.favorable_type = 'Product' and f.user_id = ?
)
or p.merchant_id in ( 
       select f.followable_id
       from followings as f
       where  f.followable_type = 'Merchant' and f.user_id = ?
)