充分利用单个 MySQL 查询

Posted

技术标签:

【中文标题】充分利用单个 MySQL 查询【英文标题】:Getting the most from a single MySQL query 【发布时间】:2012-11-13 19:42:07 【问题描述】:

我有一个网站,列出了可供出租的公寓。我的 mysql 数据库中有几个不同的表。一张表格是关于整个公寓楼的基本信息,包括地址、便利设施、照片、身份证 (NID) 等。

另一个表格列出了每栋建筑内可供出租的单元。所以每栋公寓楼都有多个平面图,有几个工作室、几个一居室单元,有时还有几个二居室单元等。

目前我查询我的“单元”表并询问给定公寓楼中的所有单元。我的查询类似于SELECT * FROM node_unit WHERE nid='555'

这可能会返回如下内容:

NID    Name       Rent    SqFT    Bedrooms    Bathrooms
555    Unit 1     $500    620      0            1
555    Unit 2     $550    680      0            1
555    Unit 3     $600    820      1            1
555    Unit 4     $650    920      1            1
555    Unit 5     $700    1220     2            1
555    Unit 6     $800    1420     2            2
555    Unit 7     $900    1500     3            2
555    Unit 8     $1100   1620     3            3

等等等等

然后我在我的 php 中做的是使用手风琴将 1 间卧室组合在一起,将 2 间卧室组合在一起,等等。

并非所有公寓都有 2 个卧室单元,有些只有 1 个卧室单元,所以我需要在我的 PHP 代码中知道是否应该打印另一个手风琴。

目前我正在对数据库进行多次点击来确定给定的建筑物是否有任何 2 个卧室单元,如果有,则打印另一行。这栋楼有三居室单位吗?如果是这样打印另一行,但我想停止这么多访问我的数据库。

最后,这是我的问题:

如何存储我的第一个 DB 调用的结果并以某种方式解析数据并确定给定的 NID 是否有工作室、1 张床、2 张床等? (我最近才开始学习PHP/MySQL)

【问题讨论】:

请发布您当前的脚本,否则很难提出建议。 只要结果卷不超过特定大小限制,您就可以检索结果中的所有条目并将它们简单地存储在 php 数组中。然后,您将拥有世界上所有的时间来完成并提取您需要的任何信息。不过,不确定这是否更快...... 【参考方案1】:

我建议这样的查询:

SELECT * FROM node_unit WHERE nid='555'
ORDER BY Bedrooms ASC, Bathrooms ASC, Rent ASC

这将返回您按卧室数、# 间浴室和租金金额(按此顺序)排序的记录。

当像这样从数据库读取时,您可以轻松地将其存储在多维数组中(假设 mysqli 与存储在 $result 中的结果集一起使用,但其他数据库连接库的概念相同)

$room_array = array();
while ($row = mysqli_fetch_assoc($result)) 
    $room_array[(int)$row['Bedrooms']][] = $row;

您现在有一个以卧室数作为第一个索引的多维数组。如果你var_dump它,数组可能看起来像这样:

Array (
    [0] => Array (
        [0] => Array (
            'NID' => '555',
            'Name' => 'Unit 1',
            'Rent' => '$500',
            'SqFt' => '620',
            'Bedrooms' => '0',
            'Bathrooms' => '1',
        )
        [1] => Array (
            'NID' => '555',
            'Name' => 'Unit 2',
            'Rent' => '$550',
            'SqFt' => '680',
            'Bedrooms' => '0',
            'Bathrooms' => '1',
        )
    )
    [1] => Array (
        [0] => Array (
            'NID' => '555',
            'Name' => 'Unit 3',
            'Rent' => '$600',
            'SqFt' => '820',
            'Bedrooms' => '1',
            'Bathrooms' => '1',
        )
        [1] => Array (
            'NID' => '555',
            'Name' => 'Unit 4',
            'Rent' => '$650',
            'SqFt' => '920',
            'Bedrooms' => '1',
            'Bathrooms' => '1',
        )
    [2] => Array (
        ...
    )
    [3] => Array (
        ...
    )
)

这使得在外部循环中迭代卧室值的数量变得非常容易,这会创建您的手风琴,然后在内部循环中迭代各个房间。

foreach ($room_array as $num_bedrooms => $rooms) 
    // start accordion
    foreach ($rooms as $room) 
        // output room details
    
    // end accordion

所有这些都只需要一个查询。

还要确保你有关于卧室、浴室、租金(或你在排序中使用的任何一个)以及 nid 的索引,因为它被用作过滤器。

【讨论】:

感谢您的帮助。这似乎是一个很好的方法。使用您的代码,我能够设置一个数组,然后在 foreach 中使用 print_r 我可以看到该数组正在正确设置数据。在我的最后,卧室是第 5 个索引,而不是第一个,我不确定这是否重要。不过我想知道,既然数据在一个数组中,我怎样才能只抓住 1 间卧室或 2 间卧室?您列出的 foreach 示例循环通过,但我想将项目分组到手风琴中。我确定我只是缺少一些简单的东西。我可以说“如果索引 [5]​​ = “3” 那么... 我想通了,只是需要另一个循环:if ($room['5'] == 0) echo "studios"; if ($room['5'] == 1) echo "1 bedrooms"; 您一定没有按照我提到的方式设置阵列。如果按照我提到的方式完成,我添加了一个 var_dump 的示例。数组的第一级代表一组卧室数量。第一维索引为 0 的所有东西都有 0 个卧室,索引为 1 的所有东西都有一个卧室,依此类推。【参考方案2】:

尝试将此作为您的数据库查询,它会为每个建筑物为其拥有的每种单元类型生成一行。您还可以将其用作子查询并连接到父表,以便一次性获取有关建筑物的任何其他详细信息。

select 'studio' as unit_type, nid from node_unit group by nid having count(case when bedrooms = 0 then 1 end) > 0
union all
select 'one bedroom' as unit_type, nid from node_unit group by nid having count(case when bedrooms = 1 then 1 end) > 0
union all
select 'two bedroom' as unit_type, nid from node_unit group by nid having count(case when bedrooms = 2 then 1 end) > 0
union all
select 'three bedroom' as unit_type, nid from node_unit group by nid having count(case when bedrooms = 3 then 1 end) > 0

【讨论】:

这将是一个非常低效的查询。如果您希望将字符串值作为单位类型返回,则最好采用我的答案中显示的查询并将 case 语句放入 SELECT 中,例如 SELECT nid, name, rent, sqft, (CASE WHEN bedrooms = 0 THEN 'studio' WHEN bedrooms = 1 THEN 'one_bedroom' WHEN bedrooms = 2 THEN 'two bedrooms' WHEN bedrooms = 3 THEN 'three bedrooms' END CASE) as unit_type, bedrooms, bathrooms FROM node_unit WHERE nid='555' ORDER BY bedrooms ASC, bathrooms ASC, rent ASC 当然,您的建议更有效,但它不会为每个建筑物和房间组合生成新行,以便轻松绑定到 Jay 所追求的 UI。有很多方法可以生成相同的结果集,而无需在桌面上进行四次传递,但根据观众,我认为太高级是不合适的。

以上是关于充分利用单个 MySQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

mysql 多实例应用配置部署指南

组合查询

MySQL必知应会-第17章-组合查询

如何在PHP / MySQL应用程序中充分利用多核CPU? MyISAM InnoDB

mysql性能优化-自我总结

第十七章 组合查询