Как создать кросс-запрос базы данных в PHP?

В нашем последнем эпизоде ​​( Как я построил кросс-запрос базы данных в MySQL ) я узнал, как построить кросс-запрос базы данных в MySQL. Это сработало отлично, но когда наш герой попытался использовать это новообретенное знание в PHP, он нашел, что его лучший друг FAIL ждет его.

Я посмотрел на mysql_select_db для PHP. Это, по-видимому, подразумевает, что если я хочу использовать MySQL с PHP, у меня есть несколько вариантов:

  1. Используйте mysql_select_db но mysql_select_db только с использованием одного db за раз. Это наша текущая настройка и размещение базы данных в качестве идентификатора пространства имен, похоже, не работает (отлично работает в оболочке MySQL, поэтому я знаю, что это не проблема с нашей настройкой сервера MySQL).

  2. Не используйте mysql_select_db . Из некоторых примеров, которые я видел, это означает, что я должен указать db для каждого запроса, который я делаю. Это имеет смысл, поскольку я не использовал mysql_select_db чтобы сообщить PHP, какой db я хочу получить. Это также печально, так как я не хочу проходить весь свой код и добавлять имя db к каждому запросу.

Есть что-то лучше этого? Есть ли способ для меня сделать кросс-db MySQL-запрос на PHP без необходимости чего-то сумасшедшего, как (2)?

CLARIFICATION : ни один из предложенных ответов на самом деле не позволяет мне выполнить запрос cross db. Вместо этого они позволяют мне обращаться к двум различным БД отдельно. Я хочу решение, которое позволяет мне делать что-то вроде SELECT foreign_db.login.username, firstname, lastname from foreign_db.login, user where ... НЕ просто делать разные запросы для разных БД. Для чего это стоит, (2) не работает для меня.

Вам понадобятся ваши базы данных для работы на одном хосте.

Если это так, вы должны иметь возможность использовать mysql_select_db в своем любимом / дефолте 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. По крайней мере, ваш разъясняющий текст:

SELECT foreign_db.login.username, firstname, lastname from foreign_db.login, пользователь, где

предполагает, что вы хотите запустить один запрос во время входа в систему как два пользователя (которые могут или не могут находиться на одном экземпляре сервера mysql).

В вашем вопросе вы сказали, что хотите запрашивать данные из двух разных баз данных, но важно понять, что один экземпляр MySQL может иметь множество баз данных. Для нескольких баз данных, управляемых одним и тем же экземпляром mysql, решение, предлагаемое в вопросе, к которому вы привязаны, просто работает: просто префикс имени таблицы с именем базы данных, разделяя имена базы данных и таблицы точкой: <db-name>.<table-name> .

Но, как я заметил, это работает только в том случае, если:

  1. все базы данных, к которым вы обращаетесь в одном запросе, находятся на одном сервере, то есть управляются одним и тем же экземпляром MySQL
  2. пользователь, подключенный к базе данных, имеет права доступа к обеим таблицам.

Сценарий1: базы данных на том же хосте: предоставить привилегии apopriate и определить имена таблиц

Поэтому, если таблицы фактически находятся в одном экземпляре mysql, нет необходимости в втором входе в систему или подключении – просто предоставите пользователю базы данных, который вы используете для подключения к базе данных, соответствующие привилегии для выбора из всех необходимых вам таблиц. Вы можете сделать это с синтаксисом GRANT , зарегистрированным здесь: http://dev.mysql.com/doc/refman/5.1/en/grant.html

Например, GRANT SELECT ON sakila.film TO 'test'@'%' позволит пользователю test@% для выбора данных из таблицы sakila базе данных sakila . После этого пользователь может ссылаться на эту таблицу, используя sakila.film (так называемое имя квалифицированной таблицы), или если текущая база данных настроена на sakila , просто как film

Сценарий2: базы данных, управляемые разными экземплярами MySQL: FEDERATED engine

Если таблицы, к которым вы хотите получить доступ, фактически управляются двумя разными экземплярами MySQL, есть один трюк, который может работать или не работать, в зависимости от вашей конфигурации. Поскольку MySQL 5.0 mysql поддерживает FEDERATED хранения данных 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.

Решение может заключаться в следующем:

  • используйте mysql_select_db чтобы выбрать базу данных по умолчанию (то есть наиболее часто используемую)
  • и укажите имя БД только в запросах, которые должны работать со «второй» (т.е. наименее используемой) базой данных.

Но это всего лишь жизнеспособное решение, если у вас есть одна БД, которая больше используется, чем другая …

Из любопытства: вы пытались установить несколько соединений с вашим сервером БД – то есть по одному для каждой базы данных?

Возможно, вы сможете:

  • подключитесь к первой БД с помощью mysql_connect , а затем выберите первую БД с помощью mysql_select_db
  • и затем подключиться ко второму БД, передав true для параметра new_link mysql_connect если это необходимо, и затем, выбрав второй БД с помощью mysql_select_db

Затем работайте с идентификатором соединения, возвращаемым первым или вторым вызовом mysql_connect , в зависимости от того, какой БД вы хотите выдать.

В качестве побочного решения: «лучшее» / «самое чистое» решение не будет mysql_* использовать функции mysql_* , но работает с какой-то структурой ORM, которая будет иметь возможность работать с несколькими соединениями DB одновременно (не уверен, но, возможно, Доктрина может это сделать – это хороший ОРМ)

Может быть, это код, который вы хотите


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

Я выполнил следующий PHP-скрипт с MySQL 5.1.41 и PHP 5.3.1 в 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); } 

Этот тест удался. Результатом является объединение двух таблиц в отдельных базах данных.

Вы всегда должны выбирать из таблиц (ов), соответствующих их именам базы данных в SQL. API-интерфейс mysql в PHP не ограничивает вас запросом одной базы данных.

Вы всегда должны упускать mysql_select_db() базы данных для «текущей» базы данных, которую вы объявляете с помощью mysql_select_db() .

Всякий раз, когда вы выбираете из нескольких таблиц, вы должны выделять псевдоним. Так что это довольно просто:

 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 и таблицы редактора из базы данных 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 …, который является простой находкой и заменой.

Удачи!

Я просто пробовал этот простой код на своем компьютере, и он отлично работает:

 <?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 вы хотите написать.