【问题标题】:Multidimensional loop in MySQL query to calculate sumMySQL查询中的多维循环计算总和
【发布时间】:2021-08-05 05:22:45
【问题描述】:

我正在尝试用 PHP 和 MySQL 编写一个具有不同级别的简单游戏。在每个关卡中,用户都可以使用提示来解决关卡。

现在我想建立一个排行榜来显示所有用户的排名,按已解决的级别、开始日期和新内容排序:基于惩罚逻辑的提示。

惩罚逻辑是:

对于用户采取的每个提示,都应该以秒/分钟为单位进行处罚。

  • 对于关卡中的第一个提示,用户将获得 30 秒的惩罚
  • 第二次提示 -> 1 分钟
  • 第三次提示 -> 3 分钟
  • 第四次提示 -> 5 分钟
  • 对于第 5 次提示和之后的每一次 -> 8 分钟

此逻辑适用于每个级别,例如当用户在第一关接受 1 次提示,在第二关接受 3 次提示时,总惩罚应该是 5 分钟 =(30 秒 + 30 秒 + 1 分钟 + 3 分钟)。

我不知道如何在查询中解决这个问题以获得有序的输出。 SELECT 查询应该返回凭证,按解决的级别和所需的总时间排序。我想过从开始日期减去罚款。

你可以在这里找到我的数据库结构

CREATE TABLE `vouchers` (
  `voucher_id` int(11) NOT NULL,
  `voucher_started` tinyint(1) NOT NULL DEFAULT 0,
  `voucher_date_started` datetime NOT NULL,
  `voucher_levels_solved` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

INSERT INTO `vouchers` (`voucher_id`, `voucher_started`, `voucher_date_started`, `voucher_levels_solved`) VALUES
(1, 1, '2021-05-15 08:05:00', 2),
(2, 1, '2021-05-15 08:03:00', 2),
(3, 1, '2021-05-15 08:08:00', 2);

CREATE TABLE `hints_taken` (
  `hint_id` int(11) NOT NULL,
  `hint_voucher_id` int(11) NOT NULL,
  `hint_level` int(11) NOT NULL,
  `hint_category` int(11) NOT NULL,
  `hint_number` int(11) NOT NULL,
  `hint_date_taken` datetime NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `hints_taken` (`hint_id`, `hint_voucher_id`, `hint_level`, `hint_category`, `hint_number`, `hint_date_taken`) VALUES
(1, 1, 1, 0, 1, '2021-05-14 12:11:46'),
(2, 1, 1, 0, 2, '2021-05-14 12:11:47'),
(3, 1, 1, 0, 3, '2021-05-14 12:11:47'),
(4, 1, 1, 0, 4, '2021-05-14 12:11:48'),
(5, 1, 2, 0, 1, '2021-05-15 09:00:33'),
(6, 1, 2, 1, 1, '2021-05-15 09:00:33'),
(7, 1, 2, 1, 2, '2021-05-15 09:00:33'),
(8, 1, 3, 0, 1, '2021-05-15 09:00:47'),
(9, 1, 3, 1, 1, '2021-05-15 09:00:47'),
(10, 2, 7, 0, 1, '2021-05-15 09:00:48'),
(11, 2, 7, 0, 2, '2021-05-15 09:00:48'),
(12, 2, 7, 1, 1, '2021-05-15 09:00:49'),
(13, 2, 7, 1, 2, '2021-05-15 09:00:49'),
(14, 2, 7, 2, 1, '2021-05-15 09:00:50'),
(15, 3, 5, 0, 1, '2021-05-15 09:01:19'),
(16, 3, 5, 0, 2, '2021-05-15 09:01:19'),
(17, 3, 5, 0, 3, '2021-05-15 09:01:20'),
(18, 3, 5, 0, 4, '2021-05-15 09:01:20'),
(19, 3, 5, 0, 5, '2021-05-15 09:01:21'),
(20, 3, 9, 0, 1, '2021-05-15 09:05:48');

或通过此链接: https://www.db-fiddle.com/f/aEs1gX1CCGFTVvb5ddkRXG/0

如果有人可以帮助我如何构建这样的查询,将非常高兴。

借助 Jayvee 的解决方案

SELECT voucher_id,
UNIX_TIMESTAMP (NOW()) - UNIX_TIMESTAMP(`voucher_date_started`) + SUM(`penalty`) as `total_time_needed`
                                            
FROM `vouchers` v
                                            
JOIN 
(Select `hint_voucher_id`, `hint_level`,sum(
  case when `hint_number`=1 then 30
  when `hint_number`=2 then 60
  when `hint_number`=3 then 180
  when `hint_number`=4 then 300
  when `hint_number`>4 then 480
  else 0 end) as `penalty`
 from `hints_taken`
 group by  `hint_voucher_id`,`hint_level`) as h
ON  h.`hint_voucher_id`= v.`voucher_id`
                
GROUP BY `voucher_id`
    
ORDER BY `total_time_needed`

【问题讨论】:

    标签: mysql loops


    【解决方案1】:

    您可能正在寻找这样的东西:

    SELECT * ,
    SUBTIME(`voucher_date_started`, SEC_TO_TIME(`total_penalty`)) as time_adjusted
    FROM `vouchers` v
    JOIN 
    (Select `hint_voucher_id`,sum(
      case when `hint_number`=1 then 30
      when `hint_number`=2 then 60
      when `hint_number`=3 then 180
      when `hint_number`=4 then 300
      when `hint_number`>4 then 480
      else 0 end) as `total_penalty`
     from `hints_taken`
     group by  `hint_voucher_id`) as h
    ON h.`hint_voucher_id`=v.`voucher_id`
    ORDER BY `voucher_levels_solved` DESC, `voucher_date_started`;
    

    根据 cmets,如果您需要按级别进行处罚,那么应该是这样的:

    SELECT * ,
    SUBTIME(`voucher_date_started`, SEC_TO_TIME(`total_penalty`)) as time_adjusted
    FROM `vouchers` v
    JOIN 
    (Select `hint_voucher_id`, `hint_level`,sum(
      case when `hint_number`=1 then 30
      when `hint_number`=2 then 60
      when `hint_number`=3 then 180
      when `hint_number`=4 then 300
      when `hint_number`>4 then 480
      else 0 end) as `total_penalty`
     from `hints_taken`
     group by  `hint_voucher_id`,`hint_level`) as h
    ON h.`hint_voucher_id`=v.`voucher_id` and h.`hint_level`=v.`voucher_levels_solved`
    ORDER BY `voucher_levels_solved` DESC, `voucher_date_started`;
    

    sqlfiddle:

    https://www.db-fiddle.com/f/aEs1gX1CCGFTVvb5ddkRXG/1

    【讨论】:

    • 嗨 Jayvee,这太聪明了!感谢您的这种不同想法 :) 我只需要弄清楚如何解决剩下的一个问题:hint_number 并不总是针对每个级别向上计数,因为提示被归类为多个类别。每个级别有多个类别,每个类别的提示编号从 1 开始。您可以在我的示例数据中看到这一点,例如用于优惠券 1 和 2 级。
    • 我明白了,您可能需要按我认为的凭证 ID 和级别分组,并按这两个属性加入
    • 嘿,非常感谢。感谢您的帮助,得到了一段工作代码!我稍微调整以计算所需的总时间并更新了上面的查询。
    猜你喜欢
    • 1970-01-01
    • 2019-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多