MySQL查询仅显示每列的最大值长度

时间:2011-12-18 18:11:56

标签: mysql max

我有一个包含n列和x行的表。

我想进行查询以显示包含所有列的表以及该列的最大长度值(以及具有最大值长度的该行的行ID)。

+--------+--------+----+
| column | length | id |
+--------+--------+----+
| a      |    123 |  1 |
| b      |    123 |  8 |
| c      |    123 |  6 |
| d      |    123 |  5 |
| e      |    123 |  3 |
+--------+--------+----+

a,b,c等是列名,长度是该列中的最大长度,id是该列的最大值长度的行。

这样的东西?但随后动态地为所有列:

SELECT MAX(LENGTH(`column_a`)) AS `length`, `id`
FROM `table` GROUP BY LENGTH(`column_a`) 
ORDER BY LENGTH(`column_a`) DESC LIMIT 1

就像添加了两列的下一个查询(最大长度和行ID)

SHOW COLUMNS FROM `table`

也许还使用此查询来获取特定表的列名:

SELECT `column_name` AS `column` 
FROM `information_schema`.`columns` 
WHERE `table_name` = 'table' 
AND `column_name` != 'id' 
ORDER BY `ordinal_position`

几乎就在那里(感谢Bill)......(只需指定'table')但现在如何运行_SQL al同样的运行......

SELECT CONCAT(GROUP_CONCAT(CONCAT('(SELECT \'', `column_name`,'\' AS `column`, LENGTH(`', `column_name`,'`) AS `length`, id ', 'FROM `', `table_schema`,'`.`', `table_name`,'` ORDER BY `length` DESC LIMIT 1)') SEPARATOR ' UNION ALL '), ';') AS _SQL
FROM `information_schema`.`columns` 
WHERE `table_name` = 'table' 
  AND `column_name` IN (
    SELECT `column_name`
    FROM `information_schema`.`columns` 
    WHERE `table_name` = 'table' 
    AND `column_name` != 'id' 
    ORDER BY `ordinal_position`);

4 个答案:

答案 0 :(得分:4)

MySQL没有任何方法可以在单个查询中执行您想要的操作。在准备查询时,必须修复对列的所有引用。

您可以做的最好的事情是对INFORMATION_SCHEMA使用一个查询来生成一个新的动态SQL查询,以获取您想要的信息。

我针对MySQL 5.5.16进行了测试:

SELECT CONCAT(GROUP_CONCAT( 
  CONCAT('(SELECT \'',COLUMN_NAME,'\' AS `column`, LENGTH(`',COLUMN_NAME,'`) AS `length`, id ',
  'FROM `',TABLE_SCHEMA,'`.`',TABLE_NAME,'` ORDER BY `length` DESC LIMIT 1)')
  SEPARATOR ' UNION ALL '), ';') AS _SQL
FROM INFORMATION_SCHEMA.COLUMNS
WHERE (TABLE_SCHEMA, TABLE_NAME) = ('test', 'tt') 
  AND COLUMN_NAME IN ('a', 'b', 'c');

此查询产生以下输出(为了在此处发布,我添加了换行符):

(SELECT 'a' AS `column`, LENGTH(`a`) AS `length`, id 
 FROM `test`.`tt` ORDER BY `length` DESC LIMIT 1) 
UNION ALL
(SELECT 'b' AS `column`, LENGTH(`b`) AS `length`, id 
 FROM `test`.`tt` ORDER BY `length` DESC LIMIT 1)
UNION ALL
(SELECT 'c' AS `column`, LENGTH(`c`) AS `length`, id 
 FROM `test`.`tt` ORDER BY `length` DESC LIMIT 1);

生成的查询在我的测试中返回以下结果:

+--------+--------+----+
| column | length | id |
+--------+--------+----+
| a      |     10 |  2 | 
| b      |      9 |  1 | 
| c      |      6 |  2 | 
+--------+--------+----+

请注意,这不会解决关系。如果多个行具有相同的最长字符串,则它将仅报告一个id,任意选择。


重新提出你的额外问题:

您必须将它们作为两个单独的查询来执行。我在回答的开头说过,在准备查询时必须在SQL字符串中修复列引用。您无法动态发现列,也无法在同一查询中查询其数据。


重新评论:

GROUP_CONCAT()返回的最长字符串默认为1024,这足以为9列生成此SQL查询。您可以增加此限制:

SET group_concat_max_len = 1024*1024;

这仅增加当前数据库会话的限制。您可以使用SET GLOBAL ...为所有会话更改它。如果您希望在重新启动MySQL后保持此值,请在my.cnf文件中设置该值(无需在配置文件中使用SET GLOBAL)。

答案 1 :(得分:1)

解决这个问题会有点棘手,所以我不打算编写确切的SQL,但这里有一般的想法:

  1. 创建一个表变量来保存结果。它将具有您在答案中发布的相同架构。

  2. 创建另一个表变量以保存要转动的所有列名。您只需要一个带有名称列的表。

  3. 将列名插入到步骤2中创建的临时表中:

    插入@TempTable(ColumnName) 从information_schema.columns中选择COLUMN_NAME,其中Table_Name ='YourTable';

  4. 使用游标循环遍历列名表变量中的每一列。

  5. 在循环中,您将使用PREPARE STATEMENT函数创建并执行动态SQL查询。通过循环的每次迭代都会在结果表中为一个列名插入一行。

    从@query预备STMT; 执行STMT;

  6. 这是对需要执行的动态SQL的准备。 @columnName是循环中变量的名称。

    declare @maxLength int;
    select @maxLength =  max(length(@ColumnName)) maxlength from YourTable;
    insert into @results (ColumnName, MaxLength, RowId)
    select '@ColumnName', @maxLength, Id from YourTable where length(@ColumnName)) = @maxLength;
    

    或者,您可以将数据转储到Excel中并使用数据透视表功能:)

答案 2 :(得分:0)

试试这个:

SELECT
    length(concat('',a)) as maxlen,
    group_concat(if (length(concat('',a))=@maxlen_a,a,null)) as maxlenval
FROM
    (select @maxlen_a:=max(length(concat('',a))) from tablename) as aview,
    tablename
GROUP BY maxlen 
HAVING maxlenval IS NOT null

UNION

SELECT
    length(concat('',b)) as maxlen,
    group_concat(if (length(concat('',b))=@maxlen_b,b,null)) as maxlenval
FROM
    (select @maxlen_b:=max(length(concat('',b))) from tablename) as bview,
    tablename
GROUP BY maxlen 
HAVING maxlenval IS NOT null

......等等每一栏。

这也解决了两个相同长度的不同值的问题

答案 3 :(得分:0)

如果我理解你需要的东西,这样的东西应该有效(在Mysql 5.1上测试):

SELECT  
    column, length, id 
FROM 
    (
     (SELECT 'a' AS column, CHAR_LENGTH(a) AS length, id 
      FROM yourtable 
      ORDER BY length DESC 
      LIMIT 1)
     UNION
     (SELECT 'b' AS column, CHAR_LENGTH(b) AS length, id 
      FROM yourtable 
      ORDER BY length DESC 
      LIMIT 1)
     UNION
     (SELECT 'c' AS column, CHAR_LENGTH(c) AS length, id 
      FROM yourtable 
      ORDER BY length DESC 
      LIMIT 1)
     UNION 
     (...)
) T