使用SELECT DISTINCT ON计算总行数而不使用子查询

时间:2018-01-09 13:15:20

标签: sql postgresql count window-functions distinct-on

我使用PostgreSQL SELECT DISTINCT ON语法执行了一些查询。我想让查询返回与每个结果行一起的总行数。

假设我有一个表my_table,如下所示:

CREATE TABLE my_table(
    id int,
    my_field text,
    id_reference bigint
);

然后我有几个值:

 id | my_field | id_reference 
----+----------+--------------
  1 | a        |            1
  1 | b        |            2
  2 | a        |            3
  2 | c        |            4
  3 | x        |            5

基本上my_table包含一些版本化数据。 id_reference是对数据库全局版本的引用。对数据库的每次更改都会增加全局版本号,更改将始终向表中添加新行(而不是更新/删除值),并且它们将插入新的版本号。

我的目标是执行一个只检索表中最新值以及总行数的查询。

例如,在上面的例子中,我想检索以下输出:

| total | id | my_field | id_reference |
+-------+----+----------+--------------+
| 3     | 1  | b        |  2           |
+-------+----+----------+--------------+
| 3     | 2  | c        |  4           |
+-------+----+----------+--------------+
| 3     | 3  | x        |  5           |
+-------+----+----------+--------------+

我的尝试如下:

select distinct on (id)
    count(*) over () as total,
    *
from my_table
order by id, id_reference desc

这几乎返回正确的输出,除了totalmy_table中的行数而不是结果查询的行数:

 total | id | my_field | id_reference 
-------+----+----------+--------------
     5 |  1 | b        |            2
     5 |  2 | c        |            4
     5 |  3 | x        |            5
(3 rows)

您可以看到它有5而不是预期的3

我可以通过使用子查询和count作为聚合函数来解决这个问题:

with my_values as (
  select distinct on (id)
    *
  from my_table
  order by id, id_reference desc
)
select count(*) over (), * from my_values

这会产生我预期的输出。

我的问题:有没有办法避免使用这个子查询并且有类似count(*) over ()的内容返回我想要的结果?

1 个答案:

答案 0 :(得分:1)

您正在寻找my_table 3种方式:

  1. 查找每个id_reference
  2. 的最新id
  3. 为每个my_field
  4. 查找最新id_referenc e的id
  5. 计算表格中id的不同数量
  6. 因此我更喜欢这个解决方案:

    select
        c.id_count as total,
        a.id,
        a.my_field,
        b.max_id_reference
    from
        my_table a
        join
        (
            select 
                id,
                max(id_reference) as max_id_reference
            from 
                my_table
            group by
                id
        ) b 
        on
            a.id = b.id and
            a.id_reference = b.max_id_reference
        join
        (
            select
                count(distinct id) as id_count
            from
                my_table
        ) c
        on true;
    

    这有点长(特别是我编写SQL的细长方式),但它清楚地说明了发生了什么。如果你在几个月后回到它(有人通常会这样做),那么理解正在发生的事情将花费更少的时间。

    最后的“on true”是一个有意识的笛卡尔积,因为子查询“c”中只能得到一个结果,你确实需要一个笛卡尔积。

    子查询没有什么问题。