При написании прямых SQL-запросов к базе данных 1С (например, через внешние компоненты или прямое обращение к MS SQL Server) программисты часто сталкиваются с ошибками при попытке сгруппировать результат по тексту, вычисляемому значению или фиксированному литералу. Проанализируем, почему возникают подобные ошибки, и разберем проверенные способы их устранения.
Рассмотрим стандартный пример прямого запроса, вызывающего проблему:
SELECT top 5
't' as test,
Номенклатура.ID as [Номенклатура $Справочник.Номенклатура]
FROM
$Справочник.Номенклатура Номенклатура (nolock)
GROUP BY
test,
Номенклатура.ID
При выполнении такого запроса СУБД возвращает ошибку «Недопустимое имя столбца "test"». Если же заменить псевдоним test на сам строковый литерал 't' в секции GROUP BY, то появится другая ошибка: «Каждое выражение GROUP BY должно содержать по меньшей мере одну ссылку на столбец».
Разберем по шагам, почему СУБД MS SQL Server ведет себя именно так:
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY. Поскольку предложение GROUP BY выполняется раньше, чем SELECT, псевдоним (алиас) столбца test еще не существует на момент группировки.GROUP BY не может состоять только из статических строк, констант или чисел. Любое выражение внутри группировки должно содержать как минимум одну ссылку на реальный столбец таблицы БД.Если вам нужно просто вывести постоянное текстовое значение (литерал) рядом со сгруппированными данными, его не нужно включать в предложение GROUP BY. Константное значение прекрасно выбирается в секции SELECT сама по себе.
Уберем лишнее выражение из группировки:
SELECT top 5
't' as test,
Номенклатура.ID as [Номенклатура $Справочник.Номенклатура]
FROM
$Справочник.Номенклатура Номенклатура (nolock)
GROUP BY
Номенклатура.ID
Этот вариант является наиболее простым и корректным, когда текстом выступает фиксированная строка.
Если главная цель запроса — избавиться от дубликатов строк, содержащих комбинацию текста и полей справочника, без использования агрегатных функций (типа SUM или COUNT), лучше использовать ключевое слово DISTINCT:
SELECT DISTINCT top 5
't' as test,
Номенклатура.ID as [Номенклатура $Справочник.Номенклатура]
FROM
$Справочник.Номенклатура Номенклатура (nolock)
В случаях, когда вам действительно необходимо сгруппировать данные по вычисляемому текстовому полю или алиасу, вынесите формирование текстового поля во внутренний запрос, а группировку выполните во внешнем. Разберем этот пример:
SELECT
SubQuery.test,
SubQuery.НоменклатураID
FROM (
SELECT
't' as test,
Номенклатура.ID as НоменклатураID
FROM $Справочник.Номенклатура Номенклатура (nolock)
) AS SubQuery
GROUP BY
SubQuery.test,
SubQuery.НоменклатураID
В этом случае во внешнем запросе поле test уже является полноценным столбцом подзапроса, и группировка по нему пройдет успешно.
Посмотрим на две альтернативные ситуации, которые часто встречаются при написании сложных SQL-запросов:
SUBSTRING или LEFT), в секции GROUP BY нужно указывать само выражение целиком, а не его псевдоним из SELECT.SELECT, но вы не хотите выносить его во вложенный запрос или группировать по нему, оберните его агрегатной функцией MAX('t') или MIN('t').