Выбирать минимальные строки, пока сумма столбца не будет больше значения - PullRequest
0 голосов
/ 27 мая 2020

У меня есть таблица (заказы) в Postgresql, схема и данные выглядят следующим образом:

+----+---------+------+-------+------+--------+
| id | symbol  | qty  | price | side | status |
+----+---------+------+-------+------+--------+
| 1  | BTCUSDT | 0.02 | 6500  | SELL | NEW    | 
+----+---------+------+-------+------+--------+
| 2  | BTCUSDT | 1.00 | 6550  | SELL | NEW    |
+----+---------+------+-------+------+--------+
| 3  | BTCUSDT | 0.03 | 6600  | SELL | NEW    |
+----+---------+------+-------+------+--------+

Я хочу выбрать строки, где сторона - ПРОДАЖА, а статус - НОВАЯ, упорядочить по цене по возрастанию до суммы (qty) больше 0,5, поэтому результат должен выбрать для меня id 1 и 2

, когда я запускаю этот запрос:

SELECT * FROM (
       SELECT *, SUM(qty) OVER (ORDER BY price ASC) as total_qty FROM orders 
       WHERE symbol = 'BTCUSDT' AND side = 'SELL' AND status = 'NEW'
    ) AS o WHERE o.total_qty <= 0.5

он просто возвращает первую строку (id: 1 ) Мне нужен запрос, возвращающий 1 и 2

Ответы [ 3 ]

0 голосов
/ 27 мая 2020

Вам нужны все строки до строки, в которой сумма равна или превышает 0.5. Это означает, что если вы вычтите qty из суммы последней строки, которую вы хотите вернуть, результат должен быть меньше qty. Вычтите qty из суммы и удалите знак равенства из предложения WHERE:

SELECT o.id, o.symbol, o.qty, o.price, o.side, o.status 
FROM (
  SELECT *, SUM(qty) OVER (ORDER BY price ASC) - qty as total_qty 
  FROM orders 
  WHERE symbol = 'BTCUSDT' AND side = 'SELL' AND status = 'NEW'
) AS o 
WHERE o.total_qty < 0.5

См. demo . Результатов:

| id  | symbol  | qty  | price | side | status |
| --- | ------- | ---- | ----- | ---- | ------ |
| 1   | BTCUSDT | 0.02 | 6500  | SELL | NEW    |
| 2   | BTCUSDT | 1.00 | 6550  | SELL | NEW    |
0 голосов
/ 27 мая 2020

Вы на правильном пути. Проблема в том, что совокупная сумма включает текущую строку. Итак, ваше предложение where отфильтровывает его, когда оно проходит 0,5. Простое решение - вычесть значение из текущей строки:

SELECT *
FROM (SELECT o.*, SUM(qty) OVER (ORDER BY price ASC) as total_qty
      FROM orders o
      WHERE symbol = 'BTCUSDT' AND side = 'SELL' AND status = 'NEW'
     ) o
WHERE o.total_qty - o.qty <= 0.5;

Вы также можете использовать оконную рамку, как это делает Impaler, но это создает проблему NULL значений в первой строке. Вы также можете вычесть сумму в подзапросе, как это делает forpas. Во всех случаях идея одна: вам нужно накопленное количество до каждой строки.

0 голосов
/ 27 мая 2020

Вам нужно оставить два SUM s. Один для текущей строки, а другой для предыдущей. Тогда фильтровать легко. Например:

select *
from (
  SELECT *, 
    SUM(qty) OVER (partition by side, status ORDER BY price ASC) as total_qty,
    SUM(qty) OVER (partition by side, status ORDER BY price ASC
      rows between unbounded preceding and 1 preceding) as prev_total_qty
  FROM orders 
  WHERE symbol = 'BTCUSDT' AND side = 'SELL' AND status = 'NEW'
) AS o 
WHERE coalesce(prev_total_qty, 0) <= 0.5

См. Рабочий пример на DB Fiddle .

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