2012-09-05 27 views
1

特定列的最终值之间有一个与列的表中的记录:获取查询要列出并在启动和相同的ID

USE 'table'; 
insert into person values 
('11','xxx','1976-05-10','p1'), 
('11','xxx ','1976-06-11','p1'), 
('11','xxx ','1976-07-21','p2'), 
('11','xxx ','1976-08-31','p2'), 

任何人都可以建议我一个查询以获得关于他按时间顺序改变的地点的人的开始和结束日期。

查询我写

SELECT PId,Name,min(Start_Date) as sdt, max(Start_Date) as edt, place 
from ** 
group by Place; 

只给了我答案的前两行。任何人都可以提出查询?

+1

你的问题是基于该顺序非常的行,以及后面的两行是否标识相同的地方。这些东西很难在SQL中表达出来,并且在应用程序级别上通常会更好地解决。 [小提琴可用](http://sqlfiddle.com/#!2/c1a86)为那些谁想要尝试不过。 – MvG

+0

如果你想匿名你的代码,请不要破坏问题和答案。我已经把它回滚到了一个较早的完整版本。 –

+0

作为警告,请勿再次擦除所有代码。您可以在这里匿名数据和名称,但您需要保留核心问题。到目前为止,您的编辑已使这个问题变得毫无意义,所以我不得不将它们推回两次。 –

回答

1

这不是漂亮,而且性能可能是可怕的,但至少它works

select min(sdt), edt, place 
from (
    select A.Start_Date sdt, max(B.Start_Date) edt, A.place 
    from person A 
     inner join person B on A.place = B.place 
          and A.Start_Date <= B.Start_Date 
     left join person C on A.place != C.place 
         and A.Start_Date < C.Start_Date 
         and C.Start_Date < B.Start_Date 
    where C.place is null 
    group by A.Start_Date, A.place 
) X 
group by edt, place 

的想法是,AB代表所有双行C将是这两者之间具有不同place的任何行。因此,在C.place is null限制之后,我们知道AB属于相同的范围,即一组地方在一个地方,在它们之间按照时间顺序没有其他地方。从所有这些对中,我们想要识别那些具有最大范围的那些,包含所有其他的那些。我们这样做使用两个嵌套的group by查询。内部人员会为每个可能的开始日期选择最大结束日期,而外部人员会为每个可能的结束日期选择最小开始日期。结果是描述相同位置的按时间顺序排列的最大范围。

+0

OMG .. !!我无法相信这一点,它工作。我从来没有想过,我可以得到答案。但一个非常委婉的解决方案。谢谢。 – user1635134

+0

上面的查询只适用于1个ID“10 --- 01”,当添加这样的ID时没有工作。查询中是否可以进行更改? – user1635134

+0

@ user1635134:您的原始查询(现在从问题中缺失!)也不关心id,所以我保持简单。要为每个ID执行所有操作,必须在两个连接的连接条件中包含id a),b)按两个组的条件和c)作为内部查询结果中的附加列。 – MvG

0

这可以通过achived:

SELECT Id, PId, 
     MIN(Start_Date) AS sdt, 
     MAX(Start_Date) as edt, 
     IF(`place` <> @var_place_prev, (@var_rank:= @var_rank + 1), @var_rank) AS rank, 
     (@var_place_prev := `place`) AS `place` 
FROM person, (SELECT @var_rank := 0, @var_place_prev := "") dummy 
GROUP BY rank, Place; 

例子:SQLFiddle

如果你想记录由ID责令则:

SELECT Id, PId, 
     MIN(Start_Date) AS sdt, 
     MAX(Start_Date) as edt, 
     `place` 
FROM(
    SELECT Id, PId, 
      Start_Date 
      IF(`place` <> @var_place_prev,(@var_rank:= @var_rank + 1),@var_rank) AS rank, 
      (@var_place_prev := `place`) AS `place` 
    FROM person, (SELECT @var_rank := 0, @var_place_prev := "") dummy 
    ORDER BY ID ASC 
    ) a 
GROUP BY rank, Place; 
+0

感谢您的简要说明。 – user1635134

+1

您的解决方案非常依赖于MySQL遍历表的顺序。如果该订单[更改](http://sqlfiddle.com/#!2/aea44/1),结果不正确。由于MySQL不对其处理关系的顺序做出任何保证,因此在对数据或数据库服务器升级进行一些更改后,您的查询可能会在现在或将来某个时间点产生不正确的结果。 – MvG

+0

雅正确!第二个查询保证记录的顺序。我故意发布第一个查询,因为它比第二个更好。 – Omesh