Published on

August 11, 2021

Улучшение запросов GROUP BY в SQL Server

Группировка данных в SQL Server иногда может стать сложной, особенно при работе с столбцами группировки, которые включают сложные выражения. В таких случаях логический порядок обработки запроса зачастую заставляет вас повторять выражение, так как его псевдоним не может быть использован в операторе GROUP BY. Однако существует решение, которое может упростить и улучшить читаемость ваших запросов GROUP BY.

Недавно Oracle представила мощный синтаксис в своем релизе 23c, позволяющий использовать псевдонимы столбцов в операторе GROUP BY. Эта функция значительно упрощает синтаксис и повышает общую читаемость запроса. Как пользователи SQL Server, мы можем только надеяться, что эта функциональность будет принята в будущих версиях SQL Server.

В настоящее время в SQL Server, когда вы пытаетесь использовать псевдоним, определенный в списке SELECT, в операторе GROUP BY, вы столкнетесь с ошибкой. Например:

SELECT TheMonth = DATEFROMPARTS(YEAR(create_date), MONTH(create_date), 1),
       MonthlyDBs = COUNT(*)
FROM sys.databases
GROUP BY TheMonth;

Этот запрос приведет к следующей ошибке:

Msg 207, Level 16, State 1
Invalid column name 'TheMonth'.

Чтобы сгруппировать по столбцу ‘TheMonth’, вам необходимо использовать одно из следующих обходных решений:

  1. Повторение выражения:
  2. SELECT TheMonth = DATEFROMPARTS(YEAR(create_date), MONTH(create_date), 1),
           MonthlyDBs = COUNT(*)
    FROM sys.databases
    GROUP BY DATEFROMPARTS(YEAR(create_date), MONTH(create_date), 1);
    
  3. Использование общего выражения таблицы (CTE):
  4. WITH cte(TheMonth) AS 
    (
      SELECT DATEFROMPARTS(YEAR(create_date), MONTH(create_date), 1)
      FROM sys.databases
    )
    SELECT TheMonth, MonthlyDBs = COUNT(*)
    FROM cte
    GROUP BY TheMonth;
    
  5. Использование подзапроса:
  6. SELECT TheMonth, MonthlyDBs = COUNT(*)
    FROM
    (
      SELECT DATEFROMPARTS(YEAR(create_date), MONTH(create_date), 1)
      FROM sys.databases
    ) AS sq(TheMonth)
    GROUP BY TheMonth;
    
  7. Использование CROSS APPLY:
  8. SELECT TheMonth, MonthlyDBs = COUNT(*)
    FROM sys.databases
    CROSS APPLY 
    (
      SELECT DATEFROMPARTS(YEAR(create_date), MONTH(create_date), 1)
    ) AS ca(TheMonth)
    GROUP BY TheMonth;
    

Стоит отметить, что в SQL Server 2022 или Azure SQL Database вы можете упростить выражение, используя DATETRUNC(MONTH, create_date). Однако вы все равно не можете обойтись без использования одного из вышеуказанных обходных решений.

В Oracle, начиная с 23c, вы можете просто использовать следующий синтаксис:

SELECT TRUNC(DateTimeColumnName, 'MONTH') AS TheMonth,
       COUNT(*) AS MonthlyWhatever
FROM TableName
GROUP BY TheMonth;

Эта форма намного удобнее и устраняет необходимость понимать логический порядок обработки. Она также разъясняет часто путающий факт о том, что псевдонимы из SELECT доступны в ORDER BY. Не было бы здорово иметь поддержку такого синтаксиса в SQL Server?

Однако важно учитывать, что слепое следование примеру Oracle не всегда является лучшим подходом. Например, недавнее добавление Oracle возможности GROUP BY column_position, которая позволяет ссылаться на группирующий столбец по его порядковому номеру, некоторыми рассматривается как бомба замедленного действия. Поэтому важно тщательно оценивать и внедрять новые функции в SQL Server.

В заключение, хотя SQL Server в настоящее время не имеет возможности использовать псевдонимы столбцов в операторе GROUP BY, существуют обходные решения, позволяющие достичь желаемых результатов. Было бы полезно для SQL Server принять синтаксис, представленный Oracle, так как он упрощает и повышает читаемость запросов GROUP BY. Однако важно подходить к новым функциям с осторожностью и учитывать их потенциальные последствия.

Дата последнего обновления статьи: 2023-12-01

Click to rate this post!
[Total: 0 Average: 0]

Let's work together

Send us a message or book free introductory meeting with us using button below.