Есть ли более понятный способ работы с полями, которые не входят в составные функции или предложение GROUP BY? - PullRequest
1 голос
/ 27 апреля 2019

Я часто сталкиваюсь с ситуациями, когда у меня есть запрос, подобный этому:

SELECT
    a.Id,
    a.A,
    a.B,
    a.C,
    SUM(b.Foo) AS foo
FROM
    TableA AS a
    JOIN TableB AS b
        ON a.Id = b.TableAId
GROUP BY a.Id;

В SQL Server (а также MySQL, если ONLY_FULL_GROUP_BY имеет значение true), этот запрос бесполезен. Все должно быть либо а) в статистической функции, либо б) в GROUP BY.

Моя проблема в том, что оба решения выглядят плохо и вводят в заблуждение. Если вы выберете случайную статистическую функцию, такую ​​как MAX(), вы получите:

SELECT
    a.Id,
    MAX(a.A) AS A,
    MAX(a.B) AS B,
    MAX(a.C) AS C,
    SUM(b.Foo) AS foo
FROM
    TableA AS a
    JOIN TableB AS b
        ON a.Id = b.TableAId
GROUP BY a.Id;

Этот запрос выглядит так, как будто мы заботимся о максимальных значениях a.A, a.B и a.C и скрывает тот факт, что max не имеет смысла.

GROUP BY немного лучше:

SELECT
    a.Id,
    a.A,
    a.B,
    a.C,
    SUM(b.Foo) AS foo
FROM
    TableA AS a
    JOIN TableB AS b
        ON a.Id = b.TableAId
GROUP BY a.Id, A, B, C;

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

Мой фон в основном находится в MySQL с отключенным ONLY_FULL_GROUP_BY, поэтому я считаю, что это ограничение в SQL Server не нужно. Хотелось бы, чтобы между ними была какая-то счастливая среда; Для компьютера очень просто взглянуть на этот запрос и увидеть, что поля TableA не нужно агрегировать, в отличие от любого поля из TableB (кроме TableAId).

Есть мысли?

Ответы [ 2 ]

5 голосов
/ 27 апреля 2019

Это не проблема SQL Server!Поведение, которое вы видите, является нарушением MySQL (в общем), поэтому по умолчанию теперь запрещается такое поведение.Тем не менее, агрегирование по уникальному столбцу в таблице и выбор других столбцов в таблице является разрешенным стандартом SQL.Тем не менее, я думаю, что только Postgres реализует это.

Вот один метод, который вы оставили:

SELECT a.*, b.foo
FROM TableA a JOIN
     (SELECT b.TableAId, SUM(b.Foo) as foo
      FROM TableB b
      GROUP BY b.TableAId
     ) b
     ON a.Id = b.TableAId;
3 голосов
/ 27 апреля 2019

MySQL 5.7 и более поздние версии справляются с этим довольно хорошо:

mysql [localhost:5724] {msandbox} (test) > select @@sql_mode;
+-------------------------------------------------------------------------------------------------------------------------------------------+
| @@sql_mode                                                                                                                                |
+-------------------------------------------------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+-------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql [localhost:5724] {msandbox} (test) > SELECT
    ->     a.Id,
    ->     a.A,
    ->     a.B,
    ->     a.C,
    ->     SUM(b.Foo) AS foo
    -> FROM
    ->     TableA AS a
    ->     JOIN TableB AS b
    ->         ON a.Id = b.TableAId
    -> GROUP BY a.Id;
Empty set (0.01 sec)

Смотрите, ошибок нет!

Поскольку этот запрос группируется по уникальному ключу TableA, он может сказатьдругие столбцы TableA имеют функциональную зависимость от столбца, по которому вы группируете.Таким образом, нет необходимости выдавать ошибки о неоднозначных результатах.

Единственный столбец в списке выбора, который не имеет функциональной зависимости от столбца группировки, - это b.Foo, который в этом запросе безопасно находится внутриагрегатная функция.

Таким образом, MySQL, хотя раньше она оставляла за разработчиком возможность узнать, как писать запросы, избегающие неоднозначности, теперь имеет два улучшения, оба реализованы в MySQL 5.7.5 (2014-09-25):

  1. ONLY_FULL_GROUP_BY включен по умолчанию
  2. MySQL анализирует функциональные зависимости и не дает горе разработчика, если ваши неагрегированные столбцы функционально зависят от столбца группировки.

Эти улучшения были в целом доступны в MySQL в течение 3,5 лет (сейчас я пишу апрель 2019 года, а в октябре 2015 года ушел 5.7 GA).Сколько лет пройдет, прежде чем MySQL получит кредит на это улучшение?

PS Я не знаю, какие другие продукты RDBMS могут правильно выполнять анализ функциональной зависимости.

...