【问题标题】:How can I save PHP arrays to a MySQL database so that I can search through the arrays on the database?如何将 PHP 数组保存到 MySQL 数据库,以便可以搜索数据库中的数组?
【发布时间】:2023-03-21 02:13:01
【问题描述】:

我正在尝试为我的用户使用的语言建立一个可搜索的数据库。

例如我可能有

$john = array("english", "french", "spanish");
$jack = array("french", "spanish");
$jill = array("english", "spanish");

我想将它们保存到 MySQL 数据库中,以便以后可以按照(伪代码)的方式运行一些东西

SELECT * FROM users WHERE spoken_languages = "french" and "spanish"

我知道如果我有 speaks_englishspeaks_frenchspeaks_spanish 列,那么我可以搜索

SELECT * FROM users WHERE speaks_french = "true" and speaks_spanish = "true"

但是每次遇到新语言都加一列的扩展性不是很好。我考虑过像

这样的表
john | english
john | french
john | spanish
jack | french
jack | spanish
jill | english
jill | spanish

因为至少要恢复用户说的语言,我可以运行

SELECT * FROM spoken_languages WHERE user = "jack"

但是为了搜索会说法语和西班牙语的人,我需要查询所有说法语的用户,所有说西班牙语的用户,然后计算交叉点。这似乎非常低效。

所以我问你,我怎样才能保存这个口语数组,以便我以后可以在不破坏服务器的情况下搜索数据库?

【问题讨论】:

  • 您建议的表格布局是推荐的。您可以调整它以使用 user_id 和 language_id 使其更小
  • 一个用户表、一个语言表和一个用户/语言表走进一个酒吧....然后就产生了多对多的关系。
  • 使用你考虑的结构,数据库擅长做交集的事情只要你知道足够的SQL
  • @RiggsFolly 你能给我一个样品吗?我不太擅长 SQL
  • @JayBlanchard 不,不,等等-- 一个用户、一种语言和一个 DBMS 走进一家酒吧... ...等等等等等等... ...调酒师说, “...来自不同的领域,但同一张桌子会排成一行!”

标签: php mysql sql database relational-division


【解决方案1】:

您的问题有正确的解决方案,person_language 表看起来像这样

john | english
john | french
jack | spanish

你可以这样查询。

SELECT person
  FROM person_language
 WHERE language IN ( 'english', 'spanish')
 GROUP BY person
HAVING COUNT(*) = 2

(language, person) 上放置一个索引,这样可以正常扩展。

如果您希望每个会说西班牙语和至少一种其他语言的人都可以这样做。

 SELECT a.person
   FROM person_language AS a
   JOIN ( SELECT person
            FROM person_language
           GROUP BY person
          HAVING COUNT(*) >= 2
        ) AS b ON a.person = b.person
  WHERE a.language = 'spanish'

这使用 JOIN 指令来获取说西班牙语的人与说两种或多种语言的人的交集。

【讨论】:

  • 不相关的问题,但是如果使用 WHERE 子句作为WHERE language = 'english' || language = 'spanish' 编写此查询,是否会有任何显着的性能差异?
  • 不会以这种方式返回所需的结果
  • @echochamber 我相信这就是 MySQL 运行查询的方式。无论哪种方式,对两个查询都使用 explain 以查看任何差异。
【解决方案2】:

您可以使用 自连接 以有效的方式执行此查询:

SELECT * FROM users u1
JOIN users u2 USING (user)
WHERE (u1.lang, u2.lang) = ('french', 'spanish')

在我的演示文稿SQL Query Patterns, Optimized 中查看关系划分解决方案的示例。

如果您有正确的索引,我的测试表明这种自联接解决方案比 GROUP BY 解决方案快大约 20 倍。

