【问题标题】:MySQL GROUP BY two columnsMySQL GROUP BY 两列
【发布时间】:2011-01-12 02:33:30
【问题描述】:

我在这里尝试按多列进行分组 - 每张桌子上一个。
在这种情况下,我想通过将每个客户当前的投资组合和现金相加来找到每个客户的最高投资组合价值,但客户可能拥有多个投资组合,因此我需要每个客户的顶级投资组合。

目前,通过下面的代码,我为他们的每个顶级投资组合多次获得相同的客户(它不是按客户 ID 分组的)。

SELECT clients.id, clients.name, portfolios.id, SUM ( portfolios.portfolio +  portfolios.cash ) AS total
FROM clients, portfolios
WHERE clients.id = portfolios.client_id
GROUP BY portfolios.id, clients.id
ORDER BY total DESC
LIMIT 30 

【问题讨论】:

    标签: sql mysql database


    【解决方案1】:

    首先,让我们做一些测试数据:

    create table client (client_id integer not null primary key auto_increment,
                         name varchar(64));
    create table portfolio (portfolio_id integer not null primary key auto_increment,
                            client_id integer references client.id,
                            cash decimal(10,2),
                            stocks decimal(10,2));
    insert into client (name) values ('John Doe'), ('Jane Doe');
    insert into portfolio (client_id, cash, stocks) values (1, 11.11, 22.22),
                                                           (1, 10.11, 23.22),
                                                           (2, 30.30, 40.40),
                                                           (2, 40.40, 50.50);
    

    如果您不需要投资组合 ID,这很容易:

    select client_id, name, max(cash + stocks)
    from client join portfolio using (client_id)
    group by client_id
    
    +-----------+----------+--------------------+
    | client_id | name     | max(cash + stocks) |
    +-----------+----------+--------------------+
    |         1 | John Doe |              33.33 | 
    |         2 | Jane Doe |              90.90 | 
    +-----------+----------+--------------------+
    

    由于您需要投资组合 ID,因此事情变得更加复杂。让我们分步进行。首先,我们将编写一个子查询,返回每个客户的最大投资组合值:

    select client_id, max(cash + stocks) as maxtotal
    from portfolio
    group by client_id
    
    +-----------+----------+
    | client_id | maxtotal |
    +-----------+----------+
    |         1 |    33.33 | 
    |         2 |    90.90 | 
    +-----------+----------+
    

    然后我们将查询投资组合表,但使用与前一个子查询的连接,以便仅保留总价值为客户最大值的投资组合:

     select portfolio_id, cash + stocks from portfolio 
     join (select client_id, max(cash + stocks) as maxtotal 
           from portfolio
           group by client_id) as maxima
     using (client_id)
     where cash + stocks = maxtotal
    
    +--------------+---------------+
    | portfolio_id | cash + stocks |
    +--------------+---------------+
    |            5 |         33.33 | 
    |            6 |         33.33 | 
    |            8 |         90.90 | 
    +--------------+---------------+
    

    最后,我们可以加入客户表(如您所做的那样)以包含每个客户的名称:

    select client_id, name, portfolio_id, cash + stocks
    from client
    join portfolio using (client_id)
    join (select client_id, max(cash + stocks) as maxtotal
          from portfolio 
          group by client_id) as maxima
    using (client_id)
    where cash + stocks = maxtotal
    
    +-----------+----------+--------------+---------------+
    | client_id | name     | portfolio_id | cash + stocks |
    +-----------+----------+--------------+---------------+
    |         1 | John Doe |            5 |         33.33 | 
    |         1 | John Doe |            6 |         33.33 | 
    |         2 | Jane Doe |            8 |         90.90 | 
    +-----------+----------+--------------+---------------+
    

    请注意,这会为 John Doe 返回两行,因为他有两个总价值完全相同的投资组合。为了避免这种情况并选择任意的顶级投资组合,请在 GROUP BY 子句上添加标签:

    select client_id, name, portfolio_id, cash + stocks
    from client
    join portfolio using (client_id)
    join (select client_id, max(cash + stocks) as maxtotal
          from portfolio 
          group by client_id) as maxima
    using (client_id)
    where cash + stocks = maxtotal
    group by client_id, cash + stocks
    
    +-----------+----------+--------------+---------------+
    | client_id | name     | portfolio_id | cash + stocks |
    +-----------+----------+--------------+---------------+
    |         1 | John Doe |            5 |         33.33 | 
    |         2 | Jane Doe |            8 |         90.90 | 
    +-----------+----------+--------------+---------------+
    

    【讨论】:

    • 这是一个了不起的答案,一旦我将 ORDER BY maxtotal DESC 放在最后,它就完美了! ;) 谢谢
    【解决方案2】:

    在 group by 上使用 Concat 会起作用

    SELECT clients.id, clients.name, portfolios.id, SUM ( portfolios.portfolio + portfolios.cash ) AS total
    FROM clients, portfolios
    WHERE clients.id = portfolios.client_id
    GROUP BY CONCAT(portfolios.id, "-", clients.id)
    ORDER BY total DESC
    LIMIT 30
    

    【讨论】:

    • 聪明,我会说。也适合我
    • 不错的解决方案!我会在那里添加一个分隔符:CONCAT(portfolios.id,“-”,clients.id)。如果没有分隔符,可能会有相同的连接值与不同的值对。
    • 正如 maksa 所说,分隔符非常重要,否则如果您碰巧遇到投资组合 1 属于客户 11(concat:'111')而投资组合 11 属于客户 1(concat:也'111') 那么它们将被组合在一起。
    • 虽然CONCAT 确实有很高的性能成本,但正如其他答案所建议的那样,它可能比使用子查询性能更高......
    • 还有CONCAT_WS('-', field, field)可以用指定的分隔符连接字段。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多