减少对同一张表的查询次数

Roc*_*nja 1 postgresql postgresql-9.3

我需要使用两个表构建一些报告:

AuthorTitles: id(pk), author_id, title_id
AuthorReports: id(pk), author_id, title_id, items_sold, date
Run Code Online (Sandbox Code Playgroud)

我的报告需要输出以下内容: author_id, max_items_sold_wavg, items_sold_wavg, date

下面的代码可能有一些错误,请检查小提琴。

max_items_sold_wavg 是空闲查询的加权平均值:

WITH maxitems AS ( 
 SELECT
   at.author_id,
   at.title_id,
   max(ar.items_sold) as sold,
   ar.date::date as date
 FROM author_titles at
 LEFT JOIN author_reports ar ON ar.author_id = at.author_id AND at.title_id = ar.title_id
 GROUP BY 1, 2, 4
), totitems AS (
    SELECT
      mi.author_id
      count(ti.title_id) as total,
      count(CASE WHEN (mi.sold = 1) THEN mi.title_id END) AS sold1,
      count(CASE WHEN (mi.sold = 2) THEN mi.title_id END) AS sold2,
      count(CASE WHEN (mi.sold = 3) THEN mi.title_id END) AS sold3,
      mi.date,
    FROM maxitems mi
    GROUP BY mi.date
), itemsold AS (
   SELECT
      at.author_id
      count(at.title_id) as total,
      count(CASE WHEN (ar.items_sold = 1) THEN ar.title_id END) AS sold1,
      count(CASE WHEN (ar.items_sold = 2) THEN ar.title_id END) AS sold2,
      count(CASE WHEN (ar.items_sold = 3) THEN ar.title_id END) AS sold3,
      ar.date::date as date,
    FROM author_titles at
    LEFT JOIN author_reports ar ON ar.author_id = at.author_id AND at.title_id = ar.title_id
    GROUP BY at.author_id, ar.date::date
)
SELECT
  ti.author_id,
  ((ti.sold1 * 30 + ti.sold2 * 60 + ti.sold3 * 100) / at.title_id),
  ((is.sold1 * 30 + is.sold2 * 60 + is.sold3 * 100) / at.title_id),
  ti.date
FROM totitems ti, itemsold is
WHERE ti.author_id = is.author_id AND ti.date = is.date
Run Code Online (Sandbox Code Playgroud)

您可以注意到,在maxitems我只提取了每个标题的最大销售量,在itemsold我提取了所有标题的所有销售量,因为一个作者可以在一天内销售许多标题。

示例报告数据:

http://sqlfiddle.com/#!15/d2efc/22

我如何改进这个查询,有没有更好的方法来做,因为你可以看到我多次访问相同的数据。

Jac*_*las 5

您可以将其减少很多 - 首先要注意的是,您根本不需要author_titles表中的信息来获得结果:

select author_id
     , sum(case max_sold when 1 then 30 when 2 then 60 when 3 then 100 else 0 end)/count(*)
         max_items_sold_wavg
     , sum(sold)/count(*) items_sold_wavg  
     , created_at
from ( select author_id
            , created_at
            , sum(case items_sold when 1 then 30 when 2 then 60 when 3 then 100 else 0 end)
                sold
            , max(items_sold) max_sold
       from author_reports
       group by author_id,title_id,created_at ) z
group by author_id,created_at;
Run Code Online (Sandbox Code Playgroud)

SQLFiddle在这里