当计数不同的结果为0时如何隐藏行? (Postgres)

Posted

技术标签:

【中文标题】当计数不同的结果为0时如何隐藏行? (Postgres)【英文标题】:How to hide rows when count distinct result is 0? (Postgres) 【发布时间】:2020-07-29 13:57:19 【问题描述】:

我有这个代码

 SELECT "School"."name" AS "School",
        count(distinct "User"."id") filter (where "public"."user_tokens"."app_name" = 'A') AS "A",
        count(distinct "User"."id") filter (where "public"."user_tokens"."app_name" = 'B') AS "B",
        count(distinct "User"."id") filter (where "public"."user_tokens"."app_name" = 'C') AS "C",
        count(distinct "User"."id") filter (where "public"."user_tokens"."app_name" = 'D') AS "D"
FROM "public"."user_tokens"
LEFT JOIN "public"."users" "User" ON "public"."user_tokens"."user_id" = "User"."id"
LEFT JOIN "public"."user_roles" "User_2" ON "public"."user_tokens"."user_id" = "User_2"."user_id"
LEFT JOIN "public"."roles" "Role" ON "User_2"."role_id" = "Role"."id" LEFT JOIN "public"."schools" "School" ON "User_2"."school_id" = "School"."id"
GROUP BY "School"."name"
ORDER BY "B" desc

结果是这样的:

  School         A        B        C         D
--------------------------------------------------
    P            5        6       10         6
    Q            1        0        0         0
    R            2        7        0         6
    S            0        8        9         0

是否可以隐藏包含值“0”的整行?在这种情况下,结果应该只是 School P。

之后,如何区分不包含零值的“学校”?对于这种情况,结果应该是 1

谢谢。

【问题讨论】:

【参考方案1】:

您使用having 子句并重复表达式

having count(distinct "User"."id") filter (where "public"."user_tokens"."app_name" = 'A') > 0 and
       count(distinct "User"."id") filter (where "public"."user_tokens"."app_name" = 'B') > 0 and
       count(distinct "User"."id") filter (where "public"."user_tokens"."app_name" = 'C') > 0 and
       count(distinct "User"."id") filter (where "public"."user_tokens"."app_name" = 'D') 

虽然 Postgres 允许在 GROUP BY 中使用列别名,但它不允许在 HAVING 子句中使用列别名上的表达式(在我看来,这是扩展 SQL 标准的一种奇怪方式)。

现在,您还可以简化和改进您的查询。首先,您需要匹配,所以只需使用inner join。其次,使用表别名。我也摆脱了双引号 - 这是一个非常糟糕的主意:

 SELECT s.name AS School,
        count(distinct u.id) filter (where ut.app_name = 'A') AS A,
        count(distinct u.id) filter (where ut.app_name = 'B') AS B,
        count(distinct u.id) filter (where ut.app_name = 'C') AS C,
        count(distinct u.id) filter (where ut.app_name = 'D') AS D
FROM "public"."user_tokens" ut JOIN
     "public"."users" u
      ON ut.user_id = u.id JOIN
      "public"."user_roles" ur
      ON ut.user_id = ur.user_id JOIN
      "public"."roles" r
      ON ur.role_id = r.id JOIN
      "public"."schools" s
      ON ur.school_id = s.id
GROUP BY s.name
having count(distinct u.id) filter (where ut.app_name = 'A') > 0 and
       count(distinct u.id) filter (where ut.app_name = 'B') > 0 and
       count(distinct u.id) filter (where ut.app_name = 'C') > 0 and
       count(distinct u.id) filter (where ut.app_name = 'D') 
ORDER BY "B" desc

【讨论】:

啊,内部连接真是个好主意。谢谢我还在学习。在此之后,如何区分不包含零值的“学校”?对于这种情况,结果应该是 1 @ettapi 。 . .您可以将其用作子查询并使用count(*)。这回答了您在这里提出的问题。如果您想要更有效的方法来获取计数,请提出 问题,提供样本数据和所需结果。【参考方案2】:
GROUP BY "School"."name"
HAVING count... > 0
      and count... > 0
ORDER BY "B" desc

【讨论】:

【参考方案3】:

此外,您可以通过将查询封装为另一个SELECT表表达式,使ABCD 列可供操作。在这个外部SELECT 中,通过添加过滤谓词很容易过滤掉行:

WHERE "A" <> 0 and "B" <> 0 and "C" <> 0 and "D" <> 0

因此,您的查询可能如下所示:

SELECT
  *,
  count(*) over() as total_rows
from (
  SELECT "School"."name" AS "School",
        count(distinct "User"."id") filter (where "public"."user_tokens"."app_name" = 'A') AS "A",
        count(distinct "User"."id") filter (where "public"."user_tokens"."app_name" = 'B') AS "B",
        count(distinct "User"."id") filter (where "public"."user_tokens"."app_name" = 'C') AS "C",
        count(distinct "User"."id") filter (where "public"."user_tokens"."app_name" = 'D') AS "D"
  FROM "public"."user_tokens"
  LEFT JOIN "public"."users" "User" ON "public"."user_tokens"."user_id" = "User"."id"
  LEFT JOIN "public"."user_roles" "User_2" ON "public"."user_tokens"."user_id" = "User_2"."user_id"
  LEFT JOIN "public"."roles" "Role" ON "User_2"."role_id" = "Role"."id" LEFT JOIN "public"."schools" "School" ON "User_2"."school_id" = "School"."id"
  GROUP BY "School"."name"
) x
WHERE "A" <> 0 and "B" <> 0 and "C" <> 0 and "D" <> 0
ORDER BY "B" desc

如果您希望避免查询中的表达式冗余,这对于更复杂的表达式会派上用场。

【讨论】:

在此之后,如何区分不包含0值的“学校”?对于这种情况,结果应该是 1 您可以添加count(*) over() as total_rows。查看已编辑的查询。

以上是关于当计数不同的结果为0时如何隐藏行? (Postgres)的主要内容,如果未能解决你的问题,请参考以下文章

Oracle:根据结果集计数更新行

如何在使用 WHERE 删除的行上将计数值显示为 0(微软访问)

如何在 iOS 11 中隐藏部分标题?

python如何进行内存管理

根据测试是不是成功通过不同的测试计数

不同时间段不同计数时的不同结果