一个数据表tab,假设其包含以下几列:
ID,Style,Area, Price
分别代表产品序列号,型号,产地,价格。
示例数据如下:
ID Style Area Price
1, 'A', '1', 10
2, 'A', '2', 12
3, 'A', '1', 8
4, 'B', '1', 10
5, 'B', '1', 13
6, 'B', '2', 9
7, 'A', '2', 7
8, 'A', '1', 14
现在希望获取所有Style和Area组合的价格最低的产品的ID。举个例子来说,比如这个数据表代表了一个手机销售数据,手机产地分为大陆、台湾、香港等,型号有N95、E90等等,那么,通过这个查询,我就可以知道各种产品(如国行N95,港版N95,国行E90等等)的价格以及对应ID,并可以由此查询到经销商等信息。我现在是这样实现的:
Select * From (Select * From tab Order By Price) As newtab Group By Style, Area;但是这里用到了一个不太确定的机制,即MySQL在处理Group By语句的时候,对于其他不在分组条件的列(在这里就是ID和Price列),是将其置为它第一次碰到的值。Select * From tab Order By Price执行之后,结果为:
7, 'A', '2', 7
3, 'A', '1', 8
6, 'B', '2', 9
1, 'A', '1', 10
4, 'B', '1', 10
2, 'A', '2', 12
5, 'B', '1', 13
8, 'A', '1', 14而执行
Select * From (Select * From tab Order By Price) As newtab Group By Style, Area;
语句后,结果为3, 'A', '1', 8
7, 'A', '2', 7
4, 'B', '1', 10
6, 'B', '2', 9如第一条 
3, 'A', '1', 8
Style='A' Area='1'对应的ID=3, Price=8只是因为MySQL碰到的第一个Style='A' Area='1'的组合中,ID和Price是这个值但是,这个机制似乎是不大可靠的。文档中似乎没有明确描述过这个行为。当然,还可以这样写Select ID, tab.Style, tab.Area, Price From tab Inner Join (Select MIN(Price) AS MinPrice, Style, Area From tab Group By Type, Area) as newtab ON (tab.Style=newtab.Style) AND (tab.Area=newtab.Area) AND (tab.Price=newtab.MinPrice);但是这条语句我一看就不喜欢它。太复杂了,而且效率估计很不好。另外,如果我想要得到的不是价格最低的一个,而是最低的,比如5个,所对应的全部信息时,那么,这条语句又应该怎么写呢?恳请高手指点!

解决方案 »

  1.   

    select * from tab t
    where not exists (select 1 from tab where Style=t.Style and Area=t.Area and Price<t.Price)
      

  2.   

    考虑到执行效率,需要创建基于 (style , area) 的复合索引。
      

  3.   

    非常感谢ACMAIN 那么如何高效率的得到所有组合中价格最低的5个呢?恳请再度帮忙。
    (刚接触SQL,都不知道not exists 这个语句……)
      

  4.   

    哦 
    是不是可以这样:select * from tab t
    where (select count(*) from tab where Style=t.Style and Area=t.Area and Price<t.Price)<=4;这样就是价格最低的5个了?