2010-01-04 40 views
9

Trong tập cuối cùng của chúng tôi (How I constructed a cross database query in MySQL) Tôi đã học cách xây dựng một truy vấn cơ sở dữ liệu chéo trong MySQL. Điều này làm việc rất lớn nhưng khi anh hùng của chúng tôi cố gắng sử dụng kiến ​​thức mới này trong PHP, anh ta tìm thấy người bạn thân nhất của mình FAIL đang đợi anh ta.Làm cách nào để xây dựng truy vấn cơ sở dữ liệu chéo trong PHP?

Tôi đã xem mysql_select_db cho PHP. Điều này dường như ngụ ý rằng nếu tôi muốn sử dụng MySQL với PHP, tôi có một vài lựa chọn:

  1. Sử dụng mysql_select_db nhưng chỉ bị mắc kẹt khi chỉ sử dụng một db một lúc. Đây là thiết lập hiện tại của chúng tôi và việc đặt một cơ sở dữ liệu như một định danh không gian tên dường như không hoạt động (nó hoạt động tốt trong trình bao MySQL vì vậy tôi biết nó không phải là vấn đề với thiết lập máy chủ MySQL của chúng tôi).

  2. Không sử dụng mysql_select_db. Từ một số ví dụ tôi đã thấy, điều này có nghĩa là tôi phải chỉ định db cho mỗi truy vấn mà tôi thực hiện. Điều này có ý nghĩa vì tôi chưa sử dụng mysql_select_db để nói cho PHP biết tôi muốn truy cập vào db nào. Điều này cũng làm cho buồn vì tôi không muốn đi qua tất cả các mã của tôi và thêm một tên db cho mỗi truy vấn.

Có điều gì tốt hơn điều này không? Có cách nào để tôi làm một truy vấn chéo db MySQL trong PHP mà không cần phải một cái gì đó điên như (2)?

CLARIFICATION: Không có câu trả lời được đề xuất nào thực sự cho phép tôi thực hiện truy vấn chéo db. Thay vào đó, chúng cho phép tôi truy cập hai DB khác nhau một cách riêng biệt. Tôi muốn một giải pháp cho phép tôi làm điều gì đó như SELECT foreign_db.login.username, firstname, lastname from foreign_db.login, user where ... KHÔNG chỉ thực hiện các truy vấn khác nhau cho các DB khác nhau. Đối với những gì nó có giá trị, (2) không làm việc cho tôi.

+0

Sau một số thử nghiệm, vì lý do nào đó, thiết lập của tôi không cho phép tôi thực hiện số (2). Tôi luôn luôn cần phải sử dụng mysql_select_db. Một cái gì đó mà làm việc là sử dụng mysql_select_db để chuyển đổi giữa các dbs, nhưng điều này không cho phép tôi làm các truy vấn db chéo. Tôi đang nghĩ về một cái gì đó như chọn * từ main_db.login, customerInfo nơi ... vv – Avery

+0

(2) là câu trả lời đúng. Máy chủ PHP của tôi thực hiện hàng trăm truy vấn như vậy một phút với một phần dữ liệu từ cơ sở dữ liệu thứ hai được chỉ định theo tên. Vì vậy, câu hỏi là ít hơn "Làm thế nào để làm điều này?" và nhiều hơn nữa "Tại sao điều này không hoạt động?" – grahamparks

+0

Sau khi một số đào sâu xung quanh, tôi đã nhận nó để làm việc như bạn sẽ nghĩ rằng nó nên: SELECT FROM * foreigndb.login WHERE ... Không chắc chắn ai nhận được tiền thưởng ... Có lẽ tôi chỉ có thể giảm hạng câu hỏi này ... và sau đó đúc một số điểm danh tiếng trong thùng từ thiện. – Avery

Trả lời

17

Bạn sẽ cần cơ sở dữ liệu của mình chạy trên cùng một máy chủ.

Nếu vậy, bạn sẽ có thể sử dụng mysql_select_db trên db yêu thích/mặc định của bạn và tự xác định cơ sở dữ liệu nước ngoài.

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

Nếu cơ sở dữ liệu của bạn chạy trên máy chủ khác, bạn sẽ không thể tham gia trực tiếp. Nhưng sau đó bạn có thể thực hiện 2 truy vấn.

$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ách in đầu ra cho trên mã "cơ sở dữ liệu chạy trên một máy chủ khác nhau"? –

3

Một giải pháp có thể là để:

  • sử dụng mysql_select_db để chọn "mặc định" (tức là sử dụng nhiều nhất) cơ sở dữ liệu
  • và chỉ định tên DB chỉ trong các truy vấn mà phải làm việc với các " cơ sở dữ liệu thứ hai (tức là ít được sử dụng) nhất.

Nhưng đây chỉ là một giải pháp khả thi nếu bạn có một DB đó là hơn được sử dụng hơn so với khác ...


Ra khỏi tò mò: bạn đã cố gắng thiết lập một số kết nối đến máy chủ DB của bạn - ví dụ: một cho mỗi cơ sở dữ liệu?

