如何在PHP中构build一个跨数据库查询?
在我们的最后一集( 我如何在MySQL中构build一个跨数据库查询 )中,我学习了如何在MySQL中构build一个跨数据库查询。 这个效果很好,但是当我们的英雄试图在PHP中使用这个新发现的知识时,他发现他最好的朋友FAIL在等着他。
我看了一下PHP的mysql_select_db
。 这似乎意味着如果我想用PHP来使用MySQL,我有几个select:
-
使用
mysql_select_db
但一次只能使用一个数据库。 这是我们目前的设置,把一个数据库作为一个名称空间标识符似乎并不工作(它在MySQL shell中工作正常,所以我知道这不是我们的MySQL服务器设置的问题)。 -
不要使用
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>
。
但是,就像我指出的那样,这只适用于以下情况:
- 您在一个查询中访问的所有数据库都驻留在同一台服务器上,即由同一个MySQL实例pipe理
- 连接到数据库的用户有权访问这两个表。
场景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_db
select第一个数据库 - 然后连接到第二个数据库,必要时为
mysql_connect
的new_link
parameter passingtrue
,然后使用mysql_select_db
select第二个数据库
然后,使用由第一次或第二次调用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的例子。