【问题标题】:find specific results in multiple joined and related tables在多个连接表和相关表中查找特定结果
【发布时间】:2013-01-14 00:38:50
【问题描述】:

我无法抽象地解释我的问题。这是一个非常简单的问题,但我需要通过这个非常明显的例子。它是完全组成的,因此应该可以与类似的应用程序相媲美。

我们有一堆包含用户信息的表格,我认为所有表格都是标准化的,有些值只是通过 ID 对其他表格的引用。

我正在使用 mySQL(以及带有 mysqli 扩展名的 PHP - 以防万一,我对此表示怀疑)

例如,这是我所拥有的:

table user_data

=====================================================
|| User_ID || Name || age || gender || location_ID ||
=====================================================
|| U000001 || Paul || 30  || m      || L00001      ||
|| U000002 || John || 20  || m      || L00001      ||
|| U000003 || Mike || 25  || m      || L00002      ||
|| U000004 || Anna || 25  || f      || L00003      ||


table user_personal_info

============================================
|| User_ID || color || food  || profession||
============================================
|| U000001 || red   || pizza || architect ||
|| U000002 || blue  || pasta || policeman ||
|| U000003 || green || steak || plumber   ||
|| U000004 || pink  || salad || teacher   ||


table locations

========================================================
|| location_ID || country || state      || city       ||
========================================================
|| L00001      || USA     || New York   || New York   ||
|| L00002      || USA     || New York   || Buffalo    ||
|| L00003      || USA     || California || Sacramento ||
|| L00004      || Canada  || Ontario    || Toronto    ||
|| L00005      || Canada  || Quebec     || Montreal   ||



table user_activities

=========================================
|| activity_ID  || user_ID || priority ||
=========================================
|| A0003        || U000001 || 5        ||
|| A0005        || U000001 || 4        ||
|| A0004        || U000002 || 2        ||
|| A0006        || U000002 || 1        ||
|| A0001        || U000003 || 3        ||
|| A0002        || U000004 || 4        ||
|| A0001        || U000004 || 1        ||
|| A0003        || U000004 || 5        ||

table activities

=================================
|| activity_ID  || description ||
=================================
|| A0001        || surfing     ||
|| A0002        || exercising  ||
|| A0003        || baseball    ||
|| A0004        || theater     ||
|| A0005        || dancing     ||
|| A0006        || reading     ||

好的,你明白这个概念了吧?

为了显示每个条目,我制作了以下 mySQL 语句,然后在 PHP 中循环遍历结果集,依此类推:

SELECT * FROM user_data
JOIN user_personal_info USING (User_ID)

为了也显示他们最喜欢的活动是什么,我还必须这样做:

SELECT * FROM user_activities 
WHERE user_ID = (current user_id)

当然,我必须通过附加查询来翻译活动 ID 代表什么以及位置 ID 代表什么...

(顺便说一句:有没有人对如何显示所有用户和与其关联的所有字段有更好的建议,而不是执行两个查询?)

现在我想构建一个彻底的搜索功能来找到非常具体的用户。 我会知道如何使用 PHP 过滤我的结果,但这需要我先下载整个数据库,而且一旦数据库中有几千个用户,这可能需要很长时间。

我知道如何找到来自特定位置(location_ID=L00001 左右)的男性、女性或两者兼有、喜欢食物或颜色的用户... 我知道如何分配有关年龄的规则(=、>、<... like>

我的问题是:

我如何找到来自某个国家或某个州的所有用户?
*我如何要求 mySQL 只显示那些用户,他们的 location_ID 与 location_ID 数组中的一个匹配?*

如何找到所有具有一项 AND/或更多特定活动的用户? 我如何要求 mySQL 只显示那些用户,谁的活动数组至少匹配数组中的所有活动(即 AND 版本)? *我如何要求 mySQL 只显示那些用户,谁的活动数组包含数组中的至少一个活动(即 OR 版本)?*

现在真正重要的问题是:

如何将这些语句与上面的正常语句结合起来? 含义:我如何找到来自纽约州的所有喜欢冲浪、男性和喜欢 PIZZA 的用户? 或者 我如何找到来自美国的所有喜欢阅读和跳舞、超过 30 岁且喜欢 GREEN 的用户? 或者 我如何找到来自加利福尼亚州萨克拉门托市的 PLUMBERS 和 FEMALE 的所有用户?

等等。等等,例子显然是无穷无尽的!

我相信有人会告诉我“你应该研究这个关键字”。但是因为我无法简洁地表达我的问题,所以我没有成功找到很多信息......

更新:

感谢您的回答。有人指出了一些有用的事情,以下是我不知道但现在做的事情的摘要:

  • 更有效地利用 JOIN
  • IN 运算符
  • GROUP BY 运算符与 HAVING COUNT() 结合使用
  • 和 SUB SELECTS

感谢您向我指出这些事情! :)

【问题讨论】:

    标签: mysql sql database search


    【解决方案1】:

    嗯,我认为您正在寻找的关键字之一是 IN 运算符。

    SELECT * FROM locations WHERE country IN ('USA', 'Canada', 'Denmark')
    

    将返回 IN 子句中的值之一与国家/地区字段匹配的所有行。所以就像这样写:

    SELECT * FROM locations WHERE country = 'USA' OR country = 'Canada' OR country = 'Denmark'
    

    至于你的其他问题:

    是否有人对如何显示所有用户和与其关联的所有字段有更好的建议,而不是执行两个查询?

    只需将它们全部连接在一起,例如:

    SELECT * FROM user_data
    JOIN locations ON user_data.location_ID = locations.location_ID
    JOIN user_personal_info ON user_data.User_ID = user_personal_info.User_ID
    JOIN user_activities ON user_personal_info.User_ID = user_activities.User_ID
    JOIN activities ON user_activities.activity_ID = activities.activity_ID
    

    当然,根据您的结构,您会使用LEFT JOINRIGHT JOIN 等。简单地通过SELECT * 检索所有数据也不是一个好习惯,而是真的只选择您需要的字段。 此外,您可以/应该创建一个/多个表示您需要的连接数据的视图并从中进行选择。

    我如何找到来自某个国家或某个州的所有用户?

    SELECT user_data.* FROM user_data
    JOIN locations ON user_data.location_ID = locations.location_ID
    WHERE locations.country = 'USA' AND state = 'New York'
    

    取决于您如何从用户那里获取数据以及如何为 PHP 中的语句准备数据。例如,假设您的用户搜索一个国家,而您通过 post 方法得到它:

    <?php
      $country = sanitize($_POST['country']);  // assuming a sanitation function for user input
      // whether by doing a sub-select
      $sql = "SELECT user_data.* FROM user_data WHERE user_data.location_ID = (SELECT locations.location_ID FROM locations WHERE locations.country LIKE '%{$country}%')";
    
      // or doing a join
      $sql = "SELECT user_data.* FROM user_data JOIN locations ON user_data.location_ID = locations.location_ID WHERE locations.country LIKE '%{$country}%'";
    ?>
    

    当然,同样的原则也适用于状态。

    如何找到所有具有一项和/或更多特定活动的用户?

    在这里,您需要加入活动表并使用 IN 运算符,如上所示。

    如何将这些语句与上面的正常语句结合起来?

    以您为例我如何找到来自纽约州的所有喜欢冲浪、男性和喜欢 PIZZA 的用户?

    SELECT user_data.* FROM user_data
     JOIN locations ON user_data.locations_ID = locations.location_ID
     JOIN user_activities = user_data.User_ID = user_activities.user_ID
     JOIN activities ON user_activities.activity_ID = user_activities.activity_ID
    WHERE locations.sate = 'New York'
      AND activities.description IN ('surfing')
      AND user_data.gender = 'm'
      AND user_personal_info.food = 'pizza'
    

    希望这对您有所帮助并让您朝着正确的方向前进。

    更新

    当然这里的 IN 运算符可以用description = 'surfing' 代替,因为它只有一个值。如果您添加另一个值,例如description IN ('surfing', 'reading'),那么您是对的,这意味着surfing OR reading。所以如果你想让所有用户都进入surfing AND reading,我想我会用一个子选择来做到这一点:

    SELECT user_data.* FROM user_data
     WHERE user_data.User_ID IN (
       SELECT user_activities.user_ID FROM user_activities
         JOIN activities ON user_activities.activity_ID = activities.activity_ID
        WHERE activities.description IN ('surfing', 'reading')
       GROUP BY user_activities.activity_ID
         HAVING COUNT(user_activities.user_ID) = 2
     )
    

    因此,子选择的意思是:计算出现“冲浪”或“阅读”的每个用户 ID,如果计数等于 2(意味着它们都匹配),则检索用户 ID。 而外部选择只是从子集的每个用户中选择数据。

    现在,我没有对此进行测试,因此可能会有所不同。并且可能有更简单的方法。至少你可以做一些事情来简化这个查询,就像我之前提到的那样创建一个视图并从中进行选择。

    【讨论】:

    • 太棒了,这很有帮助,谢谢!但是:如果添加“...谁喜欢冲浪和阅读”,现在会发生什么?您必须添加另一个条件AND activities.description IN ('reading') 对吗?但我认为结果将始终为 0,因为 JOIN 将为每个活动创建一个新的 ROW,所以 2 个活动永远不会在同一行......?同样的想法,假设有人喜欢 3 项活动。现在突然间,当拉人时,我总是会返回 3 行,即使它只有一个人。 num_rows 不会反映找到了多少人... ??!?
    • 我相应地更新了我的问题。啊,我忘记的一件事是你也可以使用DISTINCT。因此,如果返回 3 行相同,则 distinct 关键字将其减少为 1 个唯一行。
    • 非常感谢!!我更新了我的帖子,并指出了你刚刚教给我的伟大新事物! :D
    猜你喜欢
    • 2011-01-16
    • 1970-01-01
    • 2014-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多