我有3张桌子
person (id, name)
area (id, number)
history (id, person_id, area_id, type, datetime)
在此表中,我存储了某个人在特定时间具有哪个区域的信息。这就像一个推销员在一个地区旅行了一段时间,然后他得到了另一个区域。他一次也可以有多个区域。
历史类型='I'用于CheckIn或'O'用于Checkout。 例如:
id person_id area_id type datetime
1 2 5 'O' '2011-12-01'
2 2 5 'I' '2011-12-31'
A person started traveling in area 5 at 2011-12-01 and gave it back on 2011-12-31.
现在我想列出所有人现在拥有的所有领域。
person1.name, area1.number, area2.number, area6.name
person2.name, area5.number, area9.number
....
输出也可能是这样(没关系):
person1.name, area1.number
person1.name, area2.number
person1.name, area6.number
person2.name, area5.number
....
我该怎么做?
答案 0 :(得分:1)
这个问题确实非常棘手。您需要一个历史记录中的条目列表,对于给定的用户和区域,存在一个没有后续“I”记录的“O”记录。仅使用历史表,转换为:
SELECT ho.person_id, ho.area_id, ho.type, MAX(ho.datetime)
FROM History AS ho
WHERE ho.type = 'O'
AND NOT EXISTS(SELECT *
FROM History AS hi
WHERE hi.person_id = ho.person_id
AND hi.area_id = ho.area_id
AND hi.type = 'I'
AND hi.datetime > ho.datetime
)
GROUP BY ho.person_id, ho.area_id, ho.type;
然后,因为你真的只是在这个人的名字和地区的号码之后(虽然为什么区号不能和它的ID相同我不确定),你需要稍微适应,加入额外的两张桌子:
SELECT p.name, a.number
FROM History AS ho
JOIN Person AS p ON ho.person_id = p.id
JOIN Area AS a ON ho.area_id = a.id
WHERE ho.type = 'O'
AND NOT EXISTS(SELECT *
FROM History AS hi
WHERE hi.person_id = ho.person_id
AND hi.area_id = ho.area_id
AND hi.type = 'I'
AND hi.datetime > ho.datetime
);
NOT EXISTS子句是一个相关的子查询;这往往效率低下。您可以使用适当的连接和过滤条件将其重铸为LEFT OUTER JOIN:
SELECT p.name, a.number
FROM History AS ho
JOIN Person AS p ON ho.person_id = p.id
JOIN Area AS a ON ho.area_id = a.id
LEFT OUTER JOIN History AS hi
ON hi.person_id = ho.person_id
AND hi.area_id = ho.area_id
AND hi.type = 'I'
AND hi.datetime > ho.datetime
WHERE ho.type = 'O'
AND hi.person_id IS NULL;
所有SQL未经验证。
答案 1 :(得分:0)
您正在寻找每行可能有不同列数的结果吗?我想你可能想看看GROUP_CONCAT()
SELECT p.`id`, GROUP_CONCAT(a.`number`, ',') AS `areas` FROM `person` a LEFT JOIN `history` h ON h.`person_id` = p.`id` LEFT JOIN `area` a ON a.`id` = h.`area_id`
我没有测试过这个查询,但之前我以类似的方式使用了group concat。当然,您需要根据自己的需要量身定制。当然,group concat将返回一个字符串,因此需要进行后期处理才能使用数据。
编辑自从我开始回复以来,我的问题已被编辑。我的查询不再适合您的请求了......
答案 2 :(得分:0)
试试这个:
select *
from person p
inner join history h on h.person_id = p.id
left outer join history h2 on h2.person_id = p.id and h2.area_id = h.area_id and h2.type = 'O'
inner join areas on a.id = h.area_id
where h2.person_id is null and h.type = 'I'