繁体   English   中英

PHP如何构造跨库查询?

[英]How do I construct a cross database query in PHP?

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

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

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

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

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

澄清:所提出的答案实际上都没有让我进行跨数据库查询。 相反,它们允许我分别访问两个不同的数据库。 我想要一个解决方案,它允许我执行类似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
");

如果您的数据库在其他主机上运行,​​则将无法直接加入。 但是您可以进行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服务器实例中的表。 至少,您的说明文字:

从foreign_db.login中选择SELECT foreign_db.login.username,名字,姓氏,用户

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

在您的问题中,您说过要查询来自两个不同数据库的数据,但重要的是要认识到一个MySQL实例可以具有许多数据库。 对于由同一mysql实例管理的多个数据库,在您链接的问题中提出的解决方案很简单:仅在表名前加上数据库名,用点号分隔数据库和表名: <db-name>.<table-name>

但是,正如我指出的那样,这仅在以下情况下有效:

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

方案1:同一主机上的数据库:授予适当的特权并限定表名

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

例如, GRANT SELECT ON sakila.film TO 'test'@'%'将允许用户test@%sakila数据库中的film表中选择数据。 之后,该用户可以使用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罗兰。

一个解决方案可能是:

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

但这只是一个可行的解决方案,如果您拥有一个比另一个数据库使用更多的数据库...


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

您也许可以:

  • 使用mysql_connect连接到第一个数据库,然后使用mysql_select_db选择第一个数据库
  • 然后,连接到第二个数据库,如果需要,为mysql_connectnew_link参数传递true ,然后使用mysql_select_db选择第二个数据库

然后,根据要发出查询的数据库,使用第一个或第二个调用mysql_connect返回的连接标识符。


附带说明:“最佳” /“最mysql_* ”的解决方案不是直接使用mysql_*函数,而是与某种ORM框架一起使用,这种ORM框架能够同时处理多个数据库连接(不确定,但也许Doctrine可以做到这一点-这是一个非常好的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,也没有在查询中使用数据库名称。

我在单独的测试数据库中设置表,如下所示:

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()声明的“当前”数据库的数据库限定符。

每当您从多个表中进行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'

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

MySQL手册本身提供了较少详细的选项:

以下示例从db1数据库访问author表,从db2数据库访问editor表:

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 ...这是一个简单的查找和替换。

祝你好运!

我刚刚在计算机上尝试了这个简单的代码,它可以完美地工作:

<?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。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM