2010-01-04 13 views
9

En nuestro último episodio (How I constructed a cross database query in MySQL) aprendí a construir una consulta de base de datos cruzada en MySQL. Esto funcionó muy bien, pero cuando nuestro héroe trató de utilizar este nuevo conocimiento en PHP, encontró a su mejor amigo FAIL esperándolo.¿Cómo construyo una consulta de base de datos cruzada en PHP?

Eché un vistazo a mysql_select_db para PHP. Esto parece implicar que si quiero usar MySQL con PHP, tengo un par de opciones:

  1. Uso mysql_select_db pero estar pegado sólo con el uso de un dB a la vez. Esta es nuestra configuración actual y poner una base de datos como un identificador de espacio de nombres no parece funcionar (funciona bien en el shell de MySQL, así que sé que no es un problema con nuestra configuración de servidor MySQL).

  2. No utilice mysql_select_db. De algunos de los ejemplos que he visto, esto parece significar que tengo que especificar el DB para cada consulta que hago. Esto tiene sentido ya que no he usado mysql_select_db para decirle a PHP a qué db quiero acceder. Esto también es triste ya que no quiero revisar todo mi código y anteponer un nombre db a cada consulta.

¿Hay algo mejor que esto? ¿Hay alguna manera de hacer una consulta MySQL cross db en PHP sin tener que hacer algo tan loco como (2)?

ACLARACIÓN: Ninguna de las respuestas propuestas en realidad me permite hacer una consulta cross db. En cambio, me permiten acceder a dos DB diferentes por separado. Quiero una solución que me permita hacer algo como SELECT foreign_db.login.username, firstname, lastname from foreign_db.login, user where ... NO simplemente hacer diferentes consultas a diferentes bases de datos. Por lo que vale, (2) no funciona para mí.

+0

Después de algunas pruebas, por cualquier razón, mi configuración no me permite hacer el número (2). Siempre necesito usar mysql_select_db. Algo que sí funciona es usar mysql_select_db para cambiar entre dbs, pero esto no me permite hacer consultas cross db. Estoy pensando en algo como select * from main_db.login, customerInfo donde ... etc. – Avery

+0

(2) es la respuesta correcta. Mi servidor PHP hace cientos de consultas por minuto con parte de los datos de una segunda base de datos especificada por nombre. Entonces la pregunta es menos "¿Cómo hago esto?" y más "¿Por qué no funciona?" – grahamparks

+0

Después de una intensa búsqueda, lo hice funcionar como crees que debería: SELECCIONAR DE * foreigndb.login DONDE ... No estoy seguro de quién recibe la recompensa ... Tal vez puedo deponer esta pregunta ... y luego lanzar algunos puntos de reputación en el contenedor de caridad. – Avery

Respuesta

17

Necesitará que sus bases de datos se ejecuten en el mismo host.

Si es así, debería poder usar mysql_select_db en su db favorito/predeterminado y especificar manualmente una base de datos extranjera.

$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 
"); 

Si sus bases de datos se ejecutan en un host diferente, no podrá unirse directamente. Pero puedes hacer 2 consultas.

$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

Cómo imprimir la salida para arriba del código "las bases de datos se ejecutan en un host diferente"? –

3

Una solución podría ser:

  • uso mysql_select_db para seleccionar el "default" (es decir más usado) base de datos
  • y especifique el nombre del DB sólo en las consultas que tienen que trabajar con el " segunda base de datos "(es decir, menos utilizada).

pero esto es sólo una solución viable si tiene una base de datos que es más utilizado que el otro ...


Por curiosidad: ¿Usted intentó establecer varias conexiones con el servidor de base de datos - es decir, uno para cada base de datos?

Usted puede ser capaz de:

  • conectarse a la primera base de datos con mysql_connect, y, a continuación, seleccionar la primera base de datos con mysql_select_db
  • y, a continuación, conectarse a la segunda base de datos, pasando true de la new_link parámetro de mysql_connect si es necesario y, a continuación, la selección de la segunda DB con mysql_select_db

entonces, el trabajo con la conexión identifie r devuelto por la primera, o segunda, llamada al mysql_connect, dependiendo de qué base de datos desee enviar consultas.


Como nota al margen: la "mejor" solución/"más limpia" sería no usar mysql_* funciones directamente, pero trabajar con algún tipo de marco ORM, que tendría la capacidad de trabajar con varias conexiones de base de datos al mismo tiempo (no estoy seguro, pero tal vez Doctrine puede hacer eso - es una verdadera buena ORM)

0

tal vez este es el código que desea


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

Tenga en cuenta que no hicimos un mysql_select_db entre consultas, y tampoco usamos el nombre de la base de datos en la consulta.

+0

Los dos mysql_connects que llamas no harán nada significativo. De la documentación (http://cn.php.net/manual/en/function.mysql-connect.php): "Si se realiza una segunda llamada a mysql_connect() con los mismos argumentos, no se establecerá un nuevo enlace, sino que se devolverá el identificador del enlace ya abierto." – Avery

0

puedo configurar tablas de bases de datos de prueba independientes de la siguiente manera:

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; 

me encontré el siguiente script PHP con MySQL 5.1.41 y PHP 5.3.1 en Mac OS X:

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

Esta prueba tiene éxito. El resultado es la unión entre las dos tablas en bases de datos separadas.

Siempre debe poder seleccionar de las tablas calificadas por sus respectivos nombres de bases de datos en SQL. La API mysql en PHP no lo restringe a consultar una base de datos.

Siempre debe poder omitir el calificador de base de datos para la base de datos "actual", que declara con mysql_select_db().

0

Siempre que sea SELECT ing desde varias tablas, debe sepcificar un alias. Así que es bastante simple de allí:

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' 

Como otros en esta página han mencionado, la base de datos debe estar en el mismo host y la instancia. No puede consultar una base de datos desde otro servidor con esta sintaxis.

5

Después de leer su aclaración, tengo la impresión de que realmente desea consultar las tablas que residen en dos instancias separadas del servidor MySQL. Por lo menos, el texto aclaración:

foreign_db.login.username SELECT, nombre, apellido de foreign_db.login, donde el usuario

sugiere que desea ejecutar una consulta estando conectado como dos usuarios (que pueden residir o no en la misma instancia de servidor mysql).

En su pregunta, dijo que quería consultar datos de dos bases de datos diferentes, pero es importante darse cuenta de que una instancia de MySQL puede tener muchas, muchas bases de datos. Para las bases de datos múltiples administradas por la misma instancia mysql, la solución propuesta en la pregunta que enlazó simplemente funciona: simplemente prefija el nombre de la tabla con el nombre de las bases de datos, separando la base de datos y los nombres de la tabla con un punto: <db-name>.<table-name>.

Pero, como he señalado, esto sólo funciona si:

  1. todas las bases de datos se accede en una consulta residen en el mismo servidor - es decir, son gestionados por la misma instancia de MySQL
  2. el usuario que está conectado a la base de datos tiene los privilegios correctos para acceder a ambas tablas.

Escenario 1: bases de datos en mismo host: otorgar privilegios appopriate y calificar los nombres de tabla

Así que si las tablas de hecho residen en la misma instancia de MySQL, no hay necesidad de una segunda entrada o la conexión - simplemente Otorgue al usuario de la base de datos que usa para conectarse a la base de datos los privilegios apropiados para seleccionar de todas las tablas que necesita. Usted puede hacer eso con la sintaxis GRANT, documentado aquí: http://dev.mysql.com/doc/refman/5.1/en/grant.html

Por ejemplo, GRANT SELECT ON sakila.film TO 'test'@'%' permitirá al usuario [email protected]% para seleccionar datos de la tabla film en la base de datos sakila. Después de hacer eso, dicho usuario puede hacer referencia a esta tabla usando sakila.film (el llamado nombre de tabla calificado), o si la base de datos actual se establece en sakila, simplemente como film

Scenario2: bases de datos gestionadas por diferentes instancias de MySQL: FEDERADOS motor

Si las tablas a las que desea acceder son realmente administradas por dos instancias de MySQL diferentes, hay un truco que puede funcionar o no, según su configuración. Desde MySQL 5.0 mysql es compatible con el motor de almacenamiento FEDERATED. Esto le permite crear una tabla que no es realmente una tabla, sino una mirilla a una tabla en un servidor remoto. Este motor está documentado aquí: http://dev.mysql.com/doc/refman/5.1/en/federated-storage-engine.html

Por ejemplo, si usted sabe que hay esta tabla en la base de datos misc en el host remoto:

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

se puede hacer un 'puntero' local para que la tabla remota utilizando esto:

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'; 

Desafortunadamente, el motor FEDERATED no siempre está disponible, así que hay que comprobar primero si se puede usar eso. Pero supongamos que es así, entonces simplemente puede usar la tabla local t en sus consultas, al igual que cualquier otra tabla, y MySQL se comunicará con el servidor remoto y realizará las operaciones apropiadas en la tabla física en el otro lado.

Advertencia: hay varios problemas de optimización con las tablas FEDERATED. Debe averiguar si y en qué medida se aplican a usted. Por ejemplo, aplicar un WHERE a una tabla federada puede en muchos casos dar como resultado que todo el contenido de la tabla se transfiera por el cable a su servidor local, donde se aplicará el filtro real.Otro problema es con la creación de tablas: debe estar muy seguro de que las definiciones de la tabla federada y la tabla que señala coinciden exactamente, a excepción de la cláusula ENGINE (y CONEXIÓN). Si tiene, por ejemplo, un juego de caracteres diferente, los datos pueden llegar a distorsionarse por completo después de viajar por el cable.

Si desea utilizar las tablas FEDERATED, lea este artículo http://oreilly.com/pub/a/databases/2006/08/10/mysql-federated-tables.html para decidir si es adecuado para su caso de uso particular.

Si usted considera que lo necesite, tengo una utilidad para crear tablas federadas aquí: http://forge.mysql.com/tools/tool.php?id=54

Scenario3: no se puede utilizar FEDERADOS, pero las tablas en diferentes instancias de MySQL

Por último, si tienes tablas en diferentes instancias de MySQL, pero por alguna razón no puedo usar el motor de tablas federado, me temo que no tengo suerte. Simplemente va a tener que ejecutar consultas en ambas instancias de MySQL, recibir los resultados y hacer algo inteligente con ella en PHP. dependiendo de sus requisitos exactos, esta puede ser una solución perfectamente viable

Supongo que debe decidir por sí mismo qué parte de mi respuesta se ajusta mejor a su problema y agregar un comentario en caso de que necesite más ayuda. TIA Roland.

0

La opción menos detallado que tienes es proporcionada por el MySQL Manual sí:

el siguiente ejemplo se accede a la tabla autor de la base de datos DB1 y la tabla de editor de la base de datos DB2 :

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

Puede utilizar la opción dos: "No utilizar mysql_select_db" y luego nosotros e mysql_db_query en lugar de mysql_query ... que es un simple encontrar y reemplazar.

¡La mejor de las suertes!

0

Acabo de probado este código simple en mi ordenador y funciona perfectamente: (. Por supuesto, la propia consulta no tiene sentido, es sólo un ejemplo)

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

?> 

Así que puedo Realmente no ve cuál es su problema exacto. Si desea una sintaxis que sea más simple que esto, deberá proporcionar un ejemplo del tipo de SQL que desea escribir.

Cuestiones relacionadas