【讨论】:

    【解决方案3】:

    我会像这样设置三张桌子

    CREATE TABLE languages
    (
      `id` int not null auto_increment primary key, 
      `language` varchar(32) unique
    );
    CREATE TABLE users
    (
      `id` int not null auto_increment primary key,
      `name` varchar(32)
    );
    CREATE TABLE user_language
    (
      `user_id` int, 
      `language_id` int,
      primary key (user_id, language_id)
    );
    

    恕我直言,如果您没有数以百万计的用户和所有可能的语言并寻求灵活性而不是为毫秒而战,特别是如果您一次检查超过 2 种语言,您可以使用 MAX()SUM() 聚合在 HAVING 子句中。

    这里有一些示例查询:

    -- Speaks both French AND Spanish
    SELECT u.name
      FROM user_language ul JOIN languages l
        ON ul.language_id = l.id JOIN users u
        ON ul.user_id = u.id
     GROUP BY u.id
    HAVING MAX(l.language = 'french') = 1
       AND MAX(l.language = 'spanish') = 1;
    

    输出:

    |姓名 | |--------| |约翰 | |杰克 |
    -- Speaks both French OR Spanish
    SELECT u.name
      FROM user_language ul JOIN languages l
        ON ul.language_id = l.id JOIN users u
        ON ul.user_id = u.id
     GROUP BY u.id
    HAVING MAX(l.language = 'french') +
           MAX(l.language = 'spanish') > 0;
    

    输出:

    |姓名 | |--------| |约翰 | |杰克 | |吉尔 |
    -- Speaks any language French OR Spanish BUT NOT English
    SELECT u.name
      FROM user_language ul JOIN languages l
        ON ul.language_id = l.id JOIN users u
        ON ul.user_id = u.id
     GROUP BY u.id
    HAVING MAX(l.language = 'french') +
           MAX(l.language = 'spanish') > 0
       AND MAX(l.language = 'english') = 0;
    

    输出:

    |姓名 | |--------| |杰克 |
    -- Speaks any language but English
    SELECT u.name
      FROM user_language ul JOIN languages l
        ON ul.language_id = l.id JOIN users u
        ON ul.user_id = u.id
     GROUP BY u.id
    HAVING MAX(l.language = 'english') = 0;
    

    输出:

    |姓名 | |--------| |杰克 |
    -- What languages does Jack speak
    SELECT l.language
      FROM user_language ul JOIN languages l
        ON ul.language_id = l.id JOIN users u
        ON ul.user_id = u.id
     WHERE u.name = 'Jack';
    

    输出:

    |语言 | |-----------| |法语 | |西班牙语 |
    -- How many languages do users speak
    SELECT u.name, COUNT(*) no_of_languages
      FROM users u LEFT JOIN user_language ul
        ON u.id = ul.user_id
     GROUP BY u.id;
    

    输出:

    |姓名 | NO_OF_LANGUAGES | |--------|-----------------| |约翰 | 3 | |杰克 | 2 | |吉尔 | 2 |
    -- How many users do speak a particular language
    SELECT l.language, COUNT(*) no_of_users
      FROM languages l LEFT JOIN user_language ul
        ON l.id = ul.language_id
     GROUP BY l.id;
    

    输出:

    |语言 | NO_OF_USERS | |------------|-------------| |英语 | 2 | |法语 | 2 | |西班牙语 | 3 |

    现在真正的应用程序中,您很可能不会使用语言或用户名,而是处理来自您的 UI(下拉框或任何)。因此,您将能够从等式中消除一个联接,并且您的查询看起来会像这样

    -- Speaks both French AND Spanish with Ids
    SELECT u.name
      FROM user_language ul JOIN users u
        ON ul.user_id = u.id
     GROUP BY u.id
    HAVING MAX(ul.language_id = 2) = 1
       AND MAX(ul.language_id = 3) = 1;
    

    这里是SQLFiddle演示

    【讨论】:

      猜你喜欢
      • 2012-09-29
      • 2018-02-17
      • 1970-01-01
      • 1970-01-01
      • 2014-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-12
      相关资源
      最近更新 更多