sql - 创建连接多个表的数据库 View

标签 sql postgresql database-view

我想在创建数据库 View 方面获得一些帮助。 我的数据库架构如下所示:

products            (id, ignored_comments_ids (array))
activities          (id)
comments            (id)
activities_comments (activity_id comment_id)
products_comments   (product_id, comment_id)
offers              (product_id, activity_id)

现在我需要使用名为 source 的自定义列创建所有产品评论的 View :

  • source = 'OFFER': 评论来自 products.offers.activities.comments 关联
  • 来源 = '直接': 来自 products.comments 协会的评论

    此外,该 View 应排除来自 products.ignored_comments_ids

    的评论

我该怎么做?该 View 必须包含 product_idsourcecomments 表中的所有列。

我想到了以下观点,我该如何改进它?

CREATE OR REPLACE VIEW all_comments AS
  WITH the_comments AS (
    SELECT
      comments.*,
      'OFFER'     AS source,
      products.id AS product_id
    FROM comments
    JOIN activities_comments ON activities_comments.comment_id = comments.id
    JOIN activities          ON activities.id = activities_comments.activity_id
    JOIN offers              ON offers.activity_id = activities.id
    JOIN products            ON products.id = offers.product_id
  UNION
    SELECT
      comments.*,
      'DIRECT'    AS source,
      products.id AS product_id
    FROM comments
    JOIN products_comments ON products_comments.comment_id = comments.id
    JOIN products          ON products.id = products_comments.product_id
  )
  SELECT DISTINCT ON (the_comments.id)
    the_comments.id,
    the_comments.name,
    the_comments.source,
    the_comments.product_id
  FROM the_comments
  JOIN products ON products.id = the_comments.product_id
  WHERE NOT to_json(products.ignored_comment_ids)::jsonb @> the_comments.id::jsonb
  ORDER BY the_comments.id;

最佳答案

UNION 可用于合并 2 组数据,AND,同时它会删除重复的行。 UNION ALL 可用于合并 2 组数据(然后停止)。所以 UNION ALL 避免了搜索和删除重复行的开销,因此速度更快。

在您的初始公用表表达式 (cte) the_comments 中,您强制联合的每一侧使用不同的常量,例如

select *
from (
    select 1 as id, 'OFFER' AS source
    union
    select 1 as id, 'DIRECT' AS source
    ) d
;
result:
  id   source  
 ---- -------- 
   1   DIRECT  
   1   OFFER 

即使 id 1 在该联合的两边,由于常量不同,该示例查询返回 2 行。所以请改用UNION ALL

尽管 select * 很方便,但不应在 View 中使用它(尽管两种方式都有参数,例如 here )。也许这样做是为了简化问题,但我希望它不会像看到的那样按字面意思使用。如果 View 的目的是仅返回 4 列,则仅指定这些列。

虽然您需要在输出中使用 product_id,但这可以从 offers.product_idproducts_comments.product_id 中获取,因此您实际上不需要加入产品表.在 cte 之后也不需要连接到产品表。

因为我们现在正在使用 UNION ALL 我看不到使用 SELECT DISTINCT ON(...) 有任何好处,我怀疑这只是可以删除的开销。显然我无法验证这一点,它可能完全取决于您的功能要求。另请注意,SELECT DISTINCT ON(...) 将删除您精心引入的 source,例如

select distinct on (id) id, source
from (
    select 1 as id, 'OFFER' AS source
    union
    select 1 as id, 'DIRECT'AS source
    ) d
;
result:
  id   source  
 ---- -------- 
   1   DIRECT   

不要在任何 View 中包含 order by 子句,仅排序“最终查询”。换句话说;如果您创建了一个 View ,那么您很可能会在其他几个查询中使用它。这些查询中的每一个都可能有自己的 where 子句并且需要不同的结果顺序。如果您订购 View ,您只是在消耗 cpu 周期,然后在稍后放弃该工作。所以,请删除 order by 子句。

我非常想为最后的 where 子句建议一种不同的方法,但由于我不怎么处理 JSON,所以我没有足够的经验来提出替代方案。但是,在 where 子句中对数据使用函数几乎总是性能不佳的原因,最显着的原因是它通常会删除对这些函数中涉及的列的索引的访问。找到一种更有效的方法来排除评论异常可能会最大程度地提高您的查询性能。

所以,我的建议是这样的:

WITH the_comments
AS (
    SELECT
        comments.id
      , comments.name
      , 'OFFER' AS source
      , offers.product_id AS product_id
    FROM comments
    JOIN activities_comments ON activities_comments.comment_id = comments.id
    JOIN activities ON activities.id = activities_comments.activity_id
    JOIN offers ON offers.activity_id = activities.id
    UNION ALL
    SELECT
        comments.id
      , comments.name
      , 'DIRECT' AS source
      , products_comments.product_id AS product_id
    FROM comments
    JOIN products_comments ON products_comments.comment_id = comments.id
    )
SELECT
    the_comments.id
  , the_comments.name
  , the_comments.source
  , the_comments.product_id
FROM the_comments
/* perhaps raise a separate question on this bit */
WHERE NOT to_json(products.ignored_comment_ids)::jsonb @> the_comments.id::jsonb

关于sql - 创建连接多个表的数据库 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52696909/

相关文章:

node.js - 带有 elasticsearch 的 Postgres(保持同步)- nodeJS

sql - SQL表插入小数时溢出错误

sql - 在子句中使用子选择列表优化 sql 查询

Java Hibernate H2-sql 数据库

sql - 如果索引列不同,则对一列的值求和?

postgresql - psql: FATAL: 数据库 "<user>"不存在

postgresql - SymmetricDS - 在转换时添加节点 ID

database - H2 数据库 : How to list all views?

java - 没有实体主键的 JPA map View