Статьи

MySQL Bad Idea # 666

MySQL … Мы уже писали о MySQL. Много раз. Мы показали плохие идеи, реализованные в MySQL здесь:

Но это бьет все. Проверьте этот вопрос переполнения стека . Он гласит: «Почему Oracle не поддерживает ‘group by 1,2,3’?». Сначала я подумал, что этот пользователь может быть сбит с толку, потому что SQL позволяет ссылаться на столбцы по индексу (на основе 1!) В ORDER BYпредложениях:

SELECT first_name, last_name
FROM customers
ORDER BY 1, 2

Выше эквивалентно ORDER BY first_name, last_name. Индексы 1, 2ссылаются на столбцы из проекции. Это может быть полезно время от времени, чтобы избежать повторения сложных выражений столбцов, хотя это, вероятно, немного рискованно, так как вы можете изменить семантику упорядочения при добавлении столбца к SELECTпредложению.

Но этот пользователь хотел использовать тот же синтаксис для GROUP BYпредложения. И это на самом деле работает в MySQL! Проверьте следующий запрос:

SELECT a, b
FROM (
  SELECT 'a' a, 'b' b, 'c' c UNION ALL
  SELECT 'a'  , 'c'  , 'c'   UNION ALL
  SELECT 'a'  , 'b'  , 'd'
) t
GROUP BY 1, 2
ORDER BY 2

Смотрите пример на SQLFiddle

Вышеуказанное дает …

| A | B |
|---|---|
| a | b |
| a | c |

Но что бы это вообще значило? По нашему углубленному разъяснению положений SQL , проекция ( SELECTпункт) логически оценивается после того, как в GROUP BYп. Другими словами, столбцы, определенные в SELECTпредложении, еще не входят в объем GROUP BYпредложения. Следовательно, единственной разумной семантикой индексов столбцов будет индекс из источника таблицы t. Но это не так. Проверьте этот альтернативный запрос:

SELECT a, b
FROM (
  SELECT 'a' a, 'b' b, 'c' c UNION ALL
  SELECT 'a'  , 'c'  , 'c'   UNION ALL
  SELECT 'a'  , 'b'  , 'd'
) t
GROUP BY 1, 2
ORDER BY 2

Смотрите пример на SQLFiddle

Это теперь дает:

| B | C |
|---|---|
| b | c |
| c | c |
| b | d |

И это (вероятно?) Ожидаемое поведение в MySQL, как указано в документации :

На столбцы, выбранные для вывода, можно ссылаться в предложениях ORDER BY и GROUP BY, используя имена столбцов, псевдонимы столбцов или положения столбцов. Позиции столбцов целые и начинаются с 1

Документация на самом деле обрабатывается GROUP BYочень похожим образом ORDER BY. Например, можно указать направление заказа, используя GROUP BYтолько:

MySQL расширяет предложение GROUP BY, так что вы также можете указать ASC и DESC после столбцов, названных в предложении:

SELECT a, COUNT(b) 
FROM test_table GROUP BY a DESC;

Хотя мы не можем найти разумный крайний случай, который нарушает эту функцию, мы все же думаем, что в этом есть что-то подозрительное. Тот факт, что SELECTпредложение логически оценивается после таблицы source ( FROM, WHERE, GROUP BY, HAVING), позволяя GROUP BYссылаться на предложение, похоже, приводит к странному пониманию SQL.

С другой стороны, SQL является очень многословным языком с небольшой поддержкой для объявления многократного использования объектов, коротких общих табличных выражений и в WINDOWп . На самом деле немного удивительно, что разработчики стандартов SQL поддерживают это WINDOWпредложение для объявления многократно используемых оконных рам, прежде чем вводить гораздо более удобные «общие выражения столбцов», например:

-- Common column/table expressions:
WITH x AS CASE t1.a
          WHEN 1 THEN 'a'
          WHEN 2 THEN 'b'
                 ELSE 'c'
          END,
     y AS SOME_FUNCTION(t2.a, t2.b)
SELECT x, NVL(y, x)
FROM t1 JOIN t2 ON t1.id = t2.id
GROUP BY x, y
ORDER BY x DESC, y ASC

При использовании общих выражений столбцов повторное использование выражений столбцов не зависит от самого SELECTпредложения. Другими словами, вы можете повторно использовать выражения столбцов в JOINпредложениях, WHEREпредложениях, GROUP BYпредложениях, HAVINGпредложениях и т. Д., Фактически не используя SELECTих.

Итак, чтобы быть честным с MySQL, хотя эта функция не является функциональной в ее нынешнем виде, она предоставляет обходной путь для многословия SQL.