EnChikiben
@EnChikiben

Как составить запрос выборки баллов?

У меня есть табличка баллов пользователей: id. user_id, point, point_lifetime
point - это баллы они как положительные так и отрицательные
point_lifetime - время жизни баллов, в timestamp

Мне необходимо найти запись, а точнее point_lifetime, при условии что сумма point (баллов) меньше или равна N.

|      id       |      user_id      |      point     |      point_lifetime  |
|      1        |      1            |      10        |      1701533439      |
|      2        |      1            |      10        |      1701533439      |
|      3        |      2            |      10        |      1001433439      |
|      4        |      1            |      -10       |      1901533439      |
|      5        |      1            |      100       |      1801733439      |

Мне нужно найти запись на который у пользователя где у пользователя 1 накопится допустим 30 баллов, это запись id=5. Сортировать нужно по point_lifetime, чтобы суммировались записи у которых время жизни скоро кончится.
  • Вопрос задан
  • 109 просмотров
Пригласить эксперта
Ответы на вопрос 2
@alexalexes
Вас просят написать что-то с клаузой Having.
Если читать вопрос влоб, то вас просят сгруппировать выборку по атрибуту point_lifetime, и проанализировать сумму баллов в having:
select point_lifetime, sum(point)
from t
group by point_lifetime
having sum(point) <= N -- N нужно рассматривать как входной параметр запроса

Тут бы логично по user_id что-то интересное искать, но в задачке point_lifetime. В общем, нужно видеть с какими исходными данными работаете, чтобы понять, что вы группируете.
Дополнено:
-- тестовые данные
with t as (select  1 id, 1 user_id, 10 point, from_unixtime(1701533439) point_lifetime
union
select  2 id, 1 user_id, 10 point, from_unixtime(1701533439) point_lifetime
union
select  3 id, 2 user_id, 10 point, from_unixtime(1001433439) point_lifetime
union
select  4 id, 1 user_id, -10 point, from_unixtime(1901533439) point_lifetime
union
select  5 id, 1 user_id, 100 point, from_unixtime(1801733439) point_lifetime)

-- экспериментальный запрос
select a.*
from (select t.id,
       t.user_id,
       t.point,
       t.point_lifetime, 
       sum(t.point) over (partition by t.user_id) sum_point,
       row_number() over (partition by t.user_id order by case when t.point > 0 then 0 else 1 end, -- продавливаем положительные баллы вверх
                                                                t.point_lifetime desc) rn -- локальный счетчик записей по пользователю, чтобы понять, какую запись хотите выдернуть из подзапроса, нужно сделать так, чтобы интересуемые записи имели rn = 1
from t
  where point_lifetime > str_to_date('02.12.2023 10:00:00', '%d.%m.%Y %H:%i:%s') -- считаем, что отметка "сейчас" - это 02.12.2023 10:00:00
) a
where a.sum_point >= 30 -- берем все то, что больше минимальной суммы
  and a.rn = 1 -- берем только интересуемую запись по каждому пользователю
 order by id
Ответ написан
@Akina
Сетевой и системный админ, SQL-программист.

Мне нужно найти запись на который у пользователя где у пользователя 1 накопится допустим 30 баллов, это запись id=5.


WITH cte AS (
    SELECT *, SUM(point) OVER (ORDER BY point_lifetime) cum_sum
    FROM tablename
    WHERE user_id = 1 --   у пользователя 1 
    )
SELECT *
FROM cte
WHERE cum_sum >= 30   --   накопится 30 баллов
ORDER BY point_lifetime LIMIT 1;


PS. Поскольку значения в point_lifetime неуникальны, то однозначного решения может и не быть. Во всяком случае до тех пор, пока не будет точно определён порядок записей при равенстве значений этого поля.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы