система пропуска / MySQL GROUP BY и ORDER BY - PullRequest
0 голосов
/ 24 марта 2020

Я создаю систему бейджей для своего сайта: на скриншоте ниже показано, как это выглядит сейчас. Вы получаете значки с несколькими уровнями (бронза, серебро ...) после того, как вы заработали 10 100 и c очков за конкретные c действия (например, ответ на вопрос, исправление вики). Обратите внимание, что зеркало со знаком доллара есть там два раза, один в серебре и один в бронзе:

Badges

В основе лежат две таблицы, одна с информацией о значке ( x_badges : хранит какое действие и сколько очков в нем дает какой уровень значка), с каким пользователем какой значок заработал ( x_badges_earned : badgeID и uID) .

Объяснение FK:

  • uID - это идентификатор пользователя, передаваемый в качестве параметра (используйте 1 для тестов)
  • xb_ID - это идентификатор auto_increment для каждого типа значка
  • xbe_ID - это идентификатор auto_increment строки, в которой идентификаторы пользователей совпадают с идентификаторами заработанных ими значков (xb_ID -> uID)

Это был мой оригинальный запрос, который дает мне только один значок каждой категории (но не самый высокий, ie, если я заработал серебро и бронзу в одной категории, он вернет только бронзу):

SELECT * 
FROM x_badges_earned, x_badges 
WHERE xbe_bID = xb_ID 
  AND xbe_uID = ? 
GROUP BY xb_requirement  
ORDER BY xb_requirement ASC, xb_requirement_value ASC

После исследования SO я создал это запрос, который генерирует скриншот выше. Если я изменю последний параметр GROUP BY на xb_requirement, я вернусь с результатами запроса 1:

SELECT b.* 
FROM x_badges b 
LEFT JOIN x_badges b2 ON b.xb_ID = b2.xb_ID 
                     AND b.xb_requirement_value < b2.xb_requirement_value 
LEFT JOIN x_badges_earned be ON be.xbe_bID = b.xb_ID 
WHERE b2.xb_requirement_value IS NULL 
  AND be.xbe_uID = ? 
GROUP BY b.xb_ID

Я чувствую, что в данный момент я довольно много иду по кругу. Я придумал это, которое, вероятно, будет работать (по крайней мере, в моей голове), но я не могу решить это:

SELECT *
FROM x_badges
WHERE xb_ID IN (
    SELECT xb_ID, MAX(xb_requirement_value)
    FROM x_badges_earned, x_badges
    WHERE xbe_bID = xb_ID AND xbe_uID = ?
    GROUP BY xb_requirement
)

Любая помощь очень ценится!

Я приложил MySQL код, чтобы создать две таблицы и заполнить их, чтобы поиграть. Кроме того, вы можете использовать 1 в качестве значения параметра, так как это мой userID. Мой токовый выход выглядит следующим образом , желаемый результат будет таким же без первой строки (xb_ID 11), поскольку это бронзовый значок, за который я заработал серебро.


