【问题标题】:Elegant mysql to select, group, combine multiple rows from one table优雅的 mysql 从一张表中选择、分组、组合多行
【发布时间】:2012-07-28 13:24:34
【问题描述】:

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

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. 选择每组中包含最低价格的行
  2. 将列合并为一行

我知道这可以使用多个查询和/或结合对结果的一些非 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),不如将它们存储在临时表中 (使用 sum 计算 total_cost 会更容易)

随意抛开任何想法,不必是完整的答案,如果你有一个优雅的方式来完成任务1,我觉得它已经足够了

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

我的程序的目标是以最低的成本确定物品的最佳组合(最好同时具有更高的实用价值)。

考虑@ypercube 关于大量组的评论,临时表似乎是唯一可行的解​​决方案。并且还指出MySQL中没有pivoting功能(虽然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) 可以从选择中删除,因为它没有所有可用的组。

因此不必只选择每个组的最小值,而是从每个组中选择一个,这样对于每个提供者我都有一个最小的组合成本。

【问题讨论】:

  • 那么,如果你有一千个组会发生什么?您的预期结果将有 2000 列?如果你有一百万个组怎么办?
  • SQL 适用于处理多行,但将行转换为(任意数量的)列并不容易。这称为旋转。
  • 作为您期望得到的结果,我可以看到您正在将行转换为列。例如:price_a,spec_a。那只是为了得到total_cost?
  • 如果您添加有关附加连接的详细信息,则可能不需要旋转。

标签: mysql sql


【解决方案1】:

您不能在 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

【讨论】:

  • HAVING price = MIN(price) 看起来语法无效。
  • @ypercube 是的,但当然having 需要关注group by
  • 它不是有效的 ANSI SQL,尽管它在 MySQL 中有效。而且我不确定它是否给出了 OP 期望的结果,甚至在 MySQL 中也没有。
  • @ypercube,我有点困惑。根据 SQL:1992 contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt 的第 188 页,它是有效的语法,但如果 havingmin(或 max)一起使用,该页面会警告不确定的结果。不确定性由select MIN(id) AS id 修复。
  • 在该页面中,语法规则:1) ... Each <column reference> directly contained in the <search condition> shall unambiguously reference a grouping column of T or be an outer reference.
【解决方案2】:

仅生产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
      )

【讨论】:

  • 感谢您的cmets和回答,但我需要获取构成总成本的每个项目的详细信息,因为最重要的部分是确定选择哪些项目以最小化成本.
猜你喜欢
  • 2014-05-31
  • 1970-01-01
  • 1970-01-01
  • 2016-09-23
  • 1970-01-01
  • 2019-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多