mysql:在表的每列中查找最大值

时间:2018-04-06 23:07:40

标签: mysql

我有下表。我正在寻找每列中的最大值和它匹配的用户名(要忽略的所有NULL值)。 一堆疯狂的谷歌搜索让我相信我需要找到最大值,然后使用第二个查询来找到匹配的用户名?

但是有一个查询可以一次性返回吗?

ID   username    Vale   Jorge   Andrea
-------------------------------------------
01   John        2       6       NULL
02   Ted         NULL    0       0
03   Marcy       NULL    2       1

Output would be...
John Jorge 6
John Vale 2
Marcy Andrea 1

4 个答案:

答案 0 :(得分:1)

有不同的查看方式,这里有一个表格,为每个具有最大匹配值的用户名提供一行:

SELECT
   username
 , IF (max_vale = t.vale, max_vale, NULL) AS for_vale
 , IF (max_jorge = t.jorge, max_jorge, NULL) AS for_jorge
 , IF (max_andrea = t.andrea, max_andrea, NULL) AS for_andrea
FROM (
   SELECT 
      MAX(vale) AS max_vale
    , MAX(jorge) AS max_jorge
    , MAX(andrea) AS max_andrea
   FROM t
) y
JOIN t ON (
  t.vale = max_vale
  OR t.jorge = max_jorge
  OR t.andrea = max_andrea
)

http://sqlfiddle.com/#!9/58e37d/5

这给出了:

username    for_vale    for_jorge   for_andrea
----------------------------------------------
John        2           6           (null)
Marty       (null)      (null)      1

基本上,我所做的就是选择特定的列最大值,然后使用该查询作为另一个查询的源,只查看MAX生成的列和过滤器({{1} })基于找到的匹配。

答案 1 :(得分:0)

这很长但很有效。我使用UNION ALL将所有列合并到一个表中。然后获得每个姓氏的最大值。使用姓氏和值将此连接到原始表。按降序排序。

select tv.*
from( select surname, max(val) as maxval
   from (
          select username,'vale' as surname,vale as val
         from tbl
         union all
         select username,'jorge' as surname,jorge
         from tbl
         union all
         select username,'andrea' as surname,andrea
         from tbl) tab
         group by surname) tt
         join (
            select username,'vale' as surname,vale as val
            from tbl
            union all
            select username,'jorge' as surname,jorge
            from tbl
           union all
           select username,'andrea' as surname,andrea
           from tbl) tv
       on tt.surname=tv.surname and tt.maxval=tv.val
       order by tv.val desc;

答案 2 :(得分:0)

这是一种相当简单的方法...创建一个包含所有最大值的表,并在将值与max匹配时将其连接到用户名。使用NULL isn't equal to anything的事实。我还没有尝试订购结果,但添加ORDER BY条款很容易。

select username, name, COALESCE(mv.vale, mv.jorge, mv.Andrea) as value 
from table1
join 
(select 'Vale' as name, max(vale) as vale, NULL as jorge, NULL as andrea from table1
union ALL
select 'Jorge', NULL, max(jorge), NULL from table1
union all
select 'Andrea', NULL, NULL, max(andrea) from table1) mv
on table1.vale = mv.vale or table1.jorge = mv.jorge or table1.andrea = mv.andrea

输出

 username   name    value   
 John       Vale    2
 John       Jorge   6
 Marcy      Andrea  1

将此推断为更多列是相当简单的(如果有点痛苦),例如添加一个名为fred的列,你会使用(在**里面改变):

select username, name, COALESCE(mv.vale, mv.jorge, mv.Andrea**, mf.fred**) as value 
from table1
join 
(select 'Vale' as name, max(vale) as vale, NULL as jorge, NULL as andrea**, NULL as fred** from table1
union ALL
select 'Jorge', NULL, max(jorge), NULL**, NULL** from table1
union all
select 'Andrea', NULL, NULL, max(andrea)**, NULL** from table1) mv
**union all
select 'Fred', NULL, NULL, max(fred), NULL from table1) mf**
on table1.vale = mv.vale or table1.jorge = mv.jorge or table1.andrea = mv.andrea **or table1.fred = mf.fred**

如果您可以访问存储过程,也可以这样做(在列方面更加灵活)

DROP PROCEDURE IF EXISTS list_maxes;
DELIMITER //
CREATE PROCEDURE list_maxes(tname VARCHAR(20), column_list VARCHAR(1000))
BEGIN
    DECLARE maxv INT DEFAULT 0;
    DECLARE cpos INT;
    DECLARE colname VARCHAR(20);

    -- loop through the column names
    WHILE (LENGTH(column_list) > 0)
    DO
       SET cpos = LOCATE(',', column_list);
       IF (cpos > 0) THEN
           SET colname = LEFT(column_list, cpos - 1);
           SET column_list = SUBSTRING(column_list, cpos + 1);
       ELSE
           SET colname = column_list;
           SET column_list = '';
       END IF;

       -- find the maximum value of this column
       SET @getmax = CONCAT('SELECT MAX(', colname, ') INTO @maxv FROM Table1');
       PREPARE s1 FROM @getmax;
       EXECUTE s1;
       DEALLOCATE PREPARE s1;

       -- now find the user with the maximum value
       SET @finduser = CONCAT("SELECT username, '", colname, "' AS name, ", colname, ' AS value FROM ', tname,' WHERE ', colname, ' = ', @maxv);
       PREPARE s2 FROM @finduser;
       EXECUTE s2;
       DEALLOCATE PREPARE s2;
    END WHILE;
END//
DELIMITER ;
CALL list_maxes('table1', 'Vale,Jorge,Andrea')

输出

John       Vale    2
John       Jorge   6
Marcy      Andrea  1

答案 3 :(得分:0)

作为解决请求的整体其他方式,我们可以查看模型,例如,看似是域内容的内容被表示为列而不是行。这是典型的源聚合查询(例如,用于获取聚合总计或分组的数据透视或汇总),但如果基础数据展开,则应该基于该数据源的事务完整性("传播) out"潜在来源)。

基本上,我想知道为什么数据库中有ValeJorgeAndrea列。这意味着它已经被总结了。

因此,我们可能会看到一个替代模型,它可以更容易地为这些目的进行导航:

CREATE TABLE IF NOT EXISTS `user` (
  `id` MEDIUMINT NOT NULL AUTO_INCREMENT,
  `username` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `prospect` (
  `id` MEDIUMINT NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `aggregate` (
  `id` MEDIUMINT NOT NULL AUTO_INCREMENT,
  `user_id` int(6) unsigned NOT NULL,
  `prospect_id` int(6) unsigned NOT NULL,
  `total` int(6) unsigned NOT NULL,
  PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;

SELECT
   user.username
 , prospect.name
 , MAX(aggregate.total) AS max_aggregate
FROM aggregate
JOIN user ON user_id = user.id
JOIN prospect ON prospect_id = prospect.id
GROUP BY username

这会产生:

John    Andrea  6
Marty   Jorge   2
Ted     Jorge   5

http://sqlfiddle.com/#!9/07ba0c/1

这对您现在可能没有用,但随着您的体验增长以及您对高级查询的体验的发展,这将更有意义。主要困难可能是核心数据已经转变,使得查询更加困难,因为您想要的是不同的dimension than what you may have already derived