2010-11-07 82 views
1

我有2个表格,一个用于新图片和一个用于新用户,我想创建一个混合最新动作的墙,以便按日期排序显示新图片&。加入2不同列的表格

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

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

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

所需的输出:


丹尼尔加州刚刚registred 5分钟前


新画面通过大卫(点击查看)点15分钟前


等等......

我求你不要只给我的查询语法,我不亲和无法弄清楚如何处理循环内(我只知道如何获取常规的SQL查询)

感谢

回答

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 

此处假设authorphotos对应于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有一个索引,或者这将是非常低效。

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)降序并添加一个限制子句来限制返回的行数。

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

?> 

希望你能找到一些有用的这个:)