CREATE TABLE `x_badges` (
  `xb_ID` int(11) NOT NULL,
  `xb_requirement` varchar(40) NOT NULL,
  `xb_requirement_value` int(11) NOT NULL,
  `xb_text` text NOT NULL,
  `xb_text_details` text NOT NULL,
  `xb_icon` varchar(20) NOT NULL,
  `xb_color` varchar(6) NOT NULL,
  `xb_color_text` varchar(6) NOT NULL,
  `xb_level_name` varchar(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;



INSERT INTO `x_badges` (`xb_ID`, `xb_requirement`, `xb_requirement_value`, `xb_text`, `xb_text_details`, `xb_icon`, `xb_color`, `xb_color_text`, `xb_level_name`) VALUES
(11, 'added_interaction', 10, 'Added interactions', 'Received more than %d points adding interactions with target companies!', 'search-dollar', 'cc8e34', '', 'Bronze'),
(15, 'added_target', 10, 'Added targets', 'Received more than %s points adding target companies!', 'dollar-sign', 'cc8e34', '', 'Bronze'),
(16, 'asked_question', 10, 'Asked questions', 'Received more than %s points asking questions!', 'question', 'cc8e34', '', 'Bronze'),
(17, 'notified_colleagues_interaction', 10, 'Interactions shared with colleagues', 'Received more than %s points tagging colleagues in interactions added!', 'bullhorn', 'cc8e34', '', 'Bronze'),
(18, 'reply_accepted', 10, 'Helpful replies', 'Received more than %s points thanks to replies marked as helpful!', 'check-double', 'cc8e34', '', 'Bronze'),
(19, 'reply_question', 10, 'Replies to questions', 'Received more than %s points replying to questions!', 'comments', 'cc8e34', '', 'Bronze'),
(20, 'updated_info', 10, 'Updated target profiles', 'Received more than %s points updating profiles of targets!', 'funnel-dollar', 'cc8e34', '', 'Bronze'),
(21, 'updated_wiki', 10, 'Updated wiki', 'Received more than %s points updating profiles of Group companies!', 'pen-nib', 'cc8e34', '', 'Bronze'),
(22, 'upvote_question', 10, 'Helpful questions', 'Received more than %s points for having own questions upvoted!', 'grin-alt', 'cc8e34', '', 'Bronze'),
(23, 'added_interaction', 100, 'Added interactions', 'Received more than %s points adding interactions with target companies!', 'search-dollar', 'aaa9ad', '', 'Silver'),
(24, 'added_interaction', 500, 'Added interactions', 'Received more than %s points adding interactions with target companies!', 'search-dollar', 'ffd700', '495057', 'Gold'),
(25, 'updated_wiki', 1000, 'Updated Bertelsmann wiki', 'Received more than %s points asking questions!', 'pen-nib', 'b9f2ff', '495057', 'Diamond'),
(26, 'added_interaction', 1000, 'Added interactions', 'Received more than %s points adding interactions with target companies!', 'search-dollar', 'b9f2ff', '495057', 'Diamond'),
(27, 'added_interaction', 5000, 'Added interactions', 'Received more than %s points adding interactions with target companies!', 'search-dollar', 'e0115f', '', 'Ruby');



CREATE TABLE `x_badges_earned` (
  `xbe_ID` int(11) NOT NULL,
  `xbe_uID` int(11) NOT NULL,
  `xbe_bID` int(11) NOT NULL,
  `xbe_timestamp` timestamp NOT NULL DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


INSERT INTO `x_badges_earned` (`xbe_ID`, `xbe_uID`, `xbe_bID`, `xbe_timestamp`) VALUES
(19, 1, 11, '2020-03-23 15:24:54'),
(20, 1, 15, '2020-03-23 15:24:54'),
(21, 1, 16, '2020-03-23 15:24:54'),
(22, 1, 17, '2020-03-23 15:24:54'),
(23, 1, 18, '2020-03-23 15:24:54'),
(24, 1, 19, '2020-03-23 15:24:54'),
(25, 1, 23, '2020-03-23 16:00:51'),
(26, 1, 20, '2020-03-23 15:32:31'),
(27, 1, 21, '2020-03-23 15:32:31'),
(28, 1, 22, '2020-03-23 15:32:31'),
(29, 10, 25, '2020-03-23 15:37:32');

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

1 Ответ

1 голос
/ 24 марта 2020

Я не нашел идентифицирующего выражения для какого-либо определенного значка, кроме (xb_icon, xb_requirement_value) пары значений (цвет вторичен, временная метка не гарантирует порядок).

Таким образом, решение может быть:

SELECT *
FROM x_badges xb
JOIN x_badges_earned xbe ON xb.xb_ID = xbe.xbe_bID
JOIN ( SELECT xb.xb_icon, MAX(xb.xb_requirement_value) xb_requirement_value
       FROM x_badges xb
       JOIN x_badges_earned xbe ON xb.xb_ID = xbe.xbe_bID
       WHERE xbe.xbe_uID = @user
       GROUP BY xb_icon ) max_earned ON (xb.xb_icon, xb.xb_requirement_value) 
                                      = (max_earned.xb_icon, max_earned.xb_requirement_value)
WHERE xbe.xbe_uID = @user;

fiddle


В качестве рекомендации - нормализуйте таблицу x_badges, разделите ее на 2 отдельные таблицы - одна содержит данные типа значка, а другая - данные уровня ссылка на первую таблицу.

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