我有2个表,一个用于新图片,一个用于新用户,我想创建一个混合最新动作的墙,以便它将显示新用户和按日期排序的图片。
我想要的是单个查询以及如何在循环内知道当前条目是照片或用户。
TABLE: users
Columns: id,username,fullname,country,date
TABLE: photos
Columns: id,picurl,author,date
期望的输出:
Daniel 刚刚注册 5分钟前
新图片 David (点击查看) 15分钟前
等等......
我求你不要只给我查询语法,我不是专业人士,也无法弄清楚如何处理循环内部(我只知道如何获取常规的sql查询)
由于
答案 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
列对应users
表id
。如果作者实际上是一个包含用户名的字符串(这是一个糟糕的设计),你将不得不这样做:
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>";
?>
希望您能找到一些有用的内容:)