Bạn có thể có thể:

  • kết nối đến DB đầu tiên với mysql_connect, và, sau đó, chọn DB đầu tiên với mysql_select_db
  • và, sau đó, kết nối với DB thứ hai, đi qua true cho các tham số của new_linkmysql_connect nếu cần thiết, và, sau đó, chọn DB thứ hai với mysql_select_db

sau đó, làm việc với kết nối identifie r được trả về trước tiên hoặc thứ hai, gọi tới số mysql_connect, tùy thuộc vào DB bạn muốn đưa ra các truy vấn.


Là một sidenote: "tốt nhất"/giải pháp "sạch" sẽ được không sử dụng mysql_* chức năng trực tiếp, nhưng làm việc với một số loại khuôn khổ ORM, mà có thể có khả năng làm việc với một số kết nối DB đồng Hiện (không chắc chắn, nhưng có lẽ Doctrine thể làm điều đó - đó là một ORM tốt thực)

0

có lẽ đây là đoạn code mà bạn muốn


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

Lưu ý rằng chúng tôi đã không thực hiện một mysql_select_db giữa các truy vấn và chúng tôi cũng không sử dụng tên cơ sở dữ liệu trong truy vấn.

+0

Hai mysql_connects mà bạn gọi sẽ không làm bất cứ điều gì đáng kể. Từ tài liệu (http://cn.php.net/manual/en/function.mysql-connect.php): "Nếu cuộc gọi thứ hai được gửi tới mysql_connect() với cùng các đối số, sẽ không có liên kết mới nào được thiết lập, nhưng thay vào đó, liên kết nhận dạng của liên kết đã mở sẽ được trả về." – Avery

0

tôi thiết lập các bảng trong cơ sở dữ liệu thử nghiệm riêng biệt như sau:

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; 

Tôi chạy kịch bản PHP sau đây với MySQL 5.1.41 và PHP 5.3.1 trên 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); 
} 

Thử nghiệm này thành công. Kết quả là sự kết hợp giữa hai bảng trong cơ sở dữ liệu riêng biệt.

Bạn luôn có thể chọn từ (các) bảng có đủ điều kiện theo tên cơ sở dữ liệu tương ứng của chúng trong SQL. API mysql trong PHP không hạn chế bạn truy vấn một cơ sở dữ liệu.

Bạn luôn có thể bỏ qua vòng loại cơ sở dữ liệu cho cơ sở dữ liệu "hiện tại" mà bạn khai báo với mysql_select_db().

0

Bất cứ khi nào bạn đang SELECT nhập từ nhiều bảng, bạn phải phân tách bí danh. Vì vậy, nó khá đơn giản từ đó:

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' 

Như những người khác trên trang này đã đề cập, cơ sở dữ liệu phải nằm trên cùng một máy chủ và cá thể. Bạn không thể truy vấn cơ sở dữ liệu từ một máy chủ khác với cú pháp này.

5

Sau khi đọc làm rõ của bạn, tôi dưới ấn tượng rằng bạn thực sự muốn truy vấn các bảng nằm trong hai cá thể máy chủ MySQL riêng biệt. Ít nhất, văn bản của bạn làm rõ:

CHỌN foreign_db.login.username, firstname, lastname từ foreign_db.login, dùng nơi

cho thấy rằng bạn muốn chạy một truy vấn trong khi đang đăng nhập như hai người dùng (có thể hoặc không thể cư trú trên cùng một cá thể máy chủ mysql).

Trong câu hỏi của bạn, bạn nói bạn muốn truy vấn dữ liệu từ hai cơ sở dữ liệu khác nhau, nhưng điều quan trọng là nhận ra rằng một cá thể MySQL có thể có nhiều, nhiều cơ sở dữ liệu. Đối với nhiều cơ sở dữ liệu được quản lý bởi cùng một cá thể mysql, giải pháp được đề xuất trong câu hỏi mà bạn liên kết chỉ đơn giản là làm việc: chỉ cần tiền tố tên bảng với tên cơ sở dữ liệu, tách cơ sở dữ liệu và tên bảng bằng dấu chấm: <db-name>.<table-name>.

Nhưng, như tôi đã chỉ ra, điều này chỉ hoạt động nếu:

  1. tất cả các cơ sở dữ liệu bạn truy cập trong một truy vấn nằm trên cùng một máy chủ - có nghĩa là, được quản lý bởi các trường hợp MySQL cùng
  2. người dùng được kết nối với cơ sở dữ liệu có các đặc quyền phù hợp để truy cập cả hai bảng.

Scenario1: cơ sở dữ liệu trên cùng một máy chủ: cấp đặc quyền appopriate và đủ điều kiện tên bảng

Vì vậy, nếu các bảng thực cư trú trên dụ mysql cùng, không có nhu cầu về một đăng nhập thứ hai hoặc kết nối - đơn giản cấp cho người dùng cơ sở dữ liệu mà bạn sử dụng để kết nối với cơ sở dữ liệu các đặc quyền thích hợp để chọn từ tất cả các bảng bạn cần. Bạn có thể làm điều đó với các GRANT cú pháp, tài liệu ở đây: http://dev.mysql.com/doc/refman/5.1/en/grant.html

