如何在PHP中构build一个跨数据库查询?

在我们的最后一集( 我如何在MySQL中构build一个跨数据库查询 )中,我学习了如何在MySQL中构build一个跨数据库查询。 这个效果很好,但是当我们的英雄试图在PHP中使用这个新发现的知识时,他发现他最好的朋友FAIL在等着他。

我看了一下PHP的mysql_select_db 。 这似乎意味着如果我想用PHP来使用MySQL,我有几个select:

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

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

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

澄清 :没有build议的答案实际上让我做跨数据库查询。 相反,他们允许我分别访问两个不同的数据库。 我想要一个解决scheme,让我做一些像SELECT foreign_db.login.username, firstname, lastname from foreign_db.login, user where ...不只是对不同的数据库进行不同的查询。 对于它的价值,(2)对我不起作用。

你将需要你的数据库在同一个主机上运行。

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

如果您的数据库在不同的主机上运行,​​您将无法直接join。 但是你可以做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); 

在阅读你的说明后,我觉得你实际上想要查询两个单独的MySQL服务器实例中的表。 至less,你的澄清文本:

从foreign_db.login中selectforeign_db.login.username,名字,姓氏,用户所在

build议您在以两个用户身份(可能驻留在同一个mysql服务器实例中)的情况下运行一个查询。

在你的问题中,你说过你想要从两个不同的数据库查询数据,但是认识到一个MySQL实例可以有很多很多的数据库是很重要的。 对于由同一个mysql实例pipe理的多个数据库,链接到的问题中提出的解决scheme只是简单的工作:只在表名称前加上数据库的名称,用点分隔数据库和表名: <db-name>.<table-name>

但是,就像我指出的那样,这只适用于以下情况:

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

场景1:同一主机上的数据库:授予应用程序权限并限定表名

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

例如, GRANT SELECT ON sakila.film TO 'test'@'%'将允许用户test@%sakila数据库的film表中select数据。 这样做之后,所述用户可以使用sakila.film (所谓的合格的表名)来参考该表,或者如果当前数据库被设置为sakila ,则简单地作为film

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

如果您要访问的表实际上是由两个不同的MySQL实例pipe理的,则根据您的configuration,有一个技巧可能会也可能不会。 由于MySQL 5.0 mysql支持FEDERATED存储引擎。 这使您可以创build一个实际上不是表的表,而是创build一个远程服务器上的表的窥视孔。 这个引擎logging在这里: 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 ) 

你可以使用下面的方法创build一个到这个远程表的本地“指针”:

 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应用于联邦表可能会导致整个表内容被拉到您的本地服务器,在那里实际的过滤将被应用。 另一个问题是创build表格:除了ENGINE子句(和CONNECTION)之外,您必须非常确定联合表格和它指向的表格的定义是否完全匹配。 如果您有不同的字符集,数据可能在通过电线后完全混乱。

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

如果你认为你确实需要它,我可以在这里创build联邦表: http : //forge.mysql.com/tools/tool.php?id=54

场景3:不能使用FEDERATED,而是使用不同MySQL实例的表

最后,如果你有不同的MySQL实例上的表,但由于某种原因不能使用联邦表引擎,你恐怕运气不好。 你只需要对两个MySQL实例执行查询,接收结果并在PHP中对其进行智能化处理。 取决于您的具体要求,这可能是一个完美可行的解决scheme

我想你需要自己决定我的答案的哪一部分最能吸引你的问题,如果你需要更多的帮助,请添加评论。 TIA罗兰。

解决办法可能是:

  • 使用mysql_select_db来select“默认” (即最常用的)数据库
  • 并只在需要使用“第二”(即最less使用)数据库的查询中指定数据库名称。

但是这只是一个可行的解决scheme,如果你有一个数据库比其他更多的使用…

出于好奇:你是否尝试build立几个连接到你的数据库服务器 – 即每个数据库一个?

您可能能够:

  • mysql_connect连接到第一个数据库,然后用mysql_select_dbselect第一个数据库
  • 然后连接到第二个数据库,必要时为mysql_connectnew_linkparameter passingtrue ,然后使用mysql_select_dbselect第二个数据库

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

作为一个旁注:“最好”/“最干净的”解决scheme不会直接使用mysql_*函数,而是使用某种ORM框架,这将有能力同时使用多个数据库连接(不确定,但也许主义可以做到这一点 – 这是一个真正的好ORM)

也许这是你想要的代码


 //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,而且查询中也没有使用数据库名称。

我在单独的testing数据库中设置了如下表格:

 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); } 

这个testing成功了。 结果是在不同数据库中的两个表之间的连接。

您应该始终能够从SQL中的相应数据库名称限定的表中进行select。 PHP中的mysql API不限制您查询一个数据库。

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

无论何时从多个表中select,都必须将一个别名进行validation。 所以这很简单:

 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' 

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

MySQL手册本身提供的冗长选项较less:

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

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

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

祝你好运!

我刚刚在我的电脑中试过这个简单的代码,它完美的工作:

 <?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的例子。