JOIN 2具有不同列的表

时间:2010-11-07 18:58:18

标签: php mysql

我有2个表,一个用于新图片,一个用于新用户,我想创建一个混合最新动作的墙,以便它将显示新用户和按日期排序的图片。

我想要的是单个查询以及如何在循环内知道当前条目是照片或用户。

TABLE: users
Columns: id,username,fullname,country,date

TABLE: photos
Columns: id,picurl,author,date

期望的输出:


来自加利福尼亚

Daniel 刚刚注册 5分钟前


新图片 David (点击查看) 15分钟前


等等......

我求你不要只给我查询语法,我不是专业人士,也无法弄清楚如何处理循环内部(我只知道如何获取常规的sql查询)

由于

2 个答案:

答案 0 :(得分:1)

你可以使用联盟:

SELECT concat(username, " from ", country, " has just registered") txt, date FROM users
UNION
SELECT concat("New picture By ", username, " (click to view)") txt, date FROM photos INNER JOIN users ON author=users.id
ORDER BY date DESC
LIMIT 10

这假定author中的photos列对应usersid。如果作者实际上是一个包含用户名的字符串(这是一个糟糕的设计),你将不得不这样做:

SELECT concat(username, " from ", country, " has just registered") txt, date FROM users
UNION
SELECT concat("New picture By ", author, " (click to view)") txt, date FROM photos
ORDER BY date DESC
LIMIT 10

确保两个表中的date都有索引,否则效率会非常低。

答案 1 :(得分:0)

我把这个小例子放在一起让你看 - 你可能会发现它很有帮助。

可在此处找到完整脚本:http://pastie.org/1279954

所以它从3个简单的表国家,用户和user_photos开始。

<强>表格

注意:我只包含此演示的最小列数!

drop table if exists countries;
create table countries
(
country_id tinyint unsigned not null auto_increment primary key,
iso_code varchar(3) unique not null,
name varchar(255) unique not null
)
engine=innodb;

drop table if exists users;
create table users
(
user_id int unsigned not null auto_increment primary key,
country_id tinyint unsigned not null,
username varbinary(32) unique not null
-- all other detail omitted
)
engine=innodb;

drop table if exists user_photos;
create table user_photos
(
photo_id int unsigned not null auto_increment primary key,
user_id int unsigned not null,
-- all other detail omitted
key (user_id)
)
engine=innodb;

需要注意的重要一点是用户和照片的主键是无符号整数和auto_increment(1,2,3..n)所以我可以通过主键排序找到最新的10个用户和10张照片( PK)降序并添加一个limit子句来限制返回的行数。

-- change limit to increase rows returned
select * from users order by user_id desc limit 2; 
select * from user_photos order by photo_id desc limit 2;

测试数据

insert into countries (iso_code, name) values ('GB','Great Britain'),('US','United States'),('DE','Germany');

insert into users (username, country_id) values ('f00',1),('bar',2),('stack',1),('overflow',3);

insert into user_photos (user_id) values (1),(1),(2),(3),(1),(4),(2),(1),(4),(2),(1);

所以现在我们需要一种方便的方式(单次调用)来选择最新的10个用户和照片。这两个表是完全不同的,因此联合不是最好的方法,所以我们要做的是编写一个存储过程,返回两个结果集并处理在我们的php脚本中生成墙(合并结果集)。

存储过程

只是一些SQL代码的包装 - 想想它就像SQL的函数调用版本

drop procedure if exists list_latest_users_and_photos;

delimiter #

create procedure list_latest_users_and_photos()
begin

-- last 10 users
select 
    'U' as type_id, -- integer might be better
     u.user_id,
     u.country_id,
     u.username,
     -- other user columns...
     c.name as country_name
from 
 users u 
inner join countries c on u.country_id = c.country_id
order by 
 u.user_id desc limit 10;

-- last 10 photos

select 
 'P' as type_id, 
 up.photo_id,
 up.user_id,
 -- other photo columns...
 u.username 
 -- other user columns...
from 
 user_photos up
inner join users u on up.user_id = u.user_id
order by
 up.photo_id desc limit 10;

end #

delimiter ;

<强>测试

要测试我们的存储过程,我们需要做的就是调用它并查看结果。

mysql> call list_latest_users_and_photos();

+---------+---------+------------+----------+---------------+
| type_id | user_id | country_id | username | country_name  |
+---------+---------+------------+----------+---------------+
| U       |       4 |          3 | overflow | Germany       |
| U       |       3 |          1 | stack    | Great Britain |
| U       |       2 |          2 | bar      | United States |
| U       |       1 |          1 | f00      | Great Britain |
+---------+---------+------------+----------+---------------+
4 rows in set (0.00 sec)

+---------+----------+---------+----------+
| type_id | photo_id | user_id | username |
+---------+----------+---------+----------+
| P       |       11 |       1 | f00      |
| P       |       10 |       2 | bar      |
| P       |        9 |       4 | overflow |
| P       |        8 |       1 | f00      |
| P       |        7 |       2 | bar      |
| P       |        6 |       4 | overflow |
| P       |        5 |       1 | f00      |
| P       |        4 |       3 | stack    |
| P       |        3 |       2 | bar      |
| P       |        2 |       1 | f00      |
+---------+----------+---------+----------+
10 rows in set (0.01 sec)

Query OK, 0 rows affected (0.01 sec)

现在我们知道我们可以通过php调用它并生成墙。

PHP脚本

<?php

$conn = new Mysqli("localhost", "foo_dbo", "pass", "foo_db");

$result = $conn->query("call list_latest_users_and_photos()");

$users = array();
while($row = $result->fetch_assoc()) $users[] = $row;

$conn->next_result();
$result = $conn->use_result();

$photos = array();
while($row = $result->fetch_assoc()) $photos[] = $row;

$result->close();   
$conn->close();

$wall = array_merge($users, $photos);

echo "<pre>", print_r($wall), "</pre>";

?>

希望您能找到一些有用的内容:)