随机分配,直到使用所有选项

  • 本文关键字:选项 分配 随机 php
  • 更新时间 :
  • 英文 :


我有一个可用团队teams表,有24个不同的选项。

我还有另一个表entries,其中每一行都是一个团队分配给一个用户。

创建条目时,将分配一个尚未被选中的随机团队。但是,如果所有团队都已分配(这可能会多次发生),则只有本轮分配中尚未分配的团队可用。

例如,如果我的团队是 A、B、C 和 D:

  • 如果 entries 中有 A 的条目,则只有 B、C 和 D 可用
  • 如果已选择 A、B、C 和 D,则它们再次可用
  • 如果 A 有 3 个条目,B 有 3 个条目,C 有 2 个条目,D 有 2 个条目,
  • 则只有 C 和 D 可用,直到它们都有相同数量的条目

我的代码很复杂:

//Make array of teams
for($i=1;$i<=24;$i++) $team[$i] = 1;
//Get entries from database
$stmt = $dbh->prepare("SELECT `team` FROM `entries`");
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
//Create array of available teams
$numRows = $stmt->rowCount();
while($numRows >= 24) {
    for($i=1;$i<=24;$i++) {
        $team[$i] = $team[$i]+1;
    }
    $numRows = $numRows - 24;
}
//Remove entries for teams in array
foreach($rows as $row) $team[$row["team"]] = $team[$row["team"]]-1;
foreach($team as $i => $v) if($v > 0) $available[] = $i;

必须有一种更直接的方法来实现这一点;如何做到这一点?

下面给出了每个团队的分配数:

SELECT team, COUNT(*) FROM entries GROUP BY team;

这为您提供了任何团队的最小计数:

SELECT MIN(count) FROM (
  SELECT COUNT(*) as count FROM entries GROUP BY team
)

要获得计数最少的团队 - 可用的团队 - 但这两个查询合二为一:

SELECT teamcounts.team
FROM 
  (SELECT team, COUNT(*) as num FROM entries GROUP BY team) as teamcounts
WHERE 
  teamcounts.num = (
    SELECT MIN(num) FROM (
      SELECT COUNT(*) as num FROM entries GROUP BY team
    ) as tcounts
  )

为了获得那些尚未包含在条目中的团队,我们还必须使用团队表,删除当前无法选择的所有团队:

SELECT teams.name
FROM teams
WHERE teams.name NOT IN (
  SELECT teamcounts.team
  FROM 
    (SELECT team, COUNT(*) as num FROM entries GROUP BY team) as teamcounts
  WHERE 
    teamcounts.num != (
      SELECT MIN(num) FROM (
        SELECT COUNT(*) as num FROM entries GROUP BY team
      ) as tcounts
    )
)

我还没有找到仅在SQL中工作的解决方案,但是我创建了以下查询:

SELECT `id`, `num_selected` FROM
    (SELECT `id`, SUM(is_selected) AS `num_selected` FROM 
        (SELECT t.`id`, CASE WHEN e.`team` IS NULL THEN 0 ELSE 1 END AS is_selected FROM `entries` e RIGHT JOIN `teams` t ON t.`id` = e.`team`)
        AS `table1`
    GROUP BY `id`)
AS `table2` GROUP BY `id` ORDER BY `num_selected` ASC, `id` ASC

这包括所有尚未有条目的team行,结果是一个表,其中每个团队都在一列中,旁边是选择数。

然后,在 PHP 中,我只需选择最低值(这将是第一行,因为我按 num_selected ASC 排序),并且仅使用该值的其他行作为可能的选项:

$baseNum = $rows[0]["num_selected"];
foreach($rows as $row){
    if($row["num_selected"]===$baseNum) $availableTeams[] = $row["id"];
}

但是,理想情况下,我会有一个仅在SQL查询中进行的解决方案!

最新更新