Postgres COUNT 个带有 INNER JOIN 的列值

Posted

技术标签:

【中文标题】Postgres COUNT 个带有 INNER JOIN 的列值【英文标题】:Postgres COUNT number of column values with INNER JOIN 【发布时间】:2015-10-09 11:29:33 【问题描述】:

我正在 Postgres 9.3 中创建报告。这是我的SQL Fiddle。 基本上我有两张表,responsesquestions,结构是:

responses
->id
->question_id
->response

questions
->id
->question
->costperlead

response 列只能有 3 个值,Yes/No/Possbily, 我的报告应该有以下列:

  question_id
, # of Yes Responses
, # of No Responses
, # of Possbily Responses
, Revenue

然后:

# of Yes Responses - count of all Yes values in the response column
# of No Responses - count of all No values in the response column
# of Possbily Responses - count of all 'Possbily' values in the response column

收入是costperlead *(是响应的数量 + 可能响应的数量)。

我不知道如何构建查询,我是新来的,而且我来自 mysql,所以对于 postgres,有些事情是不同的。在我的 SQL Fiddle 示例中,大多数响应是 Yes 和 Null,最终没关系,会有可能和 No。

到目前为止,我只有:

SELECT a.question_id
FROM responses a
INNER JOIN questions b ON a.question_id = b.id
WHERE a.created_at = '2015-07-17'
GROUP BY a.question_id;

【问题讨论】:

【参考方案1】:

由于唯一的谓词过滤表 responses 中的行,因此首先聚合响应,然后加入问题是最有效的:

SELECT *, q.costperlead * (r.ct_yes + r.ct_maybe) AS revenue
FROM  (
   SELECT question_id
        , count(*) FILTER (WHERE response = 'Yes')      AS ct_yes
        , count(*) FILTER (WHERE response = 'No')       AS ct_no
        , count(*) FILTER (WHERE response = 'Possibly') AS ct_maybe
   FROM   responses
   WHERE  created_at = '2015-07-17'
   GROUP  BY 1
   ) r
JOIN   questions q ON q.id = r.question_id;

db小提琴here

这使用聚合 FILTER 子句(在 Postgres 9.4 或更高版本中)。见:

Aggregate columns with additional (distinct) filters

另外:考虑将response 实现为boolean 类型和true/false/null

对于 Postgres 9.3

SELECT *, q.costperlead * (r.ct_yes + r.ct_maybe) AS revenue
FROM  (
   SELECT question_id
        , count(response = 'Yes' OR NULL)      AS ct_yes
        , count(response = 'No' OR NULL)       AS ct_no
        , count(response = 'Possibly' OR NULL) AS ct_maybe
   FROM   responses
   WHERE  created_at = '2015-07-17'
   GROUP  BY 1
   ) r
JOIN   questions q ON q.id = r.question_id;

旧sqlfiddle

技术综合对比:

For absolute performance, is SUM faster or COUNT?

【讨论】:

[Err] 错误:在 "(" LINE 5: , count(*) FILTER (WHERE r.response = 'Yes') AS ct_y...处或附近出现语法错误... @JoeneFloresca:我为 pg 9.3 添加了一个解决方案。 哇,非常感谢您的帮助和解释,它工作正常,但最后一个问题,您的 GROUP BY 1?为什么是1?或者我需要那个吗? @JoeneFloresca:在您的小提琴中,您没有“可能”的值,只有 NULL。这与问题相矛盾? GROUP BY 1 是具有位置引用的简写语法,如下所述:***.com/a/10398558/939860 是的,你是对的,但如果永远不会是 NULL 值?在不影响结果准确性的情况下使用 GROUP BY 1 还可以吗?【参考方案2】:

你应该试试:

SELECT a.question_id, 
       SUM(CASE WHEN a.response = 'Yes' THEN 1 ELSE 0 END) AS NumsOfYes, 
       SUM(CASE WHEN a.response = 'No' THEN 1 ELSE 0 END) AS NumsOfNo,
       SUM(CASE WHEN a.response = 'Possibly' THEN 1 ELSE 0 END) AS NumOfPossibly,
       costperlead  * SUM(CASE WHEN a.response = 'Yes' THEN 1 ELSE 0 END) + SUM(CASE WHEN a.response = 'Possibly' THEN 1 ELSE 0 END) AS revenue
FROM responses a 
     INNER JOIN questions b ON a.question_id = b.id 
GROUP BY a.question_id, b.costperlead

【讨论】:

我收到一个错误,先生,错误:b.response 列不存在位置:29 感谢您帮助先生,但似乎给了我不正确的结果,因为如果您检查响应表 question_id = 44 有 2 个回答是,那么其他人为空,但根据您的查询结果给出 2是、否和可能? 这会错误地使用聚合函数count(),它会计算除NULL 之外的所有值。表达式产生true 还是falsecount() 无关。 使用 SUM 修改。 您好,非常感谢它运作良好,但@ErwinBrandstetter 对我更有效,加上解释。我会投票代替:) 谢谢!

以上是关于Postgres COUNT 个带有 INNER JOIN 的列值的主要内容,如果未能解决你的问题,请参考以下文章

带有 CASE 的 Postgres 自定义函数

Postgres INNER JOIN ERROR:模式“bar”不存在

带有 2 个 INNER JOIN 的 MYSQL 更新挂起

Postgres:如何获取多个布尔列的 json 数组?

使用 COUNT 和 INNER JOIN 选择查询

在 postgres 表中计算不为空的 json 键-> 值