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

时间:2010-01-04 12:23:39

标签: php mysql

在我们的上一集(How I constructed a cross database query in MySQL)中,我学习了如何在MySQL中构建跨数据库查询。这很有效但当我们的英雄试图在PHP中使用这个新发现的知识时,他发现他最好的朋友FAIL在等他。

我看了mysql_select_db的PHP。这似乎暗示如果我想在PHP中使用MySQL,我有几个选择:

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

  2. 请勿使用mysql_select_db。从我看过的一些例子中,这似乎意味着我必须为我所做的每个查询指定数据库。这是有道理的,因为我没有使用mysql_select_db告诉PHP我想要访问什么数据库。这也令人伤心,因为我不想浏览所有代码并在每个查询中添加数据库名称。

  3. 有没有比这更好的东西?有没有办法让我在PHP中进行跨数据库MySQL查询而不必像(2)那样疯狂?

    澄清:所提出的答案都没有让我做一个跨数据库查询。相反,它们允许我分别访问两个不同的DB。我想要一个允许我做SELECT foreign_db.login.username, firstname, lastname from foreign_db.login, user where ...之类的解决方案,而不仅仅是对不同的DB进行不同的查询。对于它的价值,(2)对我不起作用。

9 个答案:

答案 0 :(得分:19)

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

如果是这样,您应该能够在您喜欢的/默认数据库上使用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);

答案 1 :(得分:5)

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

  

从foreign_db.login中选择foreign_db.login.username,firstname,lastname,用户在哪里

建议您在以两个用户(可能存在也可能不存在于同一个mysql服务器实例中)的同时登录时运行一个查询。

在你的问题中,你说你想查询来自两个不同数据库的数据,但重要的是要意识到一个MySQL实例可以拥有许多很多数据库。对于由同一个mysql实例管理的多个数据库,您链接的问题中提出的解决方案只是起作用:只需在表名前加上数据库的名称,用点分隔数据库和表名:<db-name>.<table-name>。 / p>

但是,正如我所指出的,这只适用于:

  1. 您在一个查询中访问的所有数据库都驻留在同一服务器上 - 即由同一个MySQL实例管理
  2. 连接到数据库的用户具有访问这两个表的权限。
  3. 场景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,则只需film

    场景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中执行一些智能操作。根据您的具体要求,这可能是一个非常可行的解决方案

    我想你需要自己决定我的答案的哪一部分最能吸引你的问题,并在你需要更多帮助时添加评论。 TIA Roland。

答案 2 :(得分:3)

解决方案可能是:

  • 使用mysql_select_db选择“默认”(即最常用的)数据库
  • 并仅在必须使用“第二个”(即最少使用)数据库的查询中指定数据库名称。

但如果你有一个比其他数据库更常用的数据库,这只是一个可行的解决方案......


出于好奇:您是否尝试与数据库服务器建立多个连接 - 即每个数据库一个连接?

您可以:

  • 使用mysql_connect连接到第一个数据库,然后选择带有mysql_select_db的第一个数据库
  • 然后,连接到第二个数据库,如有必要,将true new_link参数传递给mysql_connect,然后选择带有mysql_select_db的第二个数据库

然后,使用第一次或第二次调用mysql_connect返回的连接标识符,具体取决于您要发出查询的数据库。


作为旁注:“最佳”/“最干净”的解决方案不是直接使用mysql_*函数,而是使用某种ORM框架,它可以同时处理多个数据库连接< em>(不确定,但也许Doctrine可以做到这一点 - 这是一个非常好的ORM)

答案 3 :(得分:0)

也许这就是你想要的代码


//create links
$link1 = mysql_connect('localhost', 'mysql_user', 'mysql_password');
$link2 = mysql_connect('localhost', 'mysql_user', 'mysql_password');

//set db on every link
mysql_select_db('foo', $link1);
mysql_select_db('bar', $link2);

//do query with specified link
$result1 = mysql_query($query1,$link1);
$result2 = mysql_query($query2,$link2);

请注意,我们没有在查询之间执行mysql_select_db,也没有在查询中使用数据库名称。

答案 4 :(得分:0)

我在不同的测试数据库中设置表格如下:

mysql> use test;
mysql> create table foo as select 42 as id from dual;
mysql> create database test2;
mysql> use test2;
mysql> create table bar as select 42 as id from dual;

我在Mac OS X上使用MySQL 5.1.41和PHP 5.3.1运行以下PHP脚本:

<?php

$link = mysql_connect('localhost', 'root', 'XXXX')
 or die('There was a problem connecting to the database.');
mysql_select_db('test');

$sql = "SELECT * FROM foo JOIN test2.bar USING (id)";
if (($result = mysql_query($sql)) === FALSE) {
  die(mysql_error());
}

while ($row = mysql_fetch_array($result)) {
  print_r($row);
}

此测试成功。结果是两个表在不同数据库中的连接。

您应始终能够从SQL中的各自数据库名称限定的表中进行选择。 PHP中的mysql API不会限制您查询一个数据库。

您应始终能够省略“当前”数据库的数据库限定符,并使用mysql_select_db()声明该数据库限定符。

答案 5 :(得分:0)

每当你SELECT来自多个表时,你必须分离别名。所以从那里开始很简单:

SELECT
    a.id, a.name, a.phone,
    b.service, b.provider

FROM
    `people` AS a,

LEFT JOIN
    `other_database`.`providers` AS b ON a.id = b.userid

WHERE
    a.username = 'sirlancelot'

正如本页上的其他人所提到的,数据库必须位于同一主机和实例上。您无法使用此语法从其他服务器查询数据库。

答案 6 :(得分:0)

MySQL Manual本身提供的详细信息较少:

  

以下示例访问   来自db1数据库的作者表和   db2的编辑器表   数据库:

USE db1;
SELECT author_name, editor_name FROM author, db2.editor
WHERE author.editor_id = db2.editor.editor_id;

答案 7 :(得分:0)

您可以使用选项二:“不要使用mysql_select_db”,然后使用mysql_db_query代替mysql_query ...这是一个简单的查找和替换。

祝你好运!

答案 8 :(得分:0)

我刚在计算机上尝试过这个简单的代码,它运行得很完美:

<?php

$conn = mysql_connect('localhost', 'root', '....');
mysql_select_db('aliro');

$sql = 'select * ' .
    'from aliro_permissions a ' .
    'left join cmsmadesimple.cms_permissions b on a.id=b.permission_id ';

$res = mysql_query($sql)
    or die(mysql_error());
while($row = mysql_fetch_assoc($res)){
    print_r($row);
}

?>

(当然,查询本身毫无意义,只是一个例子。)

所以我无法确切地看到你的确切问题。如果你想要一个比这更简单的语法,你必须提供一个你想要写的SQL类型的例子。