MySQL-запрос для отображения только максимальной длины значения каждого столбца - PullRequest
2 голосов
/ 18 декабря 2011

У меня есть таблица с n столбцами и x строками.

Я хочу сделать запрос, чтобы показать таблицу со всеми столбцами и значением максимальной длины этого столбца (и идентификатором строки этой строки с максимальной длиной значения).

+--------+--------+----+
| 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

Как следующий запрос с добавлением двух столбцов (максимальная длина и идентификатор строки)

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`

Почти там (спасибо Биллу) ... (нужно только указать "таблицу"), но теперь, как запустить _SQL и тот же запуск ...

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 ]

4 голосов
/ 18 декабря 2011

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что достаточно только для генерации этого SQL-запроса для 9 столбцов.Вы можете увеличить это ограничение:

SET group_concat_max_len = 1024*1024;

Это увеличивает ограничение только для текущего сеанса базы данных.Вы можете использовать SET GLOBAL ..., чтобы изменить его для всех сессий.Если вы хотите, чтобы это сохранялось после перезапуска MySQL, установите значение в вашем файле my.cnf (не нужно использовать SET GLOBAL в файле конфигурации).

1 голос
/ 18 декабря 2011

Решение этого будет немного сложным, поэтому я не собираюсь писать точный SQL, но вот общая идея:

  1. Создайте табличную переменную для хранения ваших результатов.Он будет иметь ту же схему, что вы опубликовали в своем ответе.

  2. Создайте еще одну табличную переменную, в которой будут содержаться все имена столбцов, которые вы хотите развернуть.Вам просто нужна таблица с именем столбца.

  3. Вставьте имена столбцов во временную таблицу, созданную на шаге 2:

    вставьте в @TempTable (ColumnName) выберите COLUMN_NAMEfrom information_schema.columns где Table_Name = 'YourTable';

  4. Используя курсор, переберите все столбцы в переменной таблицы имен столбцов.

  5. Внутри цикла вы собираетесь создавать и выполнять динамический запрос SQL, используя функцию ПОДГОТОВКА.Каждая итерация цикла будет вставлять одну строку в таблицу результатов для одного имени столбца.

    PREPARE STMT FROM @query;EXECUTE STMT;

Вот удар по динамическому 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 и использовать функцию сводной таблицы:)

0 голосов
/ 18 декабря 2011

Если я понял, что вам нужно, что-то вроде этого должно работать (проверено на 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
0 голосов
/ 18 декабря 2011

Попробуйте это:

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

... и так далее для каждого столбца.

Это также решает проблему двух разных значений одинаковой длины

...