@vladimircape

Как реализовать выборку строки, в которой сумма превысила определенное значение?

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

Вот такой запрос, но он ищет те пользователей у кого превысило, но datetime бёрет самый первый:

SELECT *,(p.datetime-u.createtime)/86400 as result 
    FROM tbl_user_points p 
    Inner join tbl_users u ON u.id=p.user_id 
    GROUP BY p.user_id
    HAVING SUM(p.points) > 100 
    order by SUM(p.points)


Вот схема таблиц tbl_user_points:

CREATE TABLE `tbl_user_points` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(10) unsigned NOT NULL,
  `action` int(10) unsigned NOT NULL,
  `description` varchar(255) DEFAULT '',
  `points` int(10) NOT NULL DEFAULT '0',
  `datetime` int(10) unsigned NOT NULL,
  `club_id` int(10) unsigned DEFAULT NULL,
  `event_id` int(10) unsigned DEFAULT NULL,
  `location_id` int(10) unsigned DEFAULT NULL,
   PRIMARY KEY (`id`),
   UNIQUE KEY `id_UNIQUE` (`id`)
   ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='Achieved users points for any actions.';


И таблицы tbl_users:

CREATE TABLE `tbl_users` (
   `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
   `username` varchar(255) DEFAULT NULL,
   `password` varchar(255) DEFAULT NULL,
   `email` varchar(128) NOT NULL,
   `activkey` varchar(128) NOT NULL DEFAULT '',
   `createtime` int(11) NOT NULL,
   `lastvisit` int(11) NOT NULL,
   `superuser` int(1) NOT NULL DEFAULT '0',
   `status` int(1) NOT NULL DEFAULT '1',
   `first_name` varchar(128) DEFAULT NULL,
   `last_name` varchar(128) DEFAULT NULL,
   `gender` varchar(6) DEFAULT NULL,
   `locale` varchar(45) DEFAULT NULL,
   `service` varchar(45) NOT NULL,
   `service_id` varchar(255) DEFAULT NULL,
   `location` varchar(128) DEFAULT NULL,
   `state` int(3) DEFAULT NULL,
   `photo` varchar(255) DEFAULT NULL,
   `city` varchar(125) DEFAULT NULL,
   `about_me` varchar(255) DEFAULT NULL,
   `user_code` varchar(10) DEFAULT NULL,
   `loyalty_level` varchar(45) DEFAULT 'basic' COMMENT 'Level of loyalty for current user',
   `updatetime` int(11) NOT NULL,
   PRIMARY KEY (`id`),
   UNIQUE KEY `email` (`email`),
   UNIQUE KEY `user_code_UNIQUE` (`user_code`),
   KEY `status` (`status`),
   KEY `superuser` (`superuser`)
 ) ENGINE=InnoDB AUTO_INCREMENT=1033 DEFAULT CHARSET=utf8;


Пример входных данных tbl_user_points:

id   |  user_id|action|description|points|       datetime
2246      1        1    First visit     5   1383331212
2254      1        2    Second visit    15  1383354853
2255      1        3    Winner          25  1383360231
2256      2        1    First visit     5   1383331202
2257      2        2    Second visit    15  1383354553
2258      2        3    Winner          25  1383360211


tbl_user пример пользователей:

id=1,createtime=1313000000
id=2,createtime=1313000001


Для HAVING SUM(p.points) > 15 выход должен быть:

user_id   datetime
 1           1383354853  
 2           1383354553


Пока для одного пользователя, работает:

SELECT *,SUM(points) as points FROM tbl_user_points 
JOIN  
  (SELECT @rn := 0 ) r 
WHERE 
  (@rn := @rn + points) >=20
and user_id=1681


Но как вывести, чтобы всех пользователей что превысили и время когда превысили?
  • Вопрос задан
  • 2858 просмотров
Пригласить эксперта
Ответы на вопрос 3
ivnik
@ivnik
Почему бы не добавить ещё одну колонку, в которой хранить сумму баллов на дату этой записи? Можно эту колонку заполнять во время работы, а можно её присоединить подзапросом (2-й вариант думаю будет работать не очень быстро). А затем просто выбрать select-ом записи у которых эта колонка будет больше 100, сгруппировать по user и найти min(datetime)?
Ответ написан
foxmuldercp
@foxmuldercp
Системный администратор, программист, фотограф
Посмотреть куда-то в сторону процедур/представлений?
Ответ написан
Комментировать
@zvorygin
"Поджойнить" tbl_user_points саму с собой на user_id, посчитать частичные суммы и выбрать сумму с минимальной датой, которая превышает заданное число - возможно получится тройное произведение, что не очень быстро, но если эту операцию надо делать редко, то почему бы и нет.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы