如何从MySQL表中对大型多维数组进行排序

时间:2012-05-08 18:49:30

标签: php mysql arrays multidimensional-array pdo

我有一个MySQL表,其中包含客户可以订购的所有可能产品的列表。该表的(非常)简化版本如下所示:

ID  |  productid    |    price    |   age_min   |   age_max   |   type
=======================================================================
1   |   baseball_1  |    12.34    |    18       |    21       |    1
2   |   baseball_2  |    15.99    |    22       |    30       |    1
3   |   baseball_3  |    18.99    |    18       |    99       |    1
4   |   golf_1      |    4.99     |    18       |    24       |    2
5   |   golf_2      |    5.99     |    25       |    44       |    2
6   |   tennis_1    |    9.99     |    18       |    50       |    3
7   |   tennis_2    |    14.99    |    51       |    99       |    3

在这家商店中,所有产品都经过年龄限制,这意味着如果客户的年龄适合该范围,则客户只能选择要购买的商品。即使每个产品“类型”存在多个选项,自定义也只能选择一个“类型”。在上面的示例表中,24岁的客户只能选择:

  

baseball_2,baseball_3 golf_1和tennis_1

我正在尝试按已知产品类型组织潜在客户的选项。所以在我的情况下,商店可能会向顾客展示:

棒球选项

  • baseball_2 - $ 15.99
  • baseball_3 - $ 18.99

高尔夫选项

  • golf_1 - $ 4.99

网球选项

  • tennis_1 - $ 9.99

我希望使用age变量对数据库进行单个(如果可能)MySQL调用并返回所有可能的产品,然后如上所述相应地显示这些产品。 SQL语句很简单,我已经完成了这个,但我不知道如何循环或构建一个可以列出成员可用选项的正确数组。

可能会建议,但这比显示的要详细得多,并且由于与该问题无关的其他几个因素,使用任何类型的第三方软件或购物车都不是一种选择。这似乎是如何处理多维数组的问题。以前有人遇到过类似的问题吗?


更新

虽然Travesty和tdammer在下面提供的解决方案在某些情况下是有效的,但我希望能够对我的数据做更多的工作,然后只显示它来自我的数据库。页面的布局和设计不应该取决于它在数据库中存储的方式/时间等。有时我可能会先为一组“类型”显示最高价格,而对另一组“最低价格”。

通过使用fetchAll语句,我能够从查询中收集所需的所有必要数据,但我真的不确定如何使用它。例如,我的数组目前是:

Array (
    [0] => Array ( [productid] => 394, [price] => 6.20,  [type] => 16 ),
    [1] => Array ( [productid] => 395, [price] => 12.40, [type] => 16 ),
    [2] => Array ( [productid] => 396, [price] => 18.60, [type] => 16 ),
    [3] => Array ( [productid] => 397, [price] => 24.80, [type] => 16 ),
    [4] => Array ( [productid] => 398, [price] => 31.00, [type] => 16 ),
    [5] => Array ( [productid] => 449, [price] => 4.20,  [type] => 17 ),
    [6] => Array ( [productid] => 450, [price] => 8.40,  [type] => 17 ),
    [7] => Array ( [productid] => 451, [price] => 12.60, [type] => 17 ),
    [8] => Array ( [productid] => 452, [price] => 16.80, [type] => 17 ),
    [9] => Array ( [productid] => 453, [price] => 21.00, [type] => 17 )
)

是否有一种很好的方式来构建我自己的数组,以后我可以基本上说“向我展示17型所有项目的产品和价格”?

3 个答案:

答案 0 :(得分:3)

您不需要多维数组。

按类型排序查询结果,然后遍历数组。在执行此操作时,在第一个项目之前插入标题,然后在类型更改的每个项目之前插入标题。

如果您有一个正确规范化的数据库,您还应该有一个product_types表,其中包含您的产品类型ID和名称;在这种情况下,请考虑JOIN。你的SQL看起来会像这样:

