首页  >  问答  >  正文

如何在PHP中构建跨数据库查询?

在我们的上一集(如何在 MySQL 中构建跨数据库查询)中,我学习了如何在 MySQL 中构建跨数据库查询。这很有效,但是当我们的英雄尝试在 PHP 中使用这些新发现的知识时,他发现他最好的朋友失败了。

我查看了 PHP 的 mysql_select_db 。这似乎意味着,如果我想将 MySQL 与 PHP 一起使用,我有几个选择:

  1. 使用 mysql_select_db 但每次只能使用一个数据库。这是我们当前的设置,将数据库作为命名空间标识符似乎不起作用(它在 MySQL shell 中工作正常,所以我知道这不是我们的 MySQL 服务器设置的问题)。

  2. 不要使用 mysql_select_db。从我看到的一些示例来看,这似乎意味着我必须为我所做的每个查询指定数据库。这是有道理的,因为我没有使用 mysql_select_db 来告诉 PHP 我想要访问哪个数据库。这也让人难过,因为我不想遍历所有代码并在每个查询前添加数据库名称。

还有比这更好的吗?有没有办法让我在 PHP 中进行跨数据库 MySQL 查询,而不必像 (2) 这样疯狂的事情?

澄清:所提出的答案实际上都没有让我进行跨数据库查询。相反,它们允许我分别访问两个不同的数据库。我想要一个解决方案,允许我执行类似 SELECTforeign_db.login.username,firstname,lastname fromforeign_db.login,user where... 的操作,而不仅仅是对不同的数据库进行不同的查询。就其价值而言,(2) 对我来说不起作用。

P粉197639753P粉197639753332 天前609

全部回复(2)我来回复

  • P粉077701708

    P粉0777017082023-10-23 11:15:52

    阅读您的说明后,我的印象是您实际上想要查询驻留在两个单独的 MySQL 服务器实例中的表。至少,您的澄清文字:

    建议您希望在以两个用户身份登录时运行一个查询(可能驻留在也可能不驻留在同一个 mysql 服务器实例上)。

    在您的问题中,您说您想要从两个不同的数据库查询数据,但重要的是要认识到一个 MySQL 实例可以有很多很多数据库。对于由同一 mysql 实例管理的多个数据库,您链接到的问题中提出的解决方案很简单:只需在表名前添加数据库名称前缀,用点分隔数据库和表名称:.<表名>.

    但是,就像我指出的那样,这只在以下情况下有效:

    1. 您在一个查询中访问的所有数据库都驻留在同一台服务器上 - 即由同一个 MySQL 实例管理
    2. 连接到数据库的用户具有访问这两个表的正确权限。

    场景1:同一主机上的数据库:授予适当的权限并限定表名称

    因此,如果这些表实际上驻留在同一个 mysql 实例上,则无需第二次登录或连接 - 只需授予您用于连接到数据库的数据库用户适当的权限,即可从您需要的所有表中进行选择。您可以使用 GRANT 语法来做到这一点,记录如下:http://dev.mysql.com/doc/refman/5.1/en/grant.html

    例如,GRANT SELECT ON sakila.film TO 'test'@'%' 将允许用户 test@%film 选择数据sakila 数据库中的 表。完成此操作后,用户可以使用 sakila.film(所谓的限定表名)引用该表,或者如果当前数据库设置为 sakila,只需如下所示电影

    场景2:由不同MySQL实例管理的数据库:FEDERATED引擎

    如果您要访问的表实际上由两个不同的 MySQL 实例管理,则有一个技巧可能有效,也可能无效,具体取决于您的配置。从MySQL 5.0开始,mysql支持FEDERATED存储引擎。这使您可以创建一个实际上不是表的表,而是远程服务器上表的窥视孔。该引擎记录在此处:http://dev. mysql.com/doc/refman/5.1/en/federated-storage-engine.html

    例如,如果您知道远程主机上的 misc 数据库中有此表:

    CREATE TABLE t (
        id int not null primary key
    ,   name varchar(10) not null unique
    )

    您可以使用以下命令创建指向该远程表的本地“指针”:

    CREATE TABLE t (
        id int not null primary key
    ,   name varchar(10) not null unique
    )
    ENGINE = FEDERATED
    CONNECTION='mysql://<user>@<remote-server>:<remote-port>/misc/t';

    不幸的是,FEDERATED 引擎并不总是可用,因此您必须首先检查是否可以使用它。但假设是这样,那么您可以在查询中简单地使用本地表 t,就像任何其他表一样,MySQL 将与远程服务器通信并对另一端的物理表执行适当的操作。

    警告:FEDERATED 表存在多个优化问题。您应该了解这些是否以及在多大程度上适用于您。例如,在许多情况下,将 WHERE 应用于联合表可能会导致整个表内容通过网络拉至本地服务器,在本地服务器上应用实际的过滤。另一个问题是表创建:您必须非常确定联合表及其指向的表的定义完全匹配,除了 ENGINE 子句(和 CONNECTION)。例如,如果您有不同的字符集,则数据在通过网络传输后可能会完全乱码。

    如果您想使用FEDERATED表,请阅读这篇文章http://oreilly.com/pub/a/databases/2006/08/10/mysql-federated-tables.html 来决定它是否适合您特定用例。

    如果您认为确实需要它,我有一个实用程序可以在此处创建联合表:http://forge.mysql.com/tools/tool.php?id=54

    场景3:无法使用FEDERATED,但表位于不同的MySQL实例上

    最后,如果您在不同的 MySQL 实例上有表,但由于某种原因无法使用联合表引擎,那么恐怕您就不走运了。您只需对两个 MySQL 实例执行查询、接收结果并在 PHP 中执行一些智能操作。根据您的具体要求,这可能是一个完全可行的解决方案

    我想您需要自己决定我的答案的哪一部分最能解决您的问题,并添加评论以防您需要更多帮助。蒂亚·罗兰。

    回复
    0
  • P粉481366803

    P粉4813668032023-10-23 10:00:37

    您将需要数据库在同一主机上运行。

    如果是这样,您应该能够在您最喜欢的/默认数据库上使用 mysql_select_db 并手动指定外部数据库。

    $db = mysql_connect($hots, $user, $password);
    mysql_select_db('my_most_used_db', $db);
    
    $q = mysql_query("
        SELECT *
        FROM   table_on_default_db a, `another_db`.`table_on_another_db` b
        WHERE  a.id = b.fk_id
    ");

    如果您的数据库运行在不同的主机上,您将无法直接加入。但随后您可以进行 2 个查询。

    $db1 = mysql_connect($host1, $user1, $password1);
    $db2 = mysql_connect($host2, $user2, $password2);
    
    $q1 = mysql_query("
        SELECT id
        FROM   table
        WHERE  [..your criteria for db1 here..]
    ", $db1);
    $tmp = array();
    while($val = mysql_fetch_array($q1))
        $tmp[] = $val['id'];
    
    $q2 = mysql_query("
        SELECT *
        FROM   table2
        WHERE  fk_id in (".implode(', ', $tmp).")
    ", $db2);

    回复
    0
  • 取消回复