1

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

我们有一堆包含用户信息的表格,所有表格都是我认为已标准化的表格,有些值只是通过 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 岁并且喜欢绿色的用户? 或者 我如何找到来自加利福尼亚州萨克拉门托的水管工和女性的所有用户?

等等等等这些例子显然是无穷无尽的!

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

更新:

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

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

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

4

1 回答 1

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

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

于 2013-01-14T01:42:28.840 回答