SELECT p.id, p.name, p.price, t.id AS type_id, t.name AS type_name FROM products AS p LEFT JOIN product_types t ON t.id = p.type WHERE :age BETWEEN p.min_age AND p.max_age;

然后,您逐步完成结果集:

$current_type = 'not_a_string';
while ($row = get_next_row_from_database) {
    if ($current_type !== $row['type_id']) {
        echo '<h3>' . htmlspecialchars($row['type_name']) . '</h3>';
        $current_type = $row['type_id'];
    }
    printf('<p>%s - $%2.2f</p>', htmlspecialchars($row['name']), $row['price']);
}

这种方法使用常量内存(在Web服务器上,显然不在数据库上)和线性时间。

您还应该考虑对数据进行分页:不要一次查询所有行,而是运行COUNT(*)查询以获取总行数,然后使用LIMIT获取只有当前页面的行(您可能还想指定一个ORDER BY子句以使您的页面有意义。)

答案 1 :(得分:3)

我认为你不需要多维数组。我认为你只需要遍历你的行并在你来到一个新组时改变你的标题。

我对这个答案采用了一种不同的方法,将每一行粘贴到一个数组中,然后将它们内爆,以便保留格式。

//USING PDO - assume connection already made
/* added ORDER BY in the query to ensure that we get the rows sequentially, by type */
$stmt = $db->prepare("SELECT * FROM table WHERE age_min >= :age AND age_max <= :age ORDER BY type");
$stmt->bindParam(":age", $customer_age);
$stmt->execute();

$type = -1;
$lines = array();
while ($data = $stmt->fetch(PDO::FETCH_ASSOC))
{
    $data = array_map("htmlspecialchars", $data); /* sanitize data for HTML output */

    if ($type != $data["type"])
    {
        $type = $data["type"];
        list($typeName) = explode("_", $data["productid"]); /* this assumes that you don't have a column with the actual product name. If you do, use that instead. */
        $lines[] = (count($lines) > 0 ? "</ul>\n" : "") ."<h2>". ucfirst($typeName) ." Option</h2>\n<ul>";
    }

    $lines[] = "\t<li>{$data["productid"]} - {$data["price"]}</li>";
}

echo implode("\n", $lines) ."\n</ul>";

<小时/> 对问题更新的回复:

  

是否有一种很好的方式来构建我自己的数组,以后我可以基本上说“向我展示17型所有项目的产品和价格”?

这是一个查询。我仍然认为没有理由将它存储在一个数组中。如果您想获得类型为17的所有项目的产品和价格,那么您应该在数据库上执行该查询。如果您想以不同方式订购结果,则应更改ORDER BY条款。

也许您需要调整查询以使其更灵活:

if (!isset($_POST["columns"]))
    $_POST["columns"] = "productid, price";
if (!isset($_POST["whereClause"]))
    $_POST["whereClause"] = "TRUE";
if (!isset($_POST["orderby"]))
    $_POST["orderby"] = "type ASC, price DESC";

$stmt = $db->prepare("SELECT :columns FROM table WHERE age_min >= :age AND age_max <= :age AND :whereClause ORDER BY :orderby");
$stmt->bindParam(":columns", $_POST["columns"]);
$stmt->bindParam(":age", $customer_age);
$stmt->bindParam(":whereClause", $_POST["whereClause"]);
$stmt->bindParam(":orderby", $_POST["orderby"]);
$stmt->execute();

您可以使用HTML表单提交(导致页面重新加载)来调用它,也可以通过AJAX调用它。但无论哪种方式,我都没有看到如何做一个fetchAll并将结果存储在数组中对你有什么好处。

答案 2 :(得分:1)

根据数据库的大小,此解决方案可能无法正常工作,但通常我的工作方式是:

将数据库结果循环到我的设计数组中

所以我可能有

Array['baseball'][0]['price'] = 15.99
Array['baseball'][1]['price'] = 18.99

遍历我创建的数组以解析结果。

在较大的数据库中,您需要一个不同的解决方案,因为这会让您多次循环结果...