mysql - 在多个连接表和相关表中查找特定结果

标签 mysql sql database search

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

我们有一堆包含用户信息的表,我认为所有表都是规范化的,一些值仅通过 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 匹配的用户?*

我如何找到进行一项和/或多项特定事件的所有用户? 我如何要求 mySQL 只显示那些用户,他们的事件数组至少匹配数组中的所有事件(这将是 AND 版本)? *我如何要求 mySQL 只显示那些用户,他们的事件数组至少包含数组中的一个事件(即 OR 版本)?*

现在真正重要的问题是:

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

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

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

更新:

感谢您的回答。我被指出了一些有用的事情,这里是我不知道但现在做的事情的总结:

  • 更有效地利用 JOIN
  • IN 运算符
  • GROUP BY 运算符结合 HAVING COUNT()
  • 和子选择

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

最佳答案

好吧,我认为您正在寻找的关键字之一是 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 * 简单地检索所有数据也不是一个好习惯。 ,但实际上只选择您需要的字段。 此外,您可以/应该创建一个/多个 View 来表示您需要的联合数据并从中选择。

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

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。 外层选择只是从子集中的每个用户中选择数据。

现在,我没有对此进行测试,因此它可能会有所不同。并且可能有更简单的方法。至少您可以按照我之前提到的那样创建一个 View 并从中进行选择来简化此查询。

关于mysql - 在多个连接表和相关表中查找特定结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14309963/

相关文章:

制作触发器查找标签并将其添加到其他表时出现 mySQL 错误

MySQL Order By 备用值

SQLITE:显示每个类别的总计(总和)

mysql - MySql中如何使用触发器制作外键

java - 从 GAE 连接到 MySQL 实例时出现 CommunicationsException

php - MySQL 查询 : insert if entry is duplicate otherwise update the existing row values

sql - 甲骨文特殊字符

c - Win32开发。标准

mysql - SQL计算部分数据的SUM

sql - MS Access 选择表中的第 N 个最高值