【问题标题】:Sum of alias columns in PostgreSQLPostgreSQL 中别名列的总和
【发布时间】:2021-08-10 19:48:50
【问题描述】:

我有一个聚合三个结果列的查询:

pending_with_documents
pending_without_documents
inprocessing

SELECT COUNT(DISTINCT (CASE
                           WHEN status_code IN ('ACK', 'INT') THEN
                               CASE
                                   WHEN ack_no IN
                                        (SELECT ack_no FROM bescom_appl_upload_doc) THEN ack_no END
    END))        AS pending_with_documents,
       COUNT(DISTINCT (CASE
                           WHEN status_code IN ('ACK', 'INT') THEN
                               CASE
                                   WHEN ack_no NOT IN
                                        (SELECT ack_no FROM bescom_appl_upload_doc) THEN ack_no END
           END)) AS pending_without_documents,
       COUNT(CASE
                 WHEN status_code NOT IN ('ACK', 'INT', 'APR', 'REJ', 'SBK', 'OBJ') THEN
                     ack_no
           END)  AS Inprocessing
FROM application_ht_install
WHERE service_code IN (36);

现在我需要一个第四列total来总结这三个。所以我尝试了:

SELECT COUNT(DISTINCT (CASE
                           WHEN status_code IN ('ACK', 'INT') THEN
                               CASE
                                   WHEN ack_no IN
                                        (SELECT ack_no FROM bescom_appl_upload_doc) THEN ack_no END
    END))                             AS pending_with_documents,
       COUNT(DISTINCT (CASE
                           WHEN status_code IN ('ACK', 'INT') THEN
                               CASE
                                   WHEN ack_no NOT IN
                                        (SELECT ack_no FROM bescom_appl_upload_doc) THEN ack_no END
           END))                      AS pending_without_documents,
       COUNT(CASE
                 WHEN status_code NOT IN ('ACK', 'INT', 'APR', 'REJ', 'SBK', 'OBJ')
                     THEN ack_no END) AS Inprocessing
    SUM((COUNT(DISTINCT(CASE WHEN status_code IN ('ACK','INT') THEN
    CASE WHEN ack_no IN
    (SELECT ack_no FROM bescom_appl_upload_doc) THEN ack_no END
    END)) AS pending_with_documents )+ ( COUNT(DISTINCT(CASE WHEN status_code  IN ('ACK','INT') THEN
    CASE WHEN ack_no NOT IN
    (SELECT ack_no FROM bescom_appl_upload_doc) THEN ack_no END
    END)) AS pending_without_documents)+ ( COUNT(CASE WHEN status_code NOT IN('ACK','INT','APR','REJ','SBK','OBJ') THEN
    ack_no
    END) AS Inprocessing))
FROM application_ht_install
WHERE service_code IN (36);

但我收到一个错误:

ERROR:  syntax error at or near "sum"
LINE 13: sum((count(distinct(case when status_code in ('ACK','INT') t...
              ^ SQL state: 42601 Character: 473

这三个派生列如何相加?

【问题讨论】:

  • 编写一个外部查询,其中您的查询是FROM 列表中的子查询,并在thatbouter 查询中添加列?
  • 从实际的、精确的表定义开始(CREATE TABLE 语句)——这很重要! (如果涉及任何 NULL 值,NOT IN 可能不会做你认为它正在做的事情......)而且总是你的 Postgres 版本。

标签: sql postgresql aggregate aggregate-filter


【解决方案1】:

您的语句中有几个语法错误。您正在为不需要别名的事物添加别名。 这是纠正了语法错误的代码。注意:有一列没有别名,所以我称它为“do_not_know_name”,因为我不知道你的意思。

select 
count(distinct(case when status_code in ('ACK','INT') then 
case when ack_no in
(select ack_no from bescom_appl_upload_doc) then ack_no end 
end)) as pending_with_documents ,
count(distinct(case when status_code  in ('ACK','INT') then 
case when ack_no not in
(select ack_no from bescom_appl_upload_doc) then ack_no end 
end)) as pending_without_documents ,
count(case when status_code not in('ACK','INT','APR','REJ','SBK','OBJ') 
then ack_no end) as Inprocessing,
sum((count(distinct(case when status_code in ('ACK','INT') then 
case when ack_no in
(select ack_no from bescom_appl_upload_doc) then ack_no end 
end))  )+ ( count(distinct(case when status_code  in ('ACK','INT') then 
case when ack_no not in
(select ack_no from bescom_appl_upload_doc) then ack_no end 
end)) )+ ( count(case when status_code not in('ACK','INT','APR','REJ','SBK','OBJ') then 
ack_no
end) )) as do_not_know_name
from application_ht_install where service_code in (36) 

【讨论】:

  • 我在他的查询中看到了几个嵌套聚合调用,我认为嵌套聚合调用是不允许的。 sum((count(distinct(case)) )+ ( count(distinct 中的两个。对不对?
  • @dinidu:不是 100% 肯定,我没有包含数据的表的 DDL,但至少我们克服了语法错误。希望 OP 会尝试这个,看看它是否有效,或者回来提供更多反馈——在不知道数据的情况下,如果没有更多信息,很难提出替代方案。认为这是获得更多的最简单方法。
  • 此外,您可以在技术上使用嵌套聚合,但前提是在运行之前解析为单个值... aka: select sum((select avg(some_column) from some_other_source)) from some_table
【解决方案2】:

基本上,您可以重复冗长的表达式,或者将所有内容放在子查询中并在外部SELECT 中求和。我建议后者:

SELECT pending_with_documents
     , pending - pending_with_documents AS pending_without_documents
     , inprocessing
     , pending + inprocessing AS total
FROM  (
   SELECT count(DISTINCT a.ack_no) FILTER (WHERE status_code IN ('ACK', 'INT'))              AS pending
        , count(DISTINCT b.ack_no) FILTER (WHERE status_code IN ('ACK', 'INT'))              AS pending_with_documents
        , count(ack_no) FILTER (WHERE status_code <> ALL ('{ACK, INT, APR, REJ, SBK, OBJ}')) AS inprocessing
   FROM   application_ht_install a
   LEFT   JOIN (SELECT DISTINCT ack_no FROM bescom_appl_upload_doc) b USING (ack_no)
   WHERE  service_code = 36
   ) sub;

这个可能做你想做的事。取决于实际的表定义。如果任一表中的ack_nostatus_code 可以是NULL,您可能需要做更多。见:

此外,子查询的LEFT JOIN 可能更有效,也可能不会更有效,具体取决于未公开的架构详细信息和基数。

&lt;&gt; ALL (&lt;array&gt;) 等价于 NOT IN (&lt;list&gt;),但对于较长的列表来说更短,通常表现更好。当涉及 NULL 时,两者都失败...

关于更高效的FILTER 子句替换嵌套的CASE 表达式:

注意在内部SELECT 列表中使用a.ack_nob.ack_noack_noa.ack_noUSING 子句左连接后实际上等同于 ack_no。我只是为了对称才拼出来的。

count(DISTINCT b.ack_no) 有效,因为 count() 不计算 NULL 值 - 如果 bescom_appl_upload_doc 中不存在 b.ack_no,您将获得这些值。

【讨论】:

  • 非常感谢您先生...您救了我,但我仍然很难理解您的简化代码。但我会明白的。再次感谢您花时间帮助我。建议我一些快速学习 postgresql 的方法,如果你有的话。
  • @krickX:我不是这个特定问题的专家,因为我在上个千年开始使用 Postgres。优秀的手册和 stackoverflow 肯定会有所帮助。
  • 当然...谢谢
猜你喜欢
  • 2011-11-22
  • 1970-01-01
  • 2022-01-23
  • 2018-05-14
  • 1970-01-01
  • 1970-01-01
  • 2014-03-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多