【问题标题】:Secret Santa sorting issue秘密圣诞老人排序问题
【发布时间】:2022-01-15 08:30:22
【问题描述】:

我被分配了创建一个秘密圣诞老人站点的任务,用户登录并从数据库中随机选择一个名称。条件是你不画自己的名字,但由于一次只选择一个名字,我遇到了下面提到的问题: 3 人是(比尔、迈克和杰克) 比尔

$sql ="SELECT gifted 
        FROM gifts 
        WHERE gifted != '$username' 
        AND isgifted = 0 
        ORDER BY Rand() 
        LIMIT 1";

【问题讨论】:

  • 您的脚本对SQL Injection Attack 开放。即使是if you are escaping inputs, its not safe!,您也应该始终在MYSQLI_PDO API 中使用prepared parameterized statements,而不是将用户提供的值连接到查询中。永远不要相信任何用户输入!
  • @ADyson 你的愿望是...... :)
  • 所以你的 PHP 代码只是一个 SQL 查询?
  • 您需要在开始时一次性完成所有作业。否则有些人需要送两份以上的礼物,而有些人根本不需要提供任何礼物。
  • @Andy 是的,这是我想到的一种解决方案,但在研究了一段时间后,我意识到当四个人在场时,该方法也可以解决问题。例如,如果 A 得到 B,B 得到 C,C 得到 A。即使没有人互相赠送,D也没有人可以赠送

标签: php sql database


【解决方案1】:

我认为解决这个问题的简单算法是:

  1. 获取所有参与者的列表,使用 SQL rand() 函数按随机顺序排序。
  2. 对于随机列表中的每一行,从下一行为每个人分配一个秘密圣诞老人。例如,第 1 行将被分配为第 2 行作为他/她的圣诞老人。第 2 行将被分配到第 3 行,依此类推。为此使用 sql lead() 函数。
  3. 对于列表中的最后一行,循环返回并将第一行指定为他/她的圣诞老人。为此,请使用 first_value() 函数。

在您的 PHP 应用程序的内存中执行此操作可能是最简单的,但由于此问题主要与 SQL 有关,因此这里有一个纯 SQL 解决方案。假设您有一个名为“people”的表,其中包含“name”和“id”列,这将为您提供所需的结果:

SELECT name,
(CASE
  WHEN secret_santa IS NULL
  THEN first
   ELSE secret_santa
END) secret_santa
FROM (
  SELECT name,secret_santa,(FIRST_VALUE(name) over ()) as first FROM (
    SELECT name,id,secret_santa
    FROM (
      SELECT name, id, LEAD(name) OVER (ORDER BY RAND()) secret_santa
      FROM people
    ) santas
   ) randomized
 ) wraparound

输出:

+------+--------------+
| name | secret_santa |
+------+--------------+
| Mike | Jake         |
| Jake | Bill         |
| Bill | Mike         |
+------+--------------+

注意,所有这里的复杂性来自于需要将最后一行环绕到第一行。如果您愿意容忍一个没有圣诞老人的人使用自定义代码进行修复,那么 SQL 就是:

SELECT name, LEAD(name) OVER (ORDER BY RAND()) secret_santa
FROM people

输出:

+------+--------------+
| name | secret_santa |
+------+--------------+
| Bill | Mike         |
| Mike | Jake         |
| Jake | NULL         |
+------+--------------+

Working Example Here

【讨论】:

    猜你喜欢
    • 2010-09-21
    • 2013-11-10
    • 2016-05-23
    • 2022-01-12
    • 2012-01-26
    • 1970-01-01
    • 2022-11-17
    • 1970-01-01
    • 2017-04-24
    相关资源
    最近更新 更多