SQL Выберите строки с максимальной разницей в столбце - PullRequest
0 голосов
/ 03 ноября 2018

У меня есть две таблицы Postgres, такие как ниже, называемые client и order.

id | name
------------
41 | james
29 | melinda
36 | henry
...

id | date | volume | client_id
------------------------------
328 | 2018-01-03 | 16 | 41
411 | 2018-01-29 | 39 | 29
129 | 2018-01-13 | 73 | 29
542 | 2018-01-22 | 62 | 36
301 | 2018-01-17 | 38 | 41
784 | 2018-01-08 | 84 | 29
299 | 2018-01-10 | 54 | 36
300 | 2018-01-10 | 18 | 36
178 | 2018-01-30 | 37 | 36
...

Затем я написал запрос со следующей логикой:

i) Найти разницу в объеме между каждым заказом и его предыдущим заказом, сгруппированным по каждому клиенту и заказу по дате. Этот столбец будет нулевым для первых заказов.

ii) Показать клиентов и максимальную разницу в объеме для каждого из них.

with cte AS
  (SELECT t.name,
          t.date,
          t.volume,
          t.volume - lag(t.volume) over (
                                         ORDER BY t.name, t.date) AS change
   FROM
     (SELECT c.name,
             o.date,
             sum(o.volume) volume
      FROM orders o
      JOIN client c using (client_id)
      GROUP BY c.name,
               o.date
      ORDER BY c.name,
               o.date) t)
SELECT cte.name,
       max(abs(change))
FROM cte
GROUP BY name

Ниже приведена результирующая таблица.

name | max
------------
james   | 22
melinda | 34
henry   | 25

Я хочу получить совет по трем вещам.

а) Можно ли показать разницу со знаком? Для клиентских идентификаторов 29 и 36 значения должны быть -34 и -25 соответственно.

б) Можно ли также показать дату? Я попытался выбрать столбец даты на CTE, но безуспешно.

в) У кого-нибудь есть общие советы о том, как улучшить запрос, чтобы сделать его более производительным или читабельным?

Ответы [ 2 ]

0 голосов
/ 03 ноября 2018

Спасибо Гордону Линоффу за большую часть этого запроса, однако для этого потребовались некоторые изменения, в частности, пункт where, показанный ниже.

SELECT DISTINCT ON (co.name) 
       co.client_id
     , co.name
     , co.DATE
     , (co.volume - co.prev_volume) change
FROM (
     SELECT 
            c.client_id
          , c.name
          , o.DATE
          , SUM(o.volume) AS volume
          , LAG(SUM(o.volume)) OVER (PARTITION BY c.name 
                                     ORDER BY o.DATE) AS prev_volume
     FROM orders o
     INNER JOIN client c USING (client_id)
     GROUP BY
           c.client_id
          , c.name
          , o.DATE
     ) co
WHERE prev_volume IS NOT NULL
ORDER BY
       co.name
     , ABS(co.volume - co.prev_volume)  DESC

Результат:

client_id | name    | date       | change
--------: | :------ | :--------- | -----:
       36 | henry   | 2018-01-30 |    -25
       41 | james   | 2018-01-17 |     22
       29 | melinda | 2018-01-29 |    -34

дБ <> скрипка здесь

0 голосов
/ 03 ноября 2018

Postgres поддерживает DISTINCT ON, что действительно облегчает ваш запрос. Кроме того, вы можете упростить запрос, потому что оконные функции и функции агрегирования могут комбинироваться на одном уровне:

SELECT DISTINCT ON (co.name) co.*
FROM (SELECT c.name, o.date, SUM(o.volume) as volume,
             LAG(SUM(o.volume)) OVER (PARTITION BY c.name ORDER BY o.date) as prev_volume
      FROM orders o JOIN
           client c 
           USING (client_id)
      GROUP BY c.name, o.date
     ) co
ORDER BY c.name, ABS(volume - prev_volume) DESC
...