插入虚拟行'在带有聚合函数的SQL中

时间:2016-05-25 18:13:27

标签: postgresql

我有一个包含以下字段的表:

公司 水果 日期 数量 价钱 TOTAL_PRICE

我有一个总结数据的查询:

Person per= (Person) criteria.uniqueResult();
per.setCreatedOn("crtBy");
currentSession.merge(per);

如果某个公司一年没有数据,我将如何将虚拟行包含在输出中?在我的时间框架内的四分之一?

1 个答案:

答案 0 :(得分:0)

这有点复杂,所以让我引导你完成它。首先,您需要一个公司列表,包括没有购买的公司。您可以通过以下方式获得:

SELECT DISTINCT company
FROM fruit_paid;

您可以使用它来获取所有公司的摘要,所有这些都是这样的:

WITH
  company_names as
    (SELECT DISTINCT company
     FROM fruit_paid)

SELECT company_names.company, sum(fruit_paid.qty) as total_fruit_purchased
FROM company_names
  LEFT OUTER JOIN fruit_paid
    ON company_names.company = fruit_paid.company
GROUP BY company_names.company;

那里有两件事情:1-我采取之前的查询(" SELECT DISTINCT ..."),并将其称为公共表表达式 - 它只是意味着我可以像表一样使用该查询。 2-我使用LEFT OUTER JOIN,它将使用左表定义行,并从右表中加入所有内容。

这是完成这项工作所需要的核心。您可以使用generate_series函数获取年份列表。类似的东西:

SELECT extract(YEAR from generate_series) as year
FROM generate_series('2015-01-01'::date,
                     '2016-01-01'::date,
                     '1 year');

您可以转身并添加到上一个查询:

WITH
  company_names as
    (SELECT DISTINCT company
     FROM fruit_paid),
  years as
    (SELECT extract(YEAR from generate_series) as year
     FROM generate_series('2015-01-01'::date,
                          '2016-01-01'::date,
                          '1 year'))

SELECT company_names.company,
       years.year,
       sum(fruit_paid.qty) as total_fruit_purchased
FROM company_names
  CROSS JOIN years
  LEFT OUTER JOIN fruit_paid
    ON company_names.company = fruit_paid.company
    AND extract(YEAR from fruit_paid.date) = years.year
GROUP BY company_names.company, years.year;

使用CROSS JOIN,左表(company_names)和右表(years)的每个组合可以获得一行。换句话说,每个公司和年份一行,无论购买。您再次与fruit_paid联系以获取购买数据。

最后一块是宿舍。获得所有季度的列表是一种简单的方法:

VALUES ('Q1'), ('Q2'), ('Q3'), ('Q4');

所以,让我们加入:

WITH
  company_names as
    (SELECT DISTINCT company
     FROM fruit_paid),
  years as
    (SELECT extract(YEAR from generate_series) as year
     FROM generate_series('2015-01-01'::date,
                          '2016-01-01'::date,
                          '1 year')),
  quarters (quarter) as
    (VALUES ('Q1'), ('Q2'), ('Q3'), ('Q4'))

SELECT company_names.company,
       years.year,
       quarters.quarter,
       sum(fruit_paid.qty) as total_fruit_purchased
FROM company_names
  CROSS JOIN years
  CROSS JOIN quarters
  LEFT OUTER JOIN fruit_paid
    ON company_names.company = fruit_paid.company
    AND extract(YEAR from fruit_paid.date) = years.year
    AND quarters.quarter = case
                             WHEN extract(MONTH FROM date) <= 3
                               THEN 'Q1'
                             WHEN extract(MONTH FROM date) BETWEEN 4 AND 6
                               THEN 'Q2'
                             WHEN extract(MONTH FROM date) BETWEEN 7 AND 9
                               THEN 'Q3'
                             WHEN extract(MONTH FROM date) BETWEEN 10 AND 12
                               THEN 'Q4'
                             ELSE 'UNKNOWN'
                           END
GROUP BY company_names.company, years.year, quarters.quarter;

我们在这里做的唯一新奇事情是为quarters公用表表达式提供更多定义 - 我们添加了一个列名。对于像VALUES这样的伪查询,能够为返回的列定义名称是很方便的,并且它使得查询稍后可以理解(否则我们将加入{{1 ,这很难理解。)

希望有所帮助。

以下是一些相关文档: