Postgres: нужен четкий счетчик записей - PullRequest
0 голосов
/ 01 июня 2018

У меня есть таблица с повторяющимися записями, и цель состоит в том, чтобы получить отдельные записи, основанные на самой последней отметке времени.

В моем случае «serial_no» будет иметь повторяющиеся записи, но я выбираю уникальные записи на основепоследняя отметка времени.

Ниже приведен запрос уникальных результатов с последней отметкой времени.Но меня беспокоит то, что мне нужно получить общее количество уникальных записей.

Например, предположим, что в моей таблице всего 40 записей.С помощью приведенного ниже запроса я могу получить 20 уникальных строк на основе серийного номера.Но 'total' возвращается как 40 вместо 20. Любая помощь по этому вопросу?

  SELECT 
  * 
  FROM 
  (
    SELECT 
      DISTINCT ON (serial_no) id, 
      serial_no, 
      name, 
      timestamp,
      COUNT(*) OVER() as total 
    FROM 
      product_info 
      INNER JOIN my.account ON id = accountid 
    WHERE 
      lower(name) = 'hello' 
    ORDER BY 
      serial_no, 
      timestamp DESC OFFSET 0 
    LIMIT 
      10
  ) AS my_info 
 ORDER BY 
   serial_no asc

enter image description here

product_info table intially has this data  

serial_no           name         timestamp                              

11212               pulp12      2018-06-01 20:00:01             
11213               mango       2018-06-01 17:00:01             
11214               grapes      2018-06-02 04:00:01             
11215               orange      2018-06-02 07:05:30             
11212               pulp12      2018-06-03 14:00:01             
11213               mango       2018-06-03 13:00:00             



After the distict query I got all unique results based on the latest 
timestamp:

serial_no       name        timestamp                   total

11212           pulp12     2018-06-03 14:00:01            6
11213           mango      2018-06-03 13:00:00            6
11214           grapes     2018-06-02 04:00:01            6
11215           orange     2018-06-02 07:05:30            6


But total is appearing as 6 . I wanted the total to be 4 since it has 
only 4 unique entries.

I am not sure how to modify my existing query to get this desired 
result.

Ответы [ 3 ]

0 голосов
/ 02 июня 2018

Что вы можете сделать, это переместить оконную функцию в оператор выбора более высокого уровня.Это связано с тем, что оконная функция оценивается до того, как применяются различные условия on и limit.Кроме того, вы не можете включать ключевое слово DISTINCT в оконные функции - оно еще не реализовано (начиная с Postgres 9.6).

 SELECT 
  *,
  COUNT(*) OVER() as total -- here
 FROM 
  (
    SELECT 
      DISTINCT ON (serial_no) id, 
      serial_no, 
      name, 
      timestamp
    FROM 
      product_info 
      INNER JOIN my.account ON id = accountid 
    WHERE 
      lower(name) = 'hello' 
    ORDER BY 
      serial_no, 
      timestamp DESC
    LIMIT 
      10
  ) AS my_info

Кроме того, смещение там не требуется, и еще одна сортировка также излишня,Я удалил их.

Другой способ - включить вычисляемый столбец в предложение select, но это будет не так быстро, как это потребует еще одного сканирования таблицы.Очевидно, это предполагает, что ваш итог строго связан с вашим набором результатов, а не с тем, что хранится в таблице, а отфильтрован.

0 голосов
/ 02 июня 2018

Postgres поддерживает COUNT(DISTINCT column_name), поэтому, если я понял ваш запрос, использование этого вместо COUNT(*) сработает, и вы можете сбросить OVER.

0 голосов
/ 01 июня 2018
select count(*), serial_no from product_info group by serial_no

даст вам количество дубликатов для каждого серийного номера

Самый бессмысленный способ включить эту информацию - присоединиться к подзапросу

  SELECT 
  * 
  FROM 
  (
    SELECT 
      DISTINCT ON (serial_no) id, 
      serial_no, 
      name, 
      timestamp,
      COUNT(*) OVER() as total 
    FROM 
      product_info 
      INNER JOIN my.account ON id = accountid 
    WHERE 
      lower(name) = 'hello' 
    ORDER BY 
      serial_no, 
      timestamp DESC OFFSET 0 
    LIMIT 
      10
  ) AS my_info
  join (select count(*) as counts, serial_no from product_info group by serial_no) as X
  on X.serial_no = my_info.serial_no
 ORDER BY 
   serial_no asc
...