【问题标题】:Use PHP Loop to Query MYSQL Database Multiple Times使用PHP循环多次查询MYSQL数据库
【发布时间】:2013-01-14 07:02:41
【问题描述】:

上下文:我正在查询数据库以返回指定数量的怪物,这些怪物将在基于网络的简单 RPG 中用于战斗。

问题:我有一个简单的 MYSQL 查询,其中包含一个 WHERE 子句来确定怪物的“级别”。在之前的函数中,我正在构建一个数组,其中包含应返回的相应怪物的级别;类似:

$levels = Array( [0] => 3 [1] => 1 [2] => 1 ) 

所以在上面的数组中,Value对应的是level。所以我希望返回 3 个怪物——3 级、1 级和 1 级。

足够简单。现在我想用以下内容查询 MYSQL 并大概使用循环进行 3 次查询以获得我的 3 个怪物;类似:

$query = "SELECT *, CardHP as EncounterCardHP, CardAP as EncounterCardAP";
$query .= " FROM Cards";
$query .= " WHERE CardTypeId = 1 AND CardRarity = {$level}";
$query .= " ORDER BY RAND() LIMIT 1";

所以在上面的查询中,变量 {$level} 是前一个数组中的怪物等级。循环格式是我苦苦挣扎的地方。我正在尝试类似:

while ($i = $levels) {
     $query = "SELECT *, CardHP as EncounterCardHP, CardAP as EncounterCardAP";
     $query .= " FROM Cards";
     $query .= " WHERE CardTypeId = 1 AND CardRarity = {$i}";
     $query .= " ORDER BY RAND() LIMIT 1";
 $result_set = mysql_query($query, $connection);
 confirm_query($result_set);
 return $result_set;    
}

我认为这很接近,但我不知道如何才能最终给我一个来自 MYSQL 的怪物数组。似乎在上面,我正在构建 3 个单独的数组?我需要使用 array_merge(),还是有更简单更优雅的方法来做到这一点?如果我得到所有相同级别的怪物,我可以简单地运行查询 1 次和 LIMIT 3,但我需要怪物与前面的数组显示的内容相对应。

有意义吗?我们总是感谢您的帮助。

【问题讨论】:

标签: php mysql loops


【解决方案1】:

我不完全理解你想要做什么,但这应该循环并让你得到你的数组:

foreach ($levels as $key => $value) {
    $query = "SELECT *, CardHP as EncounterCardHP, CardAP as EncounterCardAP FROM Cards WHERE WHERE CardTypeId = 1 AND CardRarity = {$value} ORDER BY RAND() LIMIT 1";
    $results = mysqli_query($connection, $query);
    while($row = $result->fetch_array(MYSQLI_BOTH)) {
        $monsters[$key]['HP'] = $row['CardHP'];
        //Add as needed
    }
}

它创建一个多维数组,其中第一个键与级别中的相同,后续键是 SQL 查询的结果。

$monsters = array(
    [0] => array(
        ['HP'] => 10
        ['AP'] => 5
    )
    [1] => array(
        ['HP'] => 5
        ['AP'] => 7
    )
)

另外,mysqli 可能更适合您使用,因为它支持过程样式以及面向对象,并且大多数功能完全相同,只是使用了 mysqli 前缀。

【讨论】:

  • 不仅WHERE WHERE 有错字,最好尽量减少访问数据库的次数。我认为您可能希望针对这种情况执行迭代查询的唯一原因是您想否认复制随机绘制的怪物的可能性。
【解决方案2】:

我猜WHERE IN 是你需要的。

$query = "SELECT *, CardHP as EncounterCardHP, CardAP as EncounterCardAP";
$query .= " FROM Cards";
$query .= " WHERE CardTypeId = 1 AND CardRarity IN (".implode(',', $levels).")";
$query .= " ORDER BY RAND() LIMIT 1";

【讨论】:

  • 这是不正确的,因为它不能确保结果集包含一个 lv3 和两个 lv1 怪物。
【解决方案3】:

实际上比我想象的要容易得多;也许我过度解释了这个问题。这就是我所做的。

1) 一旦我返回了我的数组 $levels,它看起来像这样:

$levels = Array( [0] => 3 [1] => 1 [2] => 2 ) 

2) 我创建了一个名为 $result_set 的空数组 2) 然后使用 foreach 循环遍历 $levels 数组,并使用 $levels 数组中的第一个 $level 运行查询。但是,我不是只返回 $result_set 并返回第一行,而是将第一行插入到我在步骤 2 中创建的空数组中。每次循环后,我将 MYSQL 中的新行插入到现在填充的 $result_set 数组中。

这是最后的样子:

$result_set = array();
foreach ($levels as $level) {
    $query = "SELECT *, CardHP as EncounterCardHP, CardAP as EncounterCardAP";
    $query .= " FROM Cards";
    $query .= " WHERE CardTypeId = 1 AND CardRarity = {$level}";
    $query .= " ORDER BY RAND() LIMIT 1";
    $result = mysqli_query($query, $connection);
    $result_set[] = mysqli_fetch_array($result);    
    confirm_query($result_set);
}
return $result_set;     

我的 $result_set 现在有 3 个怪物,一个 3 级、1 级和 2 级,它们都是从数据库中为每个相应级别随机选择的。

感谢大家的帮助。

【讨论】:

  • 虽然您获得了预期的结果,但执行迭代查询并不是最佳做法。
【解决方案4】:

这是一种基于每个 $levels 元素生成随机抽取的怪物的单个结果集的安全方法。

这只是一次访问数据库的好习惯。同时,我应该提到RAND() 并不以其性能而闻名。如果您对随机性、加权随机化或同一结果集中没有重复的怪物有要求,您可能需要考虑替代策略。

$param_types = '';
foreach ($levels as $level) {
    $selects[] = "(SELECT CardName, CardHP, CardAP FROM Cards WHERE CardTypeId = 1 AND CardRarity = ? ORDER BY RAND() LIMIT 1)";
    $param_types .= 'i';
}

$conn = new mysqli('localhost', 'root', '', 'dbname');
$stmt = $conn->prepare(implode(' UNION ALL ', $selects));
$stmt->bind_param($param_types, ...$levels);
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_all(MYSQLI_ASSOC);

上面的sn-p和这个answer of mine密切相关。

我准备了一个带有一些虚构数据的工作演示,以证明我的解决方案有效。

架构(MySQL v5.7):

CREATE TABLE `Cards` (
  id INT(11),
  CardName VARCHAR(255),
  CardTypeId INT(11),
  CardRarity INT(11),
  CardHP INT(11),
  CardAP INT(11)
);

INSERT INTO `Cards` VALUES
(1, 'Dracula',         2, 1,  500,  75),
(2, 'Gargamel',        1, 1,  200,  20),
(3, 'Rumplestiltskin', 1, 2,  175,  45),
(4, 'Megatron',        3, 3, 1000, 300),
(5, 'Smeagol',         1, 1,  225,  60),
(6, 'Cruella Deville', 4, 1,   95,  35),
(7, 'Thanos',          1, 3, 2575, 960),
(8, 'Stay Puft',       1, 3,  800, 255),
(9, 'Keyser Soze',     1, 3,  750, 300);

查询:

(SELECT CardName, CardHP, CardAP FROM Cards WHERE CardTypeId = 1 AND CardRarity = 3 ORDER BY RAND() LIMIT 1)
UNION ALL
(SELECT CardName, CardHP, CardAP FROM Cards WHERE CardTypeId = 1 AND CardRarity = 1 ORDER BY RAND() LIMIT 1)
UNION ALL
(SELECT CardName, CardHP, CardAP FROM Cards WHERE CardTypeId = 1 AND CardRarity = 1 ORDER BY RAND() LIMIT 1);

可能的结果集:

| CardName  | CardHP | CardAP |
| --------- | ------ | ------ |
| Stay Puft | 800    | 255    |
| Smeagol   | 225    | 60     |
| Gargamel  | 200    | 20     |

View on DB Fiddle

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-15
    • 2015-08-21
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    • 2014-11-29
    • 2012-04-23
    • 1970-01-01
    相关资源
    最近更新 更多