执行两个 GROUP BY 的 SQL 查询?

标签 sql ruby-on-rails postgresql

我在获取需要生成的报告的 SQL 时遇到问题。我有以下设置(等效):

  • 表格articles(名称、manufacturer_id等字段)。
  • 表格销售
    • FK 名为 article_id 的文章
    • 一个名为金额的整数
    • 日期字段
    • 名为type的字段。我们可以假设它是一个字符串,并且可以有 3 个已知值 - 'morning''evening''night'

我想在给定开始日期和结束日期的情况下生成汇总销售报告:

 +--------------+---------------+--------------+-------------+
 | article_name | morning_sales | evening_sales| night_sales |
 +--------------+---------------+--------------+-------------+
 | article 1    |             0 |           12 |           2 |
 | article 2    |            80 |            3 |           0 |
...            ...             ...            ...           ...
 | article n    |            37 |           12 |           1 |
 +--------------+---------------+--------------+-------------+

我想尽可能高效地完成这件事。到目前为止,我已经能够生成一个查询,该查询将为我提供一种类型的销售(早上、晚上或晚上),但我无法同时为多种类型执行此操作。这可能吗?

这是我到目前为止所拥有的;它会给我指定时间段内所有文章的文章名称和早间销售额 - 换句话说,报告的前两列:

SELECT articles.name as article_name,
       SUM(sales.amount) as morning_sales,
FROM "sales"
INNER JOIN articles ON articles.id = sales.articles_id
WHERE ( sales.date >= '2011-05-09'
    AND sales.end_date <= '2011-05-16'
    AND sales.type = 'morning'
)
GROUP BY sales.article_id

我想我可以在晚上和晚上做同样的事情,但文章会有所不同;例如,有些文章可能会在早上销售,但晚上不会销售。

  • 如果我必须为每种销售类型执行 1 个请求,我该如何“混合搭配”我将获得的不同文章列表?
  • 是否有更好的方法来做到这一点(也许使用某种子查询)?

同样,我可以构建一个查询,为我提供所有早间、晚间和晚间的销售情况,并按类型分组。我想我的问题是我需要执行两次 GROUP BY 才能获得此报告。如果可能的话,我不知道该怎么做。

我使用 PostgreSQL 作为我的数据库,但我想尽可能保持标准。如果有帮助,则使用它的应用程序是 Rails 应用程序。

最佳答案

幸运的是,您不需要使用数据库格式进行多次查询。这应该适合你:

SELECT
  articles.name AS article_name
  SUM(IF(sales.type = 'morning', sales.amount, 0.0)) AS morning_sales,
  SUM(IF(sales.type = 'evening', sales.amount, 0.0)) AS evening_sales,
  SUM(IF(sales.type = 'night', sales.amount, 0.0)) AS night_sales
FROM sales
  JOIN articles ON sales.article_id = articles.id
WHERE
  sales.date >= "2011-01-01 00:00:00"
  AND sales.date < "2011-02-01 00:00:00"
GROUP BY sales.article_id

如果有其他类型,您必须在那里添加更多列,或者通过将其添加到 SELECT 子句来简单地总结其他类型:

SUM(
  IF(sales.type IS NULL OR sales.type NOT IN ('morning', 'evening', 'night'), 
    sales.amount, 0.0
  )
) AS other_sales

以上兼容MySQL。要在 Postgres 中使用它,我认为您必须将 IF 表达式更改为 CASE expressions ,它应该看起来像这样(未经测试):

SELECT
  articles.name AS article_name,
  SUM(CASE WHEN sales.type = 'morning' THEN sales.amount ELSE 0.0 END) AS morning_sales,
  SUM(CASE WHEN sales.type = 'evening' THEN sales.amount ELSE 0.0 END) AS evening_sales,
  SUM(CASE WHEN sales.type = 'night' THEN sales.amount ELSE 0.0 END) AS night_sales
FROM sales
  JOIN articles ON sales.article_id = articles.id
WHERE
  sales.date >= "2011-01-01 00:00:00"
  AND sales.date < "2011-02-01 00:00:00"
GROUP BY sales.article_id

关于执行两个 GROUP BY 的 SQL 查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5942854/

相关文章:

ruby-on-rails - 让 Devise AJAX 登录使用可确认

ruby-on-rails - 用于重复事件的 gem ice_cube

postgresql - psql 可以连接到 unix 域套接字,但是具有相同参数的 py-postgresql 得到 'Permission denied'

PostgreSQL citext 索引与较低的表达式索引性能

sql - 对相同 ID 列的列值进行增量求和

Mysql列作为sql server中的vColumn语法

ruby-on-rails - 格式化 Rails 控制台输出

postgresql - 如何使用 gin 在 PostgreSQL 中的非字符类型数据上创建 tsvector_update_trigger?

sql - 如何使用 CodeIgniter 运行 mysqli 查询?

sql - 字符串匹配在 PostgreSQL 9.5 数组中的位置