Ví dụ, GRANT SELECT ON sakila.film TO 'test'@'%' sẽ cho phép người dùng [email protected]% để chọn dữ liệu từ bảng film trong cơ sở dữ liệu sakila. Sau khi làm điều đó, cho biết người dùng có thể tham khảo bảng này sử dụng sakila.film (cái gọi là tên bảng đủ điều kiện), hoặc nếu cơ sở dữ liệu hiện tại được thiết lập để sakila, đơn giản là film

Scenario2: cơ sở dữ liệu của trường MySQL khác nhau quản lý: FEDERATED Động cơ

Nếu các bảng bạn muốn truy cập thực sự được quản lý bởi hai cá thể MySQL khác nhau, có một mẹo có thể có hoặc không hoạt động, tùy thuộc vào cấu hình của bạn. Vì MySQL 5.0 mysql hỗ trợ công cụ lưu trữ FEDERATED. Điều này cho phép bạn tạo một bảng không thực sự là một bảng, mà là một lỗ hổng tới một bảng trên một máy chủ từ xa. Động cơ này được ghi chép lại ở đây: http://dev.mysql.com/doc/refman/5.1/en/federated-storage-engine.html

Ví dụ, nếu bạn biết có bảng này trong cơ sở dữ liệu misc trên máy chủ từ xa:

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

bạn có thể làm cho một địa phương 'trỏ' với bảng điều khiển từ xa sử dụng này:

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

Thật không may, động cơ FEDERATED không phải lúc nào cũng có sẵn, vì vậy bạn phải kiểm tra trước nếu bạn thậm chí có thể sử dụng. Nhưng giả sử nó là, sau đó bạn có thể sử dụng bảng cục bộ trong các truy vấn của bạn, giống như bất kỳ bảng nào khác và MySQL sẽ liên lạc với máy chủ từ xa và thực hiện các thao tác thích hợp trên bảng vật lý ở phía bên kia.

Lưu ý: có một số vấn đề tối ưu hóa với bảng FEDERATED. Bạn nên tìm hiểu xem liệu mức độ này có áp dụng cho bạn hay không. Ví dụ, việc áp dụng một WHERE vào một bảng được liên kết có thể trong nhiều trường hợp dẫn đến toàn bộ nội dung bảng được cuộn qua dây tới máy chủ cục bộ của bạn, nơi mà việc lọc thực tế sẽ được áp dụng.Một vấn đề khác là với việc tạo bảng: bạn phải chắc chắn rằng các định nghĩa của bảng được liên kết và bảng nó trỏ đến khớp chính xác, ngoại trừ mệnh đề ENGINE (và CONNECTION). Ví dụ: nếu bạn có một bộ ký tự khác, dữ liệu có thể hoàn toàn bị cắt xén sau khi di chuyển qua dây.

Nếu bạn muốn sử dụng FEDERATED bảng, hãy đọc bài viết này http://oreilly.com/pub/a/databases/2006/08/10/mysql-federated-tables.html để quyết định xem quyền của nó có phù hợp với trường hợp sử dụng cụ thể của bạn hay không.

Nếu bạn nghĩ rằng bạn cần nó, tôi có một tiện ích để tạo bảng liên đây: http://forge.mysql.com/tools/tool.php?id=54

Scenario3: không thể sử dụng FEDERATED, nhưng bảng trên trường MySQL khác nhau

Cuối cùng, nếu bạn có các bảng trên các cá thể MySQL khác nhau, nhưng không thể vì một lý do nào đó sử dụng công cụ bảng được liên kết, bạn không may mắn. Bạn chỉ đơn giản là sẽ phải thực hiện các truy vấn cho cả hai cá thể MySQL, nhận các kết quả và làm một cái gì đó thông minh với nó trong PHP. tùy thuộc vào yêu cầu chính xác của bạn, đây có thể là giải pháp hoàn toàn khả thi

Tôi đoán bạn cần tự quyết định phần nào trong câu trả lời của tôi kháng cáo tốt nhất và thêm nhận xét trong trường hợp bạn cần thêm trợ giúp. TIA Roland.

0

Các tùy chọn ít tiết bạn có được cung cấp bởi MySQL Manual bản thân:

Ví dụ sau truy cập vào bảng tác giả từ các cơ sở dữ liệu db1 và bảng biên tập từ cơ sở dữ liệu DB2 :

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

Bạn có thể sử dụng tùy chọn hai: "Không sử dụng mysql_select_db" và sau đó là e mysql_db_query thay vì mysql_query ... đó là tìm và thay thế đơn giản.

Chúc bạn may mắn!

0

Tôi vừa thử mã đơn giản này trong máy tính của tôi và nó hoạt động hoàn hảo: (. Tất nhiên, truy vấn chính nó là vô nghĩa, nó chỉ là một ví dụ)

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

?> 

Vì vậy, tôi có thể không thực sự thấy vấn đề chính xác của bạn là gì. Nếu bạn muốn một cú pháp đơn giản hơn, bạn sẽ phải cung cấp một ví dụ về loại SQL bạn muốn viết.

Các vấn đề liên quan