优雅的mysql可以选择,分组,组合一个表中的多行

时间:2012-02-06 08:07:54

标签: mysql sql

这是我的表格的简化版本:

group price spec
a     1     .
a     2     ..
b     1     ...
b     2
c     .
.     .
.     .

我想生成这样的结果:(我将其称为result_table)

price_a |spec_a |price_b |spec_b |price_c ...|total_cost
1       |.      |1       |..     |...        |
(min)            (min)                        =1+1+...

基本上我想:

  1. 选择每个组中包含 min 价格的行
  2. 将列合并为一行
  3. 我知道这可以使用几个查询和/或结果上的一些非sql处理来完成,但我怀疑可能有更好的解决方案。

    我想要执行任务2的原因(将列合并为一行) 是因为我想用result_table做以下的事情:

    select *,
    (result_table.total_cost + table1.price + table.2.price) as total_combined_cost
    from result_table 
    right join table1
    right join table2
    

    这可能要求太多,所以这里有一些关于这个问题的其他想法:

    不是尝试组合多个行(任务2),而是将它们存储在临时表中 (使用总和更容易计算total_cost)

    随意放弃任何想法,不必完全回答,如果你有一个优雅的方法来完成任务1,我觉得它非常棒!

    ==已编辑/已添加2012年2月6日==

    我的计划的目标是以最低的成本确定项目的最佳组合(并且最好同时拥有更高的实用价值)。

    考虑@ypercube关于大量群组的评论,临时表似乎是唯一可行的解​​决方案。并且还指出MySQL中没有旋转功能(虽然it can be implemented,但没有必要执行此类操作)。

    好的,经过@ Johan的回答,我正在为任务1考虑这样的事情:

    select * from
    (
        select * from
        result_table
        order by price asc
    ) as ordered_table
    group by group
    ;
    

    虽然看起来很狡猾但似乎有效。

    ==已编辑/已添加2012年2月7日==

    由于可能有多个组合可能产生相同的最小值,我修改了我的答案:

    select result_table.* from  
    (
        select * from
        (
            select * from
            result_table
            order by price asc
        ) as ordered_table
        group by group
    ) as single_min_table
    inner join result_table
    on result_table.group = single_min_table.group
    and result_table.price = single_min_table.price 
    ;
    

    然而,我刚刚意识到我需要处理另一个问题: 我不能忽略所有的规范,因为有provider属性,来自不同提供商的项目可能会或可能不能组合在一起,所以为了安全(并简化我的问题)我决定组合项目仅来自同一提供商,因此问题变为:

    例如,如果我有一个这样的初始表(只有2个组和2个提供者):

    id group price spec provider
    1  a     1     .    x
    2  a     2     ..   y
    3  a     3     ...  y
    4  b     1     ...  y
    5  b     2          x
    6  b     3          z 
    

    我需要结合

    id group price spec provider
    1  a     1     .    x
    5  b     2          x
    

    2  a     2     ..   y
    4  b     1     ...  y
    

    记录(id 6)可以从选项中删除,因为它没有所有组可用。

    所以不一定只选择每个组的最小值,而是从每个组中选择一个,这样对于每个提供商我都有最小的组合成本。

2 个答案:

答案 0 :(得分:2)

您无法在MySQL中进行数据透视,但您可以将结果分组在一起 GROUP_CONCAT函数将为您提供如下结果:

column A        column B        column c      column d
groups          specs           prices        sum(price)
a,b,c           some,list,xyz   1,5,7         13

以下是一个示例查询:
(该查询假定您在目标表上定义了一个名为id的主键(或唯一键)。

SELECT
  GROUP_CONCAT(a.`group`) as groups
  ,GROUP_CONCAT(a.spec) as specs 
  ,GROUP_CONCAT(a.min_price) as prices
  ,SUM(a.min_prices) as total_of_min_prices
FROM
  ( SELECT price, spec, `group` FROM table1
    WHERE id IN 
      (SELECT MIN(id) as id FROM table1 GROUP BY `group` HAVING price = MIN(price))
  ) AS a

请参阅:http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html

答案 1 :(得分:1)

仅生成total_cost

SELECT SUM(min_price) AS total_cost
FROM 
    ( SELECT MIN(price) AS min_price
      FROM TableX
      GROUP BY `group`
    ) AS grp

如果每组的行(不在列中)返回的最小价格的结果集合没有问题,那么您的问题是gretaest-n-per-group类型。有各种方法可以解决它。这是一个:

SELECT tg.grp 
       tm.price AS min_price
       tm.spec 
FROM
      ( SELECT DISTINCT `group` AS grp
        FROM TableX
      ) AS tg 
  JOIN
      TableX AS tm
    ON 
      tm.PK =                             --- the Primary Key of the table
      ( SELECT tmin.PK 
        FROM TableX AS tmin
        WHERE tmin.`group` = tg.grp
        ORDER BY tmin.price ASC
        LIMIT 1
      )