Claude Skill

composing-1c-queries

Compose correct and optimized 1C:Enterprise query language queries. Covers ВЫБРАТЬ/ИЗ/ГДЕ structure, table naming (catalogs, documents, registers, virtual tables), field selection, joins, grouping, totals, temporary tables, and parameter usage. Includes accounting register virtua

LLM Mart · 0 points · 16 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download Desko77-claude-code-skills-1c-skills_composing-1c-queries-ac33656.zip · 21 KB
Part of desko77/claude-code-skills-1c — 48 skills

Install

skills CLI npx skills add https://github.com/Desko77/claude-code-skills-1c/tree/main/skills/composing-1c-queries
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install desko77-claude-code-skills-1c@llmmart
Git git clone https://github.com/Desko77/claude-code-skills-1c.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole desko77/claude-code-skills-1c collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Composing 1C Queries

Rules and patterns for writing correct 1C:Enterprise query language (язык запросов 1С). Queries are executed via the execute_query tool/endpoint.

CRITICAL: Verify Metadata Before Querying

NEVER guess or invent metadata object names, attribute names, or tabular section names. 1C configurations vary greatly - object and field names are unique to each database.

Before composing a query, if you are not certain about the exact names, use get_metadata or any other available tool to retrieve 1C configuration metadata to discover:

  • Available metadata objects (catalogs, documents, registers, etc.)
  • Object attributes (реквизиты) and their types
  • Tabular sections (табличные части) and their columns
  • Register dimensions, resources, and attributes

Workflow: retrieve metadata → confirm names → compose query → validate query → execute query

A query with a wrong object or field name will fail with a runtime error. Spending one call on metadata retrieval is always cheaper than debugging a failed query.

Имена таблиц и полей из AI-EDT

Если сервер AI-EDT подключен, имена не угадываются, а берутся у него - insights operation=describe_db_tables (отдельное имя describe_db_tables тоже работает). Инструмент показывает, во что объект превращается в базе данных: основную таблицу, по одной на каждую табличную часть, виртуальные таблицы регистра (остатки, обороты, срезы) с их параметрами, таблицу изменений и перерасчеты регистра расчета. Имена таблиц и полей отдаются сразу на двух языках, с типами полей, готовыми к подстановке после ИЗ.

Это дешевле, чем писать запрос по памяти и ловить ошибки имен по одной через validate_query: за один вызов видно все, что вообще можно выбрать.

Validate Query via AI-EDT

Если сервер AI-EDT подключен (инструменты ai-edt доступны), обязательно проверяй запрос перед выполнением через validate_query:

  • Проверяет синтаксис и семантику в контексте реального проекта
  • Для запросов СКД: dcsMode=true
  • Ловит ошибки имен таблиц, полей, типов до выполнения

Formatting: Always write the entire query text in a single line. Do not use line breaks or multiline formatting.

Query Structure

Canonical order of clauses (required section marked, rest optional):

ВЫБРАТЬ [РАЗРЕШЕННЫЕ] [РАЗЛИЧНЫЕ] [ПЕРВЫЕ <N>]
    <field list>
ИЗ
    <data sources>
[ГДЕ <condition>]
[СГРУППИРОВАТЬ ПО <fields>]
[ИМЕЮЩИЕ <condition>]

[ОБЪЕДИНИТЬ [ВСЕ]
ВЫБРАТЬ ...]

[УПОРЯДОЧИТЬ ПО <fields> [ВОЗР | УБЫВ]]
[АВТОУПОРЯДОЧИВАНИЕ]

[ИТОГИ <aggregate expressions> ПО [ОБЩИЕ] <control points>]

Keywords:

Keyword Meaning
ВЫБРАТЬ SELECT - mandatory, starts the query
РАЗРЕШЕННЫЕ Respect row-level security (RLS). Use by default for safety
РАЗЛИЧНЫЕ DISTINCT - remove duplicate rows
ПЕРВЫЕ N Return only first N rows (1C has no LIMIT keyword - this is the only way)
ИЗ FROM - data sources
ГДЕ WHERE - row filter
СГРУППИРОВАТЬ ПО GROUP BY
ИМЕЮЩИЕ HAVING - group filter
ОБЪЕДИНИТЬ [ВСЕ] UNION [ALL]
УПОРЯДОЧИТЬ ПО ORDER BY. ВОЗР = ASC, УБЫВ = DESC
АВТОУПОРЯДОЧИВАНИЕ Auto-order by presentation (rarely used)
ИТОГИ TOTALS - compute aggregate subtotals

Comments: // single-line only.

Minimal example:

ВЫБРАТЬ Ссылка, Наименование
ИЗ Справочник.Контрагенты
ГДЕ НЕ ПометкаУдаления

Table Names and Sources

Every 1C metadata object has a fixed query-name pattern. Use exact names from get_metadata.

Real tables

Object type Query name pattern Example
Catalog Справочник.<Name> Справочник.Номенклатура
Document Документ.<Name> Документ.РеализацияТоваровУслуг
Document tabular section Документ.<Name>.<Section> Документ.РеализацияТоваровУслуг.Товары
Accumulation register РегистрНакопления.<Name> РегистрНакопления.ОстаткиТоваров
Information register РегистрСведений.<Name> РегистрСведений.КурсыВалют
Accounting register РегистрБухгалтерии.<Name> РегистрБухгалтерии.Хозрасчетный
Chart of accounts ПланСчетов.<Name> ПланСчетов.Хозрасчетный
Chart of characteristic types ПланВидовХарактеристик.<Name> ПланВидовХарактеристик.ВидыСубконто
Calculation register РегистрРасчета.<Name> РегистрРасчета.Начисления
Business process БизнесПроцесс.<Name> БизнесПроцесс.Согласование
Task Задача.<Name> Задача.ЗадачаИсполнителя

Enum values and predefined items

// Enum value (used in conditions, not as a table):
ЗНАЧЕНИЕ(Перечисление.ТипыЦен.Оптовая)

// Predefined catalog item:
ЗНАЧЕНИЕ(Справочник.Валюты.USD)

// Empty reference:
ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)

Virtual tables

Virtual tables are computed on-the-fly from real register data. Always pass filter conditions as virtual table parameters, NOT in WHERE - this is critical for performance.

Accumulation register (Регистр накопления):

// Current balances (no date = latest):
РегистрНакопления.ОстаткиТоваров.Остатки(, Номенклатура = &Ном)

// Balances at specific date:
РегистрНакопления.ОстаткиТоваров.Остатки(&Дата, Склад = &Склад)

// Turnovers for period:
РегистрНакопления.ОстаткиТоваров.Обороты(&НачДата, &КонДата, , Номенклатура = &Ном)

// Balances and turnovers:
РегистрНакопления.ОстаткиТоваров.ОстаткиИОбороты(&НачДата, &КонДата, , , Номенклатура = &Ном)

Information register (Регистр сведений):

// Latest values (slice of last):
РегистрСведений.КурсыВалют.СрезПоследних(&Дата, Валюта = &Валюта)

// Earliest values (slice of first):
РегистрСведений.КурсыВалют.СрезПервых(&Дата, Валюта = &Валюта)

Accounting register (Регистр бухгалтерии):

5 virtual tables: Остатки, Обороты, ОстаткиИОбороты, ОборотыДтКт, ДвиженияССубконто.

Сигнатуры ниже приведены для регистров с корреспонденцией (КорреспондирующиеСчета = Истина, например типовой Хозрасчетный). Для регистров без корреспонденции .ОборотыДтКт и .ДвиженияССубконто отсутствуют, у .Обороты нет УсловиеКорСчета и КорСубконто.

// Balances at date:
РегистрБухгалтерии.Хозрасчетный.Остатки(&Период, Счет = &Счет, , )

// Turnovers for period:
РегистрБухгалтерии.Хозрасчетный.Обороты(&НачДата, &КонДата, Месяц, Счет В (&Счета), , , , )

// Balances and turnovers:
РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(&НачДата, &КонДата, Авто, , Счет = &Счет, , )

// Debit-Credit turnovers (detailed correspondence):
РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт(&НачДата, &КонДата, , , , , , )

// Detailed records with subconto:
РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(&НачДата, &КонДата, , , )

Virtual table parameters (positional order):

Virtual table Parameters
.Остатки() Период, УсловиеСчета, Субконто, Условие
.Обороты() НачалоПериода, КонецПериода, Периодичность, УсловиеСчета, Субконто, Условие, УсловиеКорСчета, КорСубконто
.ОстаткиИОбороты() НачалоПериода, КонецПериода, Периодичность, МетодДополненияПериодов, УсловиеСчета, Субконто, Условие
.ОборотыДтКт() НачалоПериода, КонецПериода, Периодичность, УсловиеСчетаДт, СубконтоДт, УсловиеСчетаКт, СубконтоКт, Условие
.ДвиженияССубконто() НачалоПериода, КонецПериода, Условие, Порядок, Первые

Note: справка платформы (синтакс-помощник) для регистра бухгалтерии часто опускает УсловиеСчета/УсловиеКорСчета/УсловиеСчетаДт/УсловиеСчетаКт. Эти параметры реально существуют и работают (см. ИТС pubqlang) - без них смещается весь позиционный список и Счет = ... попадает в позицию Субконто (тип не совпадет, отбор не сработает).

Key differences from accumulation register:

  • Субконто parameter accepts виды субконто (plan of characteristic types references), NOT values. Filter by subconto values in Условие: Субконто1 = &Контрагент
  • Счет/КорСчет filtering - отдельные параметры УсловиеСчета/УсловиеКорСчета (не в Условие): Счет = &Счет, Счет В ИЕРАРХИИ(&Счет). Для ОборотыДтКт - УсловиеСчетаДт/УсловиеСчетаКт
  • Периодичность values: Авто, Период, Год, Полугодие, Квартал, Месяц, Декада, Неделя, День, Регистратор, Запись
  • МетодДополненияПериодов (ОстаткиИОбороты only): Движения or ДвиженияИГраницыПериода (default)
  • Resources have Дт/Кт (Debit/Credit) suffixes - see table below

Parameter syntax inside virtual tables: Dimension = Value joined by commas. Keep it simple - no subqueries or joins inside parameters.

Accumulation register resource suffixes:

When using virtual tables, resource fields get automatic suffixes:

Virtual table Suffix format Example
.Остатки() <Resource>Остаток КоличествоОстаток
.Обороты() <Resource>Оборот КоличествоОборот
.ОстаткиИОбороты() <Resource>НачальныйОстаток КоличествоНачальныйОстаток
.ОстаткиИОбороты() <Resource>Приход КоличествоПриход
.ОстаткиИОбороты() <Resource>Расход КоличествоРасход
.ОстаткиИОбороты() <Resource>Оборот КоличествоОборот
.ОстаткиИОбороты() <Resource>КонечныйОстаток КоличествоКонечныйОстаток
// Example - turnovers with all suffixes:
ВЫБРАТЬ
    Об.Номенклатура,
    Об.КоличествоПриход,
    Об.КоличествоРасход,
    Об.КоличествоОборот,
    Об.КоличествоНачальныйОстаток,
    Об.КоличествоКонечныйОстаток
ИЗ
    РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&Нач, &Кон, , , ) КАК Об

Accounting register resource suffixes:

Unlike accumulation register, accounting resources have Дт/Кт (Debit/Credit) variants:

Virtual table Suffix format Example
.Остатки() <Resource>Остаток СуммаОстаток
.Остатки() <Resource>ОстатокДт/Кт СуммаОстатокДт
.Остатки() <Resource>РазвернутыйОстатокДт/Кт СуммаРазвернутыйОстатокДт
.Обороты() <Resource>Оборот СуммаОборот
.Обороты() <Resource>ОборотДт/Кт СуммаОборотДт
.Обороты() <Resource>КорОборотДт/Кт СуммаКорОборотДт
.ОстаткиИОбороты() <Resource>НачальныйОстатокДт/Кт СуммаНачальныйОстатокДт
.ОстаткиИОбороты() <Resource>ОборотДт/Кт СуммаОборотДт
.ОстаткиИОбороты() <Resource>КонечныйОстатокДт/Кт СуммаКонечныйОстатокДт
.ОстаткиИОбороты() <Resource>НачальныйРазвернутыйОстатокДт/Кт СуммаНачальныйРазвернутыйОстатокДт
.ОстаткиИОбороты() <Resource>КонечныйРазвернутыйОстатокДт/Кт СуммаКонечныйРазвернутыйОстатокДт

Suffixes without Дт/Кт (e.g. СуммаОстаток, СуммаОборот) are for balanced resources.

// Example - accounting register balances and turnovers:
ВЫБРАТЬ
    Об.Счет,
    Об.Субконто1,
    Об.СуммаНачальныйОстатокДт КАК НачОстДт,
    Об.СуммаОборотДт,
    Об.СуммаОборотКт,
    Об.СуммаКонечныйОстатокДт КАК КонОстДт
ИЗ
    РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(
        &НачДата, &КонДата, Авто, , Счет = &Счет, , ) КАК Об

Table aliases

Справочник.Номенклатура КАК Товары

Always assign informative aliases - they must be understandable without context:

  • No single-letter (Р, Т, С) or cryptic abbreviations (ВТДок, ДокГР)
  • For long table names, shorten meaningfully: РасчетыНДФЛ, РезидентствоФЛ, ВедомостиЗП
  • For temp tables as sources, reuse the temp table name or shorten it meaningfully
// Bad:
РегистрНакопления.РасчетыНалогоплательщиковСБюджетомПоНДФЛ КАК Р

// Good:
РегистрНакопления.РасчетыНалогоплательщиковСБюджетомПоНДФЛ КАК РасчетыНДФЛ

// Bad:
ВТДокументОснованияДляУвольнений КАК ВТУвольнения

// Good:
ВТДокументОснованияДляУвольнений КАК ДокументыУвольнений

Aliases are required when self-joining or using the same table twice.

Hierarchical catalogs

Catalogs with hierarchy support nested groups:

// Direct children (one level) - preferred:
ВЫБРАТЬ Наименование
ИЗ Справочник.Номенклатура
ГДЕ Родитель = &Родитель
// params: {"Родитель": {"_objectRef": true, "УникальныйИдентификатор": "...",
//                        "ТипОбъекта": "СправочникСсылка.Номенклатура", "Представление": "..."}}

// Or by name:
ГДЕ Родитель.Наименование = "Бытовая техника"

// All items in group and subgroups - preferred:
ВЫБРАТЬ Наименование
ИЗ Справочник.Номенклатура
ГДЕ Ссылка В ИЕРАРХИИ (&Группа)
// params: {"Группа": {"_objectRef": true, "УникальныйИдентификатор": "...",
//                      "ТипОбъекта": "СправочникСсылка.Номенклатура", "Представление": "..."}}

// Or by name:
ГДЕ Ссылка В ИЕРАРХИИ (
    ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура
    ГДЕ Наименование = "Бытовая техника"
)

// Only leaf items (not groups):
ГДЕ ЭтоГруппа = ЛОЖЬ

// Only groups:
ГДЕ ЭтоГруппа = ИСТИНА

Rules:

  • Родитель = &Родитель - direct children only (one level)
  • Ссылка В ИЕРАРХИИ (&Группа) - all nested levels
  • ЭтоГруппа - ИСТИНА = groups only, ЛОЖЬ = leaf items only
  • AVOID: В ИЕРАРХИИ (ПустаяСсылка) - very slow

Field Selection

  • * selects all real fields (virtual fields are NOT included)
  • Aliases: <expression> КАК <Alias> - aliases must be unique within the query
  • Access nested fields with dot notation: Товары.Номенклатура.Наименование

CRITICAL: Compound-type field dereferencing

When a field can reference multiple table types (compound/composite type), accessing it through dots creates implicit JOINs to ALL possible target tables. This severely degrades performance.

Always narrow the type with ВЫРАЗИТЬ:

// BAD - joins to every possible Регистратор table:
ВЫБРАТЬ Регистратор.Номер ИЗ РегистрНакопления.ОстаткиТоваров

// GOOD - single join:
ВЫБРАТЬ ВЫРАЗИТЬ(Регистратор КАК Документ.РеализацияТоваровУслуг).Номер
ИЗ РегистрНакопления.ОстаткиТоваров
ГДЕ Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг

NULL handling

  • Use ЕСТЬNULL(field, default) for fields that may be NULL (e.g., from LEFT JOIN)
  • Check NULL with ЕСТЬ NULL / НЕ ЕСТЬ NULL (not = NULL)

Empty table for UNION

When unioning queries with different nested table structures:

ПУСТАЯТАБЛИЦА.(Номенклатура, Количество, Цена)

WHERE and HAVING

Operators

Operator 1C syntax Notes
Equals =
Not equals <>
Comparison <, >, <=, >=
AND И
OR ИЛИ Avoid in WHERE - see caveats
NOT НЕ
Range МЕЖДУ X И Y Inclusive both ends
In list В (val1, val2, ...)
In subquery В (ВЫБРАТЬ ...)
NULL check ЕСТЬ NULL / НЕ ЕСТЬ NULL Never use = NULL
Type check ССЫЛКА Документ.Реализация... Checks reference type
Pattern ПОДОБНО "шаблон" % any string, _ one char
CASE ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ Only in non-indexed conditions

Operator precedence: НЕ > И > ИЛИ. Use parentheses () for explicit priority.

Key rules

  • ИЛИ (OR) degrades index usage. Replace with В (...) where possible, or split into ОБЪЕДИНИТЬ ВСЕ
  • ВЫБОР (CASE) in WHERE: Only in additional (non-indexed) conditions
  • String comparison: Case-insensitive, ignores trailing spaces
  • Arithmetic in WHERE: Only in additional conditions (prevents index use)
  • Pattern ПОДОБНО: Must not start with % or _ if in indexed condition

For index-aware optimization strategy, see optimization-and-pitfalls.md.

Joins

ИЗ Документ.РеализацияТоваровУслуг КАК Док
    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Конт
    ПО Док.Контрагент = Конт.Ссылка
Type 1C syntax
Inner ВНУТРЕННЕЕ СОЕДИНЕНИЕ ... ПО
Left outer ЛЕВОЕ [ВНЕШНЕЕ] СОЕДИНЕНИЕ ... ПО
Right outer ПРАВОЕ [ВНЕШНЕЕ] СОЕДИНЕНИЕ ... ПО
Full outer ПОЛНОЕ [ВНЕШНЕЕ] СОЕДИНЕНИЕ ... ПО

Rules:

  • NEVER use nested joins (join of a subquery that itself contains joins). Replace with temporary tables or sequential joins
  • For LEFT JOIN: index the right table's join fields
  • For INNER JOIN: index the larger table's join fields

Grouping and Totals

GROUP BY

ВЫБРАТЬ
    Контрагент,
    СУММА(СуммаДокумента) КАК Итого,
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Ссылка) КАК КолДок
ИЗ Документ.РеализацияТоваровУслуг
СГРУППИРОВАТЬ ПО Контрагент
ИМЕЮЩИЕ СУММА(СуммаДокумента) > 1000

Aggregate functions: СУММА (SUM), СРЕДНЕЕ (AVG), МИНИМУМ (MIN), МАКСИМУМ (MAX), КОЛИЧЕСТВО (COUNT), КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...) (COUNT DISTINCT).

Every non-aggregated field in SELECT must appear in GROUP BY.

TOTALS (brief)

ИТОГИ СУММА(СуммаДокумента) ПО ОБЩИЕ, Контрагент

Computes subtotal rows interleaved with detail rows. For full syntax (ПЕРИОДАМИ, hierarchical control points, grouping sets), see query-syntax-reference.md.

Temporary Tables

Use temporary tables to break complex queries into steps, avoid nested subqueries, and improve performance.

// Step 1: collect items into temp table
ВЫБРАТЬ Ссылка КАК Номенклатура
ПОМЕСТИТЬ ВТ_Товары
ИЗ Справочник.Номенклатура
ГДЕ Наименование ПОДОБНО &Маска
ИНДЕКСИРОВАТЬ ПО Номенклатура
;
// Step 2: get balances for those items
ВЫБРАТЬ
    Ост.Номенклатура КАК Номенклатура,
    Ост.КоличествоОстаток КАК Остаток
ИЗ РегистрНакопления.ОстаткиТоваров.Остатки(
        ,
        Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ ВТ_Товары)
    ) КАК Ост

Rules:

  • Separate queries in a batch with ;
  • ПОМЕСТИТЬ <Name> creates the temp table (place right after SELECT fields, before ИЗ)
  • ИНДЕКСИРОВАТЬ ПО <field> - add after the query for temp tables with >1000 rows used in joins or В subqueries
  • Minimize data volume and field count in temp tables
  • NEVER create/drop temp tables in a loop
  • Prefer temp tables over nested subqueries in JOIN conditions

Parameters

Parameters are external values passed into the query. Syntax: &ParameterName.

ВЫБРАТЬ * ИЗ Справочник.Контрагенты ГДЕ Наименование ПОДОБНО &Маска

Passed via execute_query params: {"Маска": "%Рога%"}.

Rules:

  • Always use parameters for external values - never concatenate strings into query text
  • Enum values: use ЗНАЧЕНИЕ() in query text, not as parameter: ГДЕ Тип = ЗНАЧЕНИЕ(Перечисление.ТипыЦен.Оптовая)
  • Date format in params: ISO 8601 ("2024-01-15" or "2024-01-15T10:30:00")
  • Boolean: ИСТИНА / ЛОЖЬ in query text, or pass true/false as parameter

Comparing Reference Fields

When comparing reference fields (link-type attributes), pass the reference as a parameter:

// GOOD - reference passed as parameter from previous query result:
ВЫБРАТЬ * ИЗ Документ.ПродажаТоваров
ГДЕ Контрагент = &Контрагент
// params: {"Контрагент": {"_objectRef": true, "УникальныйИдентификатор": "...",
//                           "ТипОбъекта": "СправочникСсылка.Контрагенты", "Представление": "..."}}

// ALSO GOOD - compare via primitive attribute:
ГДЕ Контрагент.Наименование = "ООО Ромашка"
ГДЕ Контрагент.Код = "000001"

// AVOID - direct comparison with another table's reference:
ГДЕ Документ.Контрагент = Справочник.Контрагенты.Ссылка

Rules:

  • First choice: pass reference object from previous query result as &Parameter
  • Fallback: compare via primitive fields (Наименование, Код, etc.)
  • Never compare reference fields directly from different sources

Common Patterns

1. Find by name (fuzzy):

ВЫБРАТЬ Ссылка, Наименование ИЗ Справочник.Контрагенты ГДЕ Наименование ПОДОБНО &Маска
// params: {"Маска": "%рога%"}

2. Latest N documents:

ВЫБРАТЬ ПЕРВЫЕ 10 Ссылка, Дата, Номер, СуммаДокумента
ИЗ Документ.РеализацияТоваровУслуг
УПОРЯДОЧИТЬ ПО Дата УБЫВ

3. Current balances (virtual table, no date = now):

ВЫБРАТЬ Номенклатура, КоличествоОстаток
ИЗ РегистрНакопления.ОстаткиТоваров.Остатки(, Номенклатура = &Ном) КАК Ост

4. Latest register slice:

ВЫБРАТЬ Валюта, Курс ИЗ РегистрСведений.КурсыВалют.СрезПоследних(&Дата,) КАК Курсы

5. Count by group:

ВЫБРАТЬ Контрагент, КОЛИЧЕСТВО(*) КАК Кол
ИЗ Документ.РеализацияТоваровУслуг
СГРУППИРОВАТЬ ПО Контрагент
УПОРЯДОЧИТЬ ПО Кол УБЫВ

6. Check existence:

ВЫБРАТЬ ПЕРВЫЕ 1 Ссылка ИЗ Справочник.Контрагенты ГДЕ ИНН = &ИНН

7. Exclude items marked for deletion:

ГДЕ НЕ ПометкаУдаления

8. Explore table structure (zero-row query with schema):

ВЫБРАТЬ ПЕРВЫЕ 0 * ИЗ Справочник.Контрагенты
// use with include_schema: true in execute_query

References

  • Query syntax reference - ВЫБОР (CASE), ОБЪЕДИНИТЬ, УПОРЯДОЧИТЬ ПО, ИТОГИ, ПОДОБНО patterns, ССЫЛКА, subqueries
  • Optimization and caveats - index strategy, ИЛИ alternatives, compound types, virtual table rules, RLS impact
  • Functions and expressions - aggregate, date, string, type, math functions and type casting with ВЫРАЗИТЬ
Files (claude-code-skills-1c)
  • evals
    • evals.json 5.3 KB
      {
        "skill_name": "composing-1c-queries",
        "evals": [
          {
            "id": "accumulation-balances",
            "prompt": "Составь запрос для получения остатков товаров на складах из регистра накопления ТоварыНаСкладах (виртуальная таблица Остатки). Нужны поля Номенклатура, Склад и остаток количества. Фильтр по параметру &Дата.",
            "expected_output": "Корректный запрос к виртуальной таблице РегистрНакопления.ТоварыНаСкладах.Остатки с параметром даты, полями с псевдонимами КАК, информативными псевдонимами таблиц.",
            "expectations": [
              "Запрос использует ключевое слово ВЫБРАТЬ и ИЗ",
              "Виртуальная таблица вызвана с параметром даты: .Остатки(&Дата",
              "Каждое поле имеет псевдоним через КАК",
              "Псевдоним таблицы информативный (не однобуквенный)",
              "Параметры используют префикс & (например &Дата)",
              "Запрос не содержит конкатенацию строк в тексте запроса"
            ],
            "expect": [
              "ВЫБРАТЬ",
              "РегистрНакопления\\.ТоварыНаСкладах\\.Остатки",
              "\\bКАК\\b"
            ],
            "forbid": [
              "\\bSELECT\\b",
              "\\bFROM\\b"
            ],
            "should_activate": true
          },
          {
            "id": "documents-by-period",
            "prompt": "Напиши запрос для поиска всех проведённых документов ПоступлениеТоваровУслуг за период с &НачДата по &КонДата, у которых контрагент равен &Контрагент. Нужны: ссылка на документ, дата, номер, сумма документа.",
            "expected_output": "Запрос к таблице Документ.ПоступлениеТоваровУслуг с условием по дате, контрагенту и признаку проведения, с псевдонимами полей.",
            "expectations": [
              "Запрос обращается к таблице Документ.ПоступлениеТоваровУслуг",
              "Условие ГДЕ включает фильтр по периоду через &НачДата и &КонДата",
              "Условие ГДЕ включает фильтр по &Контрагент",
              "Присутствует условие на проведённость (Проведён = ИСТИНА или аналог)",
              "Поля Ссылка, Дата, Номер имеют псевдонимы через КАК"
            ],
            "expect": [
              "ВЫБРАТЬ",
              "Документ\\.ПоступлениеТоваровУслуг",
              "&НачДата",
              "&КонДата",
              "Проведен"
            ],
            "forbid": [
              "\\bSELECT\\b",
              "\\bWHERE\\b"
            ],
            "should_activate": true
          },
          {
            "id": "temp-table-join",
            "prompt": "Составь запрос с временными таблицами: сначала отобрать номенклатуру из справочника Номенклатура где пометка удаления = Ложь, затем соединить с остатками из РегистрНакопления.ТоварыНаСкладах.Остатки. Итоговый запрос должен вернуть Номенклатура, Наименование, КоличествоОстаток.",
            "expected_output": "Пакетный запрос: первый запрос создаёт временную таблицу с ПОМЕСТИТЬ, индексирует её, второй запрос соединяет с виртуальной таблицей остатков. Промежуточная переменная для результата запроса.",
            "expectations": [
              "Первый запрос использует ПОМЕСТИТЬ для создания временной таблицы",
              "Временная таблица имеет ИНДЕКСИРОВАТЬ ПО для поля соединения",
              "Второй запрос использует ЛЕВОЕ СОЕДИНЕНИЕ или ВНУТРЕННЕЕ СОЕДИНЕНИЕ с временной таблицей",
              "Запросы разделены точкой с запятой (;)",
              "Условие на пометку удаления присутствует в первом запросе",
              "Все поля имеют псевдонимы через КАК"
            ],
            "expect": [
              "ПОМЕСТИТЬ",
              "Справочник\\.Номенклатура",
              "СОЕДИНЕНИЕ|ПО\\s"
            ],
            "forbid": [
              "\\bSELECT\\b",
              "\\bJOIN\\b"
            ],
            "should_activate": true
          }
        ]
      }
      
  • references
    • functions-and-expressions.md 8.7 KB
      # Functions and Expressions
      
      Complete reference of functions and expression syntax available in 1C query language.
      
      ## Contents
      
      - [Type casting (ВЫРАЗИТЬ)](#type-casting-выразить)
      - [Aggregate functions](#aggregate-functions)
      - [Date and time functions](#date-and-time-functions)
      - [String functions](#string-functions)
      - [Type functions](#type-functions)
      - [Logical and NULL functions](#logical-and-null-functions)
      - [Math functions](#math-functions)
      - [Trigonometric functions](#trigonometric-functions)
      - [Special functions](#special-functions)
      - [Arithmetic operators](#arithmetic-operators)
      - [Constants and literals](#constants-and-literals)
      
      ---
      
      ## Type Casting (ВЫРАЗИТЬ)
      
      Explicitly converts a value to a specific type. **Essential for compound-type fields.**
      
      ```
      ВЫРАЗИТЬ(<expression> КАК <type>)
      ```
      
      Examples:
      ```
      // Narrow compound reference to specific type:
      ВЫРАЗИТЬ(Регистратор КАК Документ.РеализацияТоваровУслуг)
      
      // Cast number to specific precision:
      ВЫРАЗИТЬ(Сумма КАК ЧИСЛО(15, 2))
      
      // Cast to string:
      ВЫРАЗИТЬ(Код КАК СТРОКА(10))
      
      // Cast to boolean:
      ВЫРАЗИТЬ(Значение КАК БУЛЕВО)
      
      // Cast to date:
      ВЫРАЗИТЬ(Значение КАК ДАТА)
      ```
      
      Primitive types for casting: `ЧИСЛО(<length>, <precision>)`, `СТРОКА(<length>)`, `БУЛЕВО`, `ДАТА`.
      
      ---
      
      ## Aggregate Functions
      
      Used with `СГРУППИРОВАТЬ ПО`, `ИМЕЮЩИЕ`, `ИТОГИ`, and `УПОРЯДОЧИТЬ ПО`.
      
      | Function | Description | Example |
      |----------|-------------|---------|
      | `СУММА(<field>)` | Sum | `СУММА(Количество)` |
      | `СРЕДНЕЕ(<field>)` | Average | `СРЕДНЕЕ(Цена)` |
      | `МИНИМУМ(<field>)` | Minimum value | `МИНИМУМ(Дата)` |
      | `МАКСИМУМ(<field>)` | Maximum value | `МАКСИМУМ(Дата)` |
      | `КОЛИЧЕСТВО(*)` | Count all rows | `КОЛИЧЕСТВО(*)` |
      | `КОЛИЧЕСТВО(<field>)` | Count non-NULL values | `КОЛИЧЕСТВО(Контрагент)` |
      | `КОЛИЧЕСТВО(РАЗЛИЧНЫЕ <field>)` | Count distinct values | `КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Контрагент)` |
      
      **Rule:** Do not use grouping fields inside aggregate functions (except nested table fields).
      
      ---
      
      ## Date and Time Functions
      
      ### Component extraction
      
      | Function | Returns | Example |
      |----------|---------|---------|
      | `ГОД(<date>)` | Year | `ГОД(Дата)` → 2024 |
      | `КВАРТАЛ(<date>)` | Quarter (1-4) | `КВАРТАЛ(Дата)` → 1 |
      | `МЕСЯЦ(<date>)` | Month (1-12) | `МЕСЯЦ(Дата)` → 3 |
      | `ДЕНЬГОДА(<date>)` | Day of year (1-366) | `ДЕНЬГОДА(Дата)` |
      | `ДЕНЬ(<date>)` | Day of month (1-31) | `ДЕНЬ(Дата)` → 15 |
      | `ДЕНЬНЕДЕЛИ(<date>)` | Day of week (1=Mon..7=Sun) | `ДЕНЬНЕДЕЛИ(Дата)` |
      | `ЧАС(<date>)` | Hour (0-23) | `ЧАС(Дата)` |
      | `МИНУТА(<date>)` | Minute (0-59) | `МИНУТА(Дата)` |
      | `СЕКУНДА(<date>)` | Second (0-59) | `СЕКУНДА(Дата)` |
      
      ### Period boundaries
      
      | Function | Description |
      |----------|-------------|
      | `НАЧАЛОПЕРИОДА(<date>, <period>)` | Start of period. `<period>`: МИНУТА, ЧАС, ДЕНЬ, НЕДЕЛЯ, МЕСЯЦ, КВАРТАЛ, ГОД, ДЕКАДА, ПОЛУГОДИЕ |
      | `КОНЕЦПЕРИОДА(<date>, <period>)` | End of period (same period options) |
      
      ```
      НАЧАЛОПЕРИОДА(Дата, МЕСЯЦ)    // first day of month
      КОНЕЦПЕРИОДА(Дата, КВАРТАЛ)    // last moment of quarter
      ```
      
      ### Date arithmetic
      
      | Function | Description |
      |----------|-------------|
      | `ДОБАВИТЬКДАТЕ(<date>, <period>, <count>)` | Add N periods to date |
      | `РАЗНОСТЬДАТ(<date1>, <date2>, <period>)` | Difference between dates in periods |
      
      ```
      ДОБАВИТЬКДАТЕ(Дата, МЕСЯЦ, 3)         // add 3 months
      ДОБАВИТЬКДАТЕ(Дата, ДЕНЬ, -7)          // subtract 7 days
      РАЗНОСТЬДАТ(ДатаНач, ДатаКон, ДЕНЬ)   // days between dates
      ```
      
      Period options: `СЕКУНДА`, `МИНУТА`, `ЧАС`, `ДЕНЬ`, `МЕСЯЦ`, `КВАРТАЛ`, `ГОД`.
      
      ---
      
      ## String Functions
      
      | Function | Description | Example |
      |----------|-------------|---------|
      | `ПОДСТРОКА(<str>, <start>, <length>)` | Substring (1-based) | `ПОДСТРОКА(Код, 1, 3)` |
      | `ДЛИНАСТРОКИ(<str>)` | String length | `ДЛИНАСТРОКИ(Наименование)` |
      | `ЛЕВ(<str>, <n>)` | Left N characters | `ЛЕВ(Код, 5)` |
      | `ПРАВ(<str>, <n>)` | Right N characters | `ПРАВ(Код, 3)` |
      | `СТРЗАМЕНИТЬ(<str>, <find>, <replace>)` | Replace substring | `СТРЗАМЕНИТЬ(Имя, " ", "_")` |
      | `СОКРЛ(<str>)` | Trim leading spaces | `СОКРЛ(Код)` |
      | `СОКРП(<str>)` | Trim trailing spaces | `СОКРП(Код)` |
      | `СОКРЛП(<str>)` | Trim both sides | `СОКРЛП(Код)` |
      | `ВРЕГ(<str>)` | Uppercase | `ВРЕГ(Наименование)` |
      | `НРЕГ(<str>)` | Lowercase | `НРЕГ(Наименование)` |
      
      **Note:** `ПОДСТРОКА` in WHERE main condition prevents index usage. Use only in additional conditions.
      
      ---
      
      ## Type Functions
      
      | Function | Description | Example |
      |----------|-------------|---------|
      | `ТИПЗНАЧЕНИЯ(<expr>)` | Returns the type of a value | `ТИПЗНАЧЕНИЯ(Ссылка)` |
      | `ТИП(<type_name>)` | Returns a type object for comparison | `ТИП("Справочник.Контрагенты")` |
      | `ССЫЛКА` | Type check operator for references | `Рег ССЫЛКА Документ.Реализация` |
      | `ПРЕДСТАВЛЕНИЕ(<expr>)` | Human-readable string of a reference | `ПРЕДСТАВЛЕНИЕ(Контрагент)` |
      | `УНИКАЛЬНЫЙИДЕНТИФИКАТОР(<ref>)` | UUID of a reference as string | `УНИКАЛЬНЫЙИДЕНТИФИКАТОР(Ссылка)` |
      
      ```
      // Filter by value type:
      ГДЕ ТИПЗНАЧЕНИЯ(Субконто1) = ТИП("Справочник.Контрагенты")
      ```
      
      ---
      
      ## Logical and NULL Functions
      
      | Function | Description |
      |----------|-------------|
      | `ЕСТЬNULL(<expr>, <default>)` | Returns `<default>` if `<expr>` is NULL (like SQL COALESCE for two args) |
      
      ```
      ЕСТЬNULL(Ост.КоличествоОстаток, 0)
      ```
      
      **ВЫБОР (CASE):** See [query-syntax-reference.md](query-syntax-reference.md#выбор-case).
      
      ---
      
      ## Math Functions
      
      | Function | Description |
      |----------|-------------|
      | `ОКР(<number>, <precision>)` | Round to N decimal places |
      | `ЦЕЛ(<number>)` | Truncate to integer (floor toward zero) |
      
      ```
      ОКР(Сумма / Количество, 2)   // round to 2 decimals
      ЦЕЛ(Сумма / 100)             // integer part
      ```
      
      **Arithmetic precision:** At least 8 decimal places. Results may vary slightly across DBMS.
      
      ---
      
      ## Trigonometric Functions
      
      Standard math functions - same semantics as in most languages.
      
      | Function | Description |
      |----------|-------------|
      | `SIN(<x>)` | Sine (radians) |
      | `COS(<x>)` | Cosine |
      | `TAN(<x>)` | Tangent |
      | `ASIN(<x>)` | Arcsine |
      | `ACOS(<x>)` | Arccosine |
      | `ATAN(<x>)` | Arctangent |
      
      ---
      
      ## Special Functions
      
      | Function | Description |
      |----------|-------------|
      | `EXP(<x>)` | e^x |
      | `LOG(<x>)` | Natural logarithm |
      | `LOG10(<x>)` | Base-10 logarithm |
      | `POW(<base>, <exp>)` | Power |
      | `SQRT(<x>)` | Square root |
      | `АВТОНОМЕРЗАПИСИ()` | Auto row number in result |
      | `РАЗМЕРХРАНИМЫХДАННЫХ(<field>)` | Storage size of a field in bytes |
      | `СГРУППИРОВАНОПО(<field>)` | TRUE if current row was grouped by this field (for grouping sets) |
      
      ---
      
      ## Arithmetic Operators
      
      `+`, `-`, `*`, `/` - standard arithmetic. Precision: at least 8 decimal places.
      
      **In WHERE:** Only use in additional conditions (prevents index use in main condition).
      
      ---
      
      ## Constants and Literals
      
      | Type | Syntax | Example |
      |------|--------|---------|
      | Boolean | `ИСТИНА` / `ЛОЖЬ` | `ГДЕ Проведен = ИСТИНА` |
      | Number | Decimal literal | `1000`, `3.14` |
      | String | Double quotes | `"Текст"` |
      | String with quotes | Escape `"` by doubling | `"Компания ""Рога и Копыта"""` |
      | Date | `ДАТАВРЕМЯ(<Y>, <M>, <D> [, <H>, <Min>, <S>])` | `ДАТАВРЕМЯ(2024, 1, 15)` |
      | NULL | `NULL` | `ЕСТЬNULL(X, 0)` |
      | Undefined | `НЕОПРЕДЕЛЕНО` | |
      | Enum/predefined | `ЗНАЧЕНИЕ(...)` | `ЗНАЧЕНИЕ(Перечисление.Типы.Оптовая)` |
      | Empty reference | `ЗНАЧЕНИЕ(Справочник.X.ПустаяСсылка)` | |
      
      **Parameters:** `&Name` - external values passed to query. Always prefer parameters over string concatenation.
      
    • optimization-and-pitfalls.md 11 KB
      # Optimization and Caveats
      
      1C-specific query optimization rules. These differ from generic SQL and are critical for production performance.
      
      ## Contents
      
      - [Index-aware filtering (main vs additional conditions)](#index-aware-filtering)
      - [ИЛИ (OR) performance trap](#или-or-performance-trap)
      - [Compound-type dereferencing](#compound-type-dereferencing)
      - [Virtual table parameters](#virtual-table-parameters)
      - [Accounting register virtual table specifics](#accounting-register-virtual-table-specifics)
      - [Nested joins prohibition](#nested-joins-prohibition)
      - [Temporary table best practices](#temporary-table-best-practices)
      - [RLS impact](#rls-impact)
      - [Subquery restrictions](#subquery-restrictions)
      - [DBMS portability](#dbms-portability)
      
      ---
      
      ## Index-Aware Filtering
      
      1C query optimizer splits WHERE conditions into two categories:
      
      ### Main condition (основное условие)
      - **Used for index lookup** - determines which index range to scan
      - Must be the most restrictive part of the filter
      - Allowed operators: `=`, `>`, `<`, `>=`, `<=`, `ПОДОБНО`, `МЕЖДУ`, `В`
      - Combined with other main conditions using `И` only
      - **Forbidden in main condition:** `ИЛИ`, `ВЫБОР`, arithmetic expressions, function calls (like `ПОДСТРОКА`), `НЕ`
      
      ### Additional condition (дополнительное условие)
      - Applied **after** index scan - filters rows one by one
      - Can use any operators, `ИЛИ`, `ВЫБОР`, arithmetic, functions
      - Combined with the main condition using `И`
      
      ### Strategy
      Structure your WHERE as: `<main_condition> И <additional_condition>`
      
      ```
      // Main: indexed field with =
      // Additional: complex logic
      ГДЕ Организация = &Орг                              // main (indexed)
          И (Сумма > 1000 ИЛИ ПометкаУдаления = ИСТИНА)   // additional
      ```
      
      If a query is slow, check if conditions prevent index use. Fix by:
      1. Using `ВЫРАЗИТЬ` to narrow compound types
      2. Moving complex logic to additional condition
      3. Rewriting with temporary tables
      
      ---
      
      ## ИЛИ (OR) Performance Trap
      
      `ИЛИ` in the main condition **prevents index use** on all fields involved.
      
      **Allowed only when:**
      - Applied to the **last or only** field of an index
      - AND can be replaced with `В (...)`:
      
      ```
      // BAD - breaks index on both Контрагент and Организация:
      ГДЕ Контрагент = &К1 ИЛИ Организация = &Орг
      
      // GOOD - use В instead:
      ГДЕ Контрагент В (&К1, &К2, &К3)
      
      // GOOD - split into UNION ALL:
      ВЫБРАТЬ ... ГДЕ Контрагент = &К1
      ОБЪЕДИНИТЬ ВСЕ
      ВЫБРАТЬ ... ГДЕ Организация = &Орг
      ```
      
      When replacing `ИЛИ` with `ОБЪЕДИНИТЬ ВСЕ`, verify that the result is equivalent (no missing/duplicate rows).
      
      ---
      
      ## Compound-Type Dereferencing
      
      When a field has a composite reference type (can point to multiple tables), accessing sub-fields through dots creates implicit JOINs to **every** possible target table.
      
      **Impact:**
      - Query complexity explodes (many extra joins)
      - Performance degrades severely, especially with RLS
      - Behavior varies across DBMS
      
      **Solutions:**
      
      1. **ВЫРАЗИТЬ (CAST):** Narrow to specific type before dereferencing:
         ```
         ВЫРАЗИТЬ(Регистратор КАК Документ.Реализация).Номер
         ```
      
      2. **ССЫЛКА + ВЫБОР:** Handle multiple types explicitly:
         ```
         ВЫБОР
             КОГДА Рег ССЫЛКА Документ.Реализация
                 ТОГДА ВЫРАЗИТЬ(Рег КАК Документ.Реализация).Контрагент
             КОГДА Рег ССЫЛКА Документ.Поступление
                 ТОГДА ВЫРАЗИТЬ(Рег КАК Документ.Поступление).Контрагент
         КОНЕЦ
         ```
      
      3. **Temporary tables:** Pre-filter by type, then join:
         ```
         ВЫБРАТЬ Регистратор КАК Док ПОМЕСТИТЬ ВТ_Реализации
         ИЗ РегистрНакопления.Товары
         ГДЕ Регистратор ССЫЛКА Документ.Реализация;
      
         ВЫБРАТЬ ВЫРАЗИТЬ(ВТ.Док КАК Документ.Реализация).Контрагент
         ИЗ ВТ_Реализации КАК ВТ
         ```
      
      4. **Denormalization:** For frequently accessed related data, add a dedicated field to the source table (configuration-level change).
      
      ---
      
      ## Virtual Table Parameters
      
      Virtual tables (Остатки, Обороты, СрезПоследних, etc.) accept parameters that act as **pre-filters** at the storage engine level.
      
      **CRITICAL: Always pass conditions into virtual table parameters, NOT into WHERE.**
      
      ```
      // BAD - full table scan, then filter:
      ВЫБРАТЬ * ИЗ РегистрНакопления.Товары.Остатки() КАК Ост
      ГДЕ Ост.Склад = &Склад
      
      // GOOD - pre-filtered at storage level:
      ВЫБРАТЬ * ИЗ РегистрНакопления.Товары.Остатки(, Склад = &Склад) КАК Ост
      ```
      
      **Parameter rules:**
      - Use simple expressions only: `Dimension = Value`
      - Multiple conditions separated by commas (implicit AND)
      - NO subqueries inside parameters (use temp table + `В (ВЫБРАТЬ ... ИЗ ВТ)` pattern)
      - NO joins inside parameters
      - For Остатки without date parameter - returns current (latest) balances
      
      ---
      
      ## Accounting Register Virtual Table Specifics
      
      Accounting register virtual tables have different parameter semantics from accumulation registers.
      
      ### Субконто parameter vs Условие
      
      The `Субконто` parameter accepts виды субконто references (types from plan of characteristic types), NOT values. To filter by subconto values, use the `Условие` parameter:
      
      ```
      // BAD - subconto VALUE in Субконто parameter position:
      .Остатки(&Период, , &Контрагент, )
      
      // GOOD - виды субконто in Субконто (parameter 3), VALUE in Условие (parameter 4):
      .Остатки(&Период, , &ВидыСубконто, Субконто1 = &Контрагент)
      ```
      
      Параметры `.Остатки()` (4): Период, УсловиеСчета, Субконто, Условие. Не путать с регистром накопления, где у `.Остатки()` другая сигнатура.
      
      ### Счет conditions in УсловиеСчета, not WHERE
      
      ```
      // BAD - full table scan, then filter:
      ВЫБРАТЬ * ИЗ РегистрБухгалтерии.Хозрасчетный.Остатки() КАК Ост
      ГДЕ Ост.Счет = &Счет
      
      // GOOD - pre-filtered at storage level via УсловиеСчета (parameter 2):
      ВЫБРАТЬ * ИЗ РегистрБухгалтерии.Хозрасчетный.Остатки(, Счет = &Счет, , ) КАК Ост
      ```
      
      Use `Счет В ИЕРАРХИИ(&Счет)` to include all sub-accounts of a parent account.
      
      ### Parameter distribution across virtual tables
      
      Each virtual table has its own parameter set. Do not mix them. Параметры по счету (`УсловиеСчета`/`УсловиеКорСчета`/`УсловиеСчетаДт`/`УсловиеСчетаКт`) - отдельные позиционные параметры, не часть `Условие`:
      
      - `Остатки` - 4 параметра, `УсловиеСчета` на позиции 2
      - `Обороты` - 8 параметров (`УсловиеСчета` на 4, `УсловиеКорСчета` на 7, `КорСубконто` на 8)
      - `ОстаткиИОбороты` - 7 параметров, есть `МетодДополненияПериодов` (4) и `УсловиеСчета` (5)
      - `ОборотыДтКт` - 8 параметров с раздельными `УсловиеСчетаДт`/`СубконтоДт` и `УсловиеСчетаКт`/`СубконтоКт`
      - `ДвиженияССубконто` - 5 параметров, отдельного `УсловиеСчета` нет - фильтр по счету идет через `Условие` (3-й параметр)
      
      See the parameter table in the main skill file for exact positional order.
      
      ---
      
      ## Nested Joins Prohibition
      
      **Never nest joins** - i.e., do not join to a subquery that itself contains joins.
      
      ```
      // BAD - nested join:
      ЛЕВОЕ СОЕДИНЕНИЕ (
          ВЫБРАТЬ ... ИЗ Т1 ВНУТРЕННЕЕ СОЕДИНЕНИЕ Т2 ПО ...
      ) КАК Подзапрос
      ПО ...
      
      // GOOD - use temp table:
      ВЫБРАТЬ ... ПОМЕСТИТЬ ВТ ИЗ Т1 ВНУТРЕННЕЕ СОЕДИНЕНИЕ Т2 ПО ...;
      ... ЛЕВОЕ СОЕДИНЕНИЕ ВТ ПО ...
      ```
      
      **Also avoid:**
      - Joining to subqueries with `В` that contain joins
      - Complex conditions in `ПО` (join ON clause) - especially subqueries
      
      Replace all such patterns with sequential queries using temporary tables.
      
      ---
      
      ## Temporary Table Best Practices
      
      **When to use:**
      - Replace nested joins or subqueries in conditions
      - Pre-filter large datasets before joining
      - Break complex multi-join queries into steps
      - Store intermediate results for reuse in batch queries
      
      **Rules:**
      - `ИНДЕКСИРОВАТЬ ПО <field>` - always add when table has >1000 rows and is used in JOIN or `В` subquery
      - Minimize data volume: select only needed fields
      - Minimize row count: apply filters early
      - **Never create/drop temp tables in a loop** - pre-compute or batch-process instead
      - Don't copy a temp table just to rename it - use the original
      - For very large datasets, process in portions rather than loading everything into one temp table
      
      ---
      
      ## RLS Impact
      
      Row-Level Security (RLS) adds implicit conditions to every query. When RLS rules contain subqueries or joins:
      
      - Query plan becomes significantly more complex
      - Compound-type dereferencing cost multiplies
      - Joins become slower
      
      **Mitigation:**
      - Avoid roles with contradictory RLS on the same object
      - Use `РАЗРЕШЕННЫЕ` in SELECT to apply RLS (without it, access errors may occur)
      - If RLS causes severe slowdown: rewrite with temp tables in privileged mode (configuration-level)
      - Keep RLS conditions simple (avoid subqueries and joins in RLS templates)
      
      ---
      
      ## Subquery Restrictions
      
      When using subqueries (in `В`, `СУЩЕСТВУЕТ`, or as a source), avoid:
      
      - Joins inside the subquery
      - Compound-type field access ("any reference" patterns)
      - Accessing document header fields from a tabular section subquery
      - Complex RLS conditions that apply to subquery tables
      
      All of these inflate the SQL generated by the 1C engine. Replace with temporary tables.
      
      ---
      
      ## DBMS Portability
      
      1C runs on multiple DBMS backends (MS SQL, PostgreSQL, IBM DB2, Oracle). Some behaviors differ:
      
      - **String comparison:** Generally case-insensitive in 1C, but edge cases may differ by DBMS
      - **Date arithmetic precision:** May vary
      - **Arithmetic precision:** Rounding differences possible
      - **Query plan optimization:** Different DBMS may choose different execution plans for the same 1C query
      
      **Recommendation:** Always use `ВЫРАЗИТЬ` for explicit type casting. Test queries on the target DBMS. Avoid relying on DBMS-specific behaviors.
      
    • query-syntax-reference.md 7.8 KB
      # Query Syntax Reference
      
      Detailed syntax for clauses covered briefly in the main SKILL.md.
      
      ## Contents
      
      - [ВЫБОР (CASE)](#выбор-case)
      - [ОБЪЕДИНИТЬ (UNION)](#объединить-union)
      - [УПОРЯДОЧИТЬ ПО (ORDER BY)](#упорядочить-по-order-by)
      - [АВТОУПОРЯДОЧИВАНИЕ](#автоупорядочивание)
      - [ИТОГИ (TOTALS)](#итоги-totals)
      - [Grouping sets](#grouping-sets)
      - [ПОДОБНО (LIKE)](#подобно-like)
      - [ССЫЛКА (type check)](#ссылка-type-check)
      - [Subqueries in В (IN)](#subqueries-in-в-in)
      - [ПУСТАЯТАБЛИЦА (empty table)](#пустаятаблица-empty-table)
      
      ---
      
      ## ВЫБОР (CASE)
      
      Conditional expression - equivalent to SQL CASE.
      
      ```
      ВЫБОР
          КОГДА <condition1> ТОГДА <result1>
          КОГДА <condition2> ТОГДА <result2>
          ИНАЧЕ <default>
      КОНЕЦ
      ```
      
      Can be used in field list, HAVING, TOTALS. **Cannot** be used as part of indexed (main) WHERE condition.
      
      Example:
      ```
      ВЫБРАТЬ
          Наименование,
          ВЫБОР
              КОГДА Сумма > 100000 ТОГДА "Крупный"
              КОГДА Сумма > 10000 ТОГДА "Средний"
              ИНАЧЕ "Мелкий"
          КОНЕЦ КАК Категория
      ИЗ Документ.РеализацияТоваровУслуг
      ```
      
      ---
      
      ## ОБЪЕДИНИТЬ (UNION)
      
      Merges results of two or more SELECT queries into one result set.
      
      ```
      ВЫБРАТЬ Поле1, Поле2 ИЗ Таблица1
      ОБЪЕДИНИТЬ [ВСЕ]
      ВЫБРАТЬ Поле1, Поле2 ИЗ Таблица2
      ```
      
      **Rules:**
      - `ОБЪЕДИНИТЬ` - removes duplicates (like UNION)
      - `ОБЪЕДИНИТЬ ВСЕ` - keeps duplicates (like UNION ALL, faster)
      - Column count must match across all queries
      - Column names and types are taken from the **first** query
      - If nested table structures differ, use `ПУСТАЯТАБЛИЦА` in the query that lacks the nested table
      
      ---
      
      ## УПОРЯДОЧИТЬ ПО (ORDER BY)
      
      ```
      УПОРЯДОЧИТЬ ПО <field_or_alias> [ВОЗР | УБЫВ] [, ...]
      ```
      
      - `ВОЗР` - ascending (default)
      - `УБЫВ` - descending
      - Can reference field aliases from SELECT
      - Can use aggregate function results when grouping
      - **Do NOT use aggregate functions directly** for comparison in ORDER BY
      
      Example:
      ```
      ВЫБРАТЬ Контрагент, СУММА(Сумма) КАК Итого
      ИЗ Документ.РеализацияТоваровУслуг
      СГРУППИРОВАТЬ ПО Контрагент
      УПОРЯДОЧИТЬ ПО Итого УБЫВ
      ```
      
      ---
      
      ## АВТОУПОРЯДОЧИВАНИЕ
      
      Adds automatic ordering by "presentation" (human-readable name) of reference fields. Placed after ORDER BY or standalone.
      
      ```
      ВЫБРАТЬ Контрагент, Сумма
      ИЗ Документ.РеализацияТоваровУслуг
      АВТОУПОРЯДОЧИВАНИЕ
      ```
      
      Rarely needed - explicit `УПОРЯДОЧИТЬ ПО` is preferred for predictable results.
      
      ---
      
      ## ИТОГИ (TOTALS)
      
      Computes aggregate subtotal rows and interleaves them with detail rows.
      
      ```
      ИТОГИ
          [<aggregate_expression> [КАК <Alias>] [, ...]]
      ПО
          [ОБЩИЕ]
          [, <control_point> [, ...]]
      ```
      
      **Components:**
      - `ОБЩИЕ` - grand total across entire result
      - Control points - fields to group subtotals by. Can be hierarchical
      - `ПЕРИОДАМИ(<Period>, <StartDate>, <EndDate>)` - for date-type fields; `<Period>` is one of: `СЕКУНДА`, `МИНУТА`, `ЧАС`, `ДЕНЬ`, `НЕДЕЛЯ`, `МЕСЯЦ`, `КВАРТАЛ`, `ГОД`, `ДЕКАДА`, `ПОЛУГОДИЕ`
      
      Example:
      ```
      ВЫБРАТЬ
          Контрагент, Номенклатура, Количество, Сумма
      ИЗ Документ.РеализацияТоваровУслуг.Товары
      ИТОГИ СУММА(Количество), СУММА(Сумма)
      ПО ОБЩИЕ, Контрагент
      ```
      
      **Periodic register totals:** Only enable (`РАЗРЕШИТЬ ИТОГИ`) when large data volume, no date in slice queries, and simple RLS.
      
      ---
      
      ## Grouping Sets
      
      Multiple groupings in a single pass for performance.
      
      ```
      СГРУППИРОВАТЬ ПО ГРУППИРУЮЩИМ НАБОРАМ
          (
              (НаборПолей1),
              (НаборПолей2)
          )
      ```
      
      Field order within a set and set order both matter. Use `СГРУППИРОВАНОПО(<field>)` function to determine which grouping set produced a given row.
      
      Example:
      ```
      ВЫБРАТЬ Контрагент, Номенклатура, СУММА(Сумма) КАК Итого
      ИЗ Документ.РеализацияТоваровУслуг.Товары
      СГРУППИРОВАТЬ ПО ГРУППИРУЮЩИМ НАБОРАМ
          (
              (Контрагент),
              (Номенклатура),
              (Контрагент, Номенклатура)
          )
      ```
      
      ---
      
      ## ПОДОБНО (LIKE)
      
      String pattern matching operator.
      
      ```
      ГДЕ Наименование ПОДОБНО "Шаблон"
      ```
      
      **Wildcards:**
      
      | Character | Meaning | Example |
      |-----------|---------|---------|
      | `%` | Any string (0+ chars) | `"%молоко%"` - contains "молоко" |
      | `_` | Exactly one character | `"__-__"` - matches "12-34" |
      | `[abc]` | One char from set | `"[АБВ]%"` - starts with А, Б, or В |
      | `[^abc]` | One char NOT in set | `"[^0-9]%"` - starts with non-digit |
      | `[a-z]` | One char in range | `"[А-Я]%"` - starts with capital Cyrillic |
      
      **Escape character:** Use `СПЕЦСИМВОЛ` to escape wildcards:
      ```
      ГДЕ Код ПОДОБНО "%#_%" СПЕЦСИМВОЛ "#"
      // matches literal underscore in Код
      ```
      
      **Performance:** Pattern must NOT start with `%` or `_` if used in indexed (main) condition - such patterns prevent index usage.
      
      ---
      
      ## ССЫЛКА (Type Check)
      
      Checks if a reference-type value points to a specific table. Used with compound-type fields.
      
      ```
      ГДЕ Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
      ```
      
      Commonly paired with `ВЫРАЗИТЬ`:
      ```
      ВЫБРАТЬ
          ВЫБОР
              КОГДА Регистратор ССЫЛКА Документ.Реализация
                  ТОГДА ВЫРАЗИТЬ(Регистратор КАК Документ.Реализация).Контрагент
              КОГДА Регистратор ССЫЛКА Документ.Поступление
                  ТОГДА ВЫРАЗИТЬ(Регистратор КАК Документ.Поступление).Контрагент
          КОНЕЦ КАК Контрагент
      ИЗ РегистрНакопления.ОстаткиТоваров
      ```
      
      ---
      
      ## Subqueries in В (IN)
      
      Check membership against a subquery result:
      
      ```
      ГДЕ Контрагент В (
          ВЫБРАТЬ Ссылка ИЗ Справочник.Контрагенты ГДЕ Город = &Город
      )
      ```
      
      **Rules:**
      - Subquery must return exactly one column
      - Avoid complex subqueries (joins, compound type access, nested subqueries). Use temporary tables instead
      - For large filter sets, a temp table with `В (ВЫБРАТЬ ... ИЗ ВТ)` is more efficient than a literal list
      
      ---
      
      ## ПУСТАЯТАБЛИЦА (Empty Table)
      
      Used in UNION when one query has a nested table (tabular section) that the other doesn't.
      
      ```
      // Query 1 has Товары nested table
      ВЫБРАТЬ Ссылка, Товары.(Номенклатура, Количество)
      ИЗ Документ.РеализацияТоваровУслуг
      
      ОБЪЕДИНИТЬ ВСЕ
      
      // Query 2 lacks it - provide matching empty table
      ВЫБРАТЬ Ссылка, ПУСТАЯТАБЛИЦА.(Номенклатура, Количество)
      ИЗ Документ.ВозвратТоваров
      ```
      
      Alias names inside `ПУСТАЯТАБЛИЦА.(...)` must match the aliases from the corresponding real nested table in the other query.
      
  • SKILL.md 28.9 KB
    ---
    name: composing-1c-queries
    description: >
      Compose correct and optimized 1C:Enterprise query language queries. Covers
      ВЫБРАТЬ/ИЗ/ГДЕ structure, table naming (catalogs, documents, registers,
      virtual tables), field selection, joins, grouping, totals, temporary tables,
      and parameter usage. Includes accounting register virtual tables (Остатки,
      Обороты, ОстаткиИОбороты, ОборотыДтКт, ДвиженияССубконто) with Счет,
      Субконто, and correspondence parameters. Use when the agent needs to compose
      a 1C query for execute_query, or when the user asks to query, filter,
      aggregate, or analyze data from a 1C database. Triggered by requests
      involving 1C data retrieval, report building, or query debugging.
    ---
    
    # Composing 1C Queries
    
    Rules and patterns for writing correct 1C:Enterprise query language (язык запросов 1С).
    Queries are executed via the `execute_query` tool/endpoint.
    
    ## CRITICAL: Verify Metadata Before Querying
    
    **NEVER guess or invent metadata object names, attribute names, or tabular section names.** 1C configurations vary greatly - object and field names are unique to each database.
    
    Before composing a query, if you are not certain about the exact names, **use `get_metadata` or any other available tool to retrieve 1C configuration metadata** to discover:
    - Available metadata objects (catalogs, documents, registers, etc.)
    - Object attributes (реквизиты) and their types
    - Tabular sections (табличные части) and their columns
    - Register dimensions, resources, and attributes
    
    **Workflow:** retrieve metadata → confirm names → compose query → **validate query** → execute query
    
    A query with a wrong object or field name will fail with a runtime error. Spending one call on metadata retrieval is always cheaper than debugging a failed query.
    
    ## Имена таблиц и полей из AI-EDT
    
    Если сервер AI-EDT подключен, имена не угадываются, а берутся у него - `insights operation=describe_db_tables`
    (отдельное имя `describe_db_tables` тоже работает). Инструмент показывает, во что объект превращается в
    базе данных: основную таблицу, по одной на каждую табличную часть, виртуальные таблицы регистра
    (остатки, обороты, срезы) с их параметрами, таблицу изменений и перерасчеты регистра расчета. Имена
    таблиц и полей отдаются сразу на двух языках, с типами полей, готовыми к подстановке после `ИЗ`.
    
    Это дешевле, чем писать запрос по памяти и ловить ошибки имен по одной через `validate_query`: за один
    вызов видно все, что вообще можно выбрать.
    
    ## Validate Query via AI-EDT
    
    Если сервер AI-EDT подключен (инструменты `ai-edt` доступны), **обязательно проверяй запрос** перед выполнением через `validate_query`:
    - Проверяет синтаксис и семантику в контексте реального проекта
    - Для запросов СКД: `dcsMode=true`
    - Ловит ошибки имен таблиц, полей, типов до выполнения
    
    **Formatting:** Always write the entire query text in a **single line**. Do not use line breaks or multiline formatting.
    
    ## Query Structure
    
    Canonical order of clauses (required section marked, rest optional):
    
    ```
    ВЫБРАТЬ [РАЗРЕШЕННЫЕ] [РАЗЛИЧНЫЕ] [ПЕРВЫЕ <N>]
        <field list>
    ИЗ
        <data sources>
    [ГДЕ <condition>]
    [СГРУППИРОВАТЬ ПО <fields>]
    [ИМЕЮЩИЕ <condition>]
    
    [ОБЪЕДИНИТЬ [ВСЕ]
    ВЫБРАТЬ ...]
    
    [УПОРЯДОЧИТЬ ПО <fields> [ВОЗР | УБЫВ]]
    [АВТОУПОРЯДОЧИВАНИЕ]
    
    [ИТОГИ <aggregate expressions> ПО [ОБЩИЕ] <control points>]
    ```
    
    **Keywords:**
    
    | Keyword | Meaning |
    |---------|---------|
    | `ВЫБРАТЬ` | SELECT - mandatory, starts the query |
    | `РАЗРЕШЕННЫЕ` | Respect row-level security (RLS). Use by default for safety |
    | `РАЗЛИЧНЫЕ` | DISTINCT - remove duplicate rows |
    | `ПЕРВЫЕ N` | Return only first N rows (1C has no LIMIT keyword - this is the only way) |
    | `ИЗ` | FROM - data sources |
    | `ГДЕ` | WHERE - row filter |
    | `СГРУППИРОВАТЬ ПО` | GROUP BY |
    | `ИМЕЮЩИЕ` | HAVING - group filter |
    | `ОБЪЕДИНИТЬ [ВСЕ]` | UNION [ALL] |
    | `УПОРЯДОЧИТЬ ПО` | ORDER BY. `ВОЗР` = ASC, `УБЫВ` = DESC |
    | `АВТОУПОРЯДОЧИВАНИЕ` | Auto-order by presentation (rarely used) |
    | `ИТОГИ` | TOTALS - compute aggregate subtotals |
    
    Comments: `// single-line only`.
    
    Minimal example:
    
    ```
    ВЫБРАТЬ Ссылка, Наименование
    ИЗ Справочник.Контрагенты
    ГДЕ НЕ ПометкаУдаления
    ```
    
    ## Table Names and Sources
    
    Every 1C metadata object has a fixed query-name pattern. Use exact names from `get_metadata`.
    
    ### Real tables
    
    | Object type | Query name pattern | Example |
    |-------------|-------------------|---------|
    | Catalog | `Справочник.<Name>` | `Справочник.Номенклатура` |
    | Document | `Документ.<Name>` | `Документ.РеализацияТоваровУслуг` |
    | Document tabular section | `Документ.<Name>.<Section>` | `Документ.РеализацияТоваровУслуг.Товары` |
    | Accumulation register | `РегистрНакопления.<Name>` | `РегистрНакопления.ОстаткиТоваров` |
    | Information register | `РегистрСведений.<Name>` | `РегистрСведений.КурсыВалют` |
    | Accounting register | `РегистрБухгалтерии.<Name>` | `РегистрБухгалтерии.Хозрасчетный` |
    | Chart of accounts | `ПланСчетов.<Name>` | `ПланСчетов.Хозрасчетный` |
    | Chart of characteristic types | `ПланВидовХарактеристик.<Name>` | `ПланВидовХарактеристик.ВидыСубконто` |
    | Calculation register | `РегистрРасчета.<Name>` | `РегистрРасчета.Начисления` |
    | Business process | `БизнесПроцесс.<Name>` | `БизнесПроцесс.Согласование` |
    | Task | `Задача.<Name>` | `Задача.ЗадачаИсполнителя` |
    
    ### Enum values and predefined items
    
    ```
    // Enum value (used in conditions, not as a table):
    ЗНАЧЕНИЕ(Перечисление.ТипыЦен.Оптовая)
    
    // Predefined catalog item:
    ЗНАЧЕНИЕ(Справочник.Валюты.USD)
    
    // Empty reference:
    ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)
    ```
    
    ### Virtual tables
    
    Virtual tables are computed on-the-fly from real register data. **Always pass filter conditions as virtual table parameters, NOT in WHERE** - this is critical for performance.
    
    **Accumulation register (Регистр накопления):**
    
    ```
    // Current balances (no date = latest):
    РегистрНакопления.ОстаткиТоваров.Остатки(, Номенклатура = &Ном)
    
    // Balances at specific date:
    РегистрНакопления.ОстаткиТоваров.Остатки(&Дата, Склад = &Склад)
    
    // Turnovers for period:
    РегистрНакопления.ОстаткиТоваров.Обороты(&НачДата, &КонДата, , Номенклатура = &Ном)
    
    // Balances and turnovers:
    РегистрНакопления.ОстаткиТоваров.ОстаткиИОбороты(&НачДата, &КонДата, , , Номенклатура = &Ном)
    ```
    
    **Information register (Регистр сведений):**
    
    ```
    // Latest values (slice of last):
    РегистрСведений.КурсыВалют.СрезПоследних(&Дата, Валюта = &Валюта)
    
    // Earliest values (slice of first):
    РегистрСведений.КурсыВалют.СрезПервых(&Дата, Валюта = &Валюта)
    ```
    
    **Accounting register (Регистр бухгалтерии):**
    
    5 virtual tables: Остатки, Обороты, ОстаткиИОбороты, ОборотыДтКт, ДвиженияССубконто.
    
    Сигнатуры ниже приведены для регистров с корреспонденцией (`КорреспондирующиеСчета = Истина`, например типовой `Хозрасчетный`). Для регистров без корреспонденции `.ОборотыДтКт` и `.ДвиженияССубконто` отсутствуют, у `.Обороты` нет `УсловиеКорСчета` и `КорСубконто`.
    
    ```
    // Balances at date:
    РегистрБухгалтерии.Хозрасчетный.Остатки(&Период, Счет = &Счет, , )
    
    // Turnovers for period:
    РегистрБухгалтерии.Хозрасчетный.Обороты(&НачДата, &КонДата, Месяц, Счет В (&Счета), , , , )
    
    // Balances and turnovers:
    РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(&НачДата, &КонДата, Авто, , Счет = &Счет, , )
    
    // Debit-Credit turnovers (detailed correspondence):
    РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт(&НачДата, &КонДата, , , , , , )
    
    // Detailed records with subconto:
    РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(&НачДата, &КонДата, , , )
    ```
    
    Virtual table parameters (positional order):
    
    | Virtual table | Parameters |
    |---------------|------------|
    | `.Остатки()` | Период, УсловиеСчета, Субконто, Условие |
    | `.Обороты()` | НачалоПериода, КонецПериода, Периодичность, УсловиеСчета, Субконто, Условие, УсловиеКорСчета, КорСубконто |
    | `.ОстаткиИОбороты()` | НачалоПериода, КонецПериода, Периодичность, МетодДополненияПериодов, УсловиеСчета, Субконто, Условие |
    | `.ОборотыДтКт()` | НачалоПериода, КонецПериода, Периодичность, УсловиеСчетаДт, СубконтоДт, УсловиеСчетаКт, СубконтоКт, Условие |
    | `.ДвиженияССубконто()` | НачалоПериода, КонецПериода, Условие, Порядок, Первые |
    
    Note: справка платформы (синтакс-помощник) для регистра бухгалтерии часто опускает `УсловиеСчета`/`УсловиеКорСчета`/`УсловиеСчетаДт`/`УсловиеСчетаКт`. Эти параметры реально существуют и работают (см. ИТС pubqlang) - без них смещается весь позиционный список и `Счет = ...` попадает в позицию `Субконто` (тип не совпадет, отбор не сработает).
    
    **Key differences from accumulation register:**
    
    - **Субконто parameter** accepts виды субконто (plan of characteristic types references), NOT values. Filter by subconto values in `Условие`: `Субконто1 = &Контрагент`
    - **Счет/КорСчет** filtering - отдельные параметры `УсловиеСчета`/`УсловиеКорСчета` (не в `Условие`): `Счет = &Счет`, `Счет В ИЕРАРХИИ(&Счет)`. Для `ОборотыДтКт` - `УсловиеСчетаДт`/`УсловиеСчетаКт`
    - **Периодичность** values: Авто, Период, Год, Полугодие, Квартал, Месяц, Декада, Неделя, День, Регистратор, Запись
    - **МетодДополненияПериодов** (ОстаткиИОбороты only): `Движения` or `ДвиженияИГраницыПериода` (default)
    - Resources have Дт/Кт (Debit/Credit) suffixes - see table below
    
    Parameter syntax inside virtual tables: `Dimension = Value` joined by commas. Keep it simple - no subqueries or joins inside parameters.
    
    **Accumulation register resource suffixes:**
    
    When using virtual tables, resource fields get automatic suffixes:
    
    | Virtual table | Suffix format | Example |
    |---------------|---------------|---------|
    | `.Остатки()` | `<Resource>Остаток` | `КоличествоОстаток` |
    | `.Обороты()` | `<Resource>Оборот` | `КоличествоОборот` |
    | `.ОстаткиИОбороты()` | `<Resource>НачальныйОстаток` | `КоличествоНачальныйОстаток` |
    | `.ОстаткиИОбороты()` | `<Resource>Приход` | `КоличествоПриход` |
    | `.ОстаткиИОбороты()` | `<Resource>Расход` | `КоличествоРасход` |
    | `.ОстаткиИОбороты()` | `<Resource>Оборот` | `КоличествоОборот` |
    | `.ОстаткиИОбороты()` | `<Resource>КонечныйОстаток` | `КоличествоКонечныйОстаток` |
    
    ```
    // Example - turnovers with all suffixes:
    ВЫБРАТЬ
        Об.Номенклатура,
        Об.КоличествоПриход,
        Об.КоличествоРасход,
        Об.КоличествоОборот,
        Об.КоличествоНачальныйОстаток,
        Об.КоличествоКонечныйОстаток
    ИЗ
        РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&Нач, &Кон, , , ) КАК Об
    ```
    
    **Accounting register resource suffixes:**
    
    Unlike accumulation register, accounting resources have Дт/Кт (Debit/Credit) variants:
    
    | Virtual table | Suffix format | Example |
    |---------------|---------------|---------|
    | `.Остатки()` | `<Resource>Остаток` | `СуммаОстаток` |
    | `.Остатки()` | `<Resource>ОстатокДт/Кт` | `СуммаОстатокДт` |
    | `.Остатки()` | `<Resource>РазвернутыйОстатокДт/Кт` | `СуммаРазвернутыйОстатокДт` |
    | `.Обороты()` | `<Resource>Оборот` | `СуммаОборот` |
    | `.Обороты()` | `<Resource>ОборотДт/Кт` | `СуммаОборотДт` |
    | `.Обороты()` | `<Resource>КорОборотДт/Кт` | `СуммаКорОборотДт` |
    | `.ОстаткиИОбороты()` | `<Resource>НачальныйОстатокДт/Кт` | `СуммаНачальныйОстатокДт` |
    | `.ОстаткиИОбороты()` | `<Resource>ОборотДт/Кт` | `СуммаОборотДт` |
    | `.ОстаткиИОбороты()` | `<Resource>КонечныйОстатокДт/Кт` | `СуммаКонечныйОстатокДт` |
    | `.ОстаткиИОбороты()` | `<Resource>НачальныйРазвернутыйОстатокДт/Кт` | `СуммаНачальныйРазвернутыйОстатокДт` |
    | `.ОстаткиИОбороты()` | `<Resource>КонечныйРазвернутыйОстатокДт/Кт` | `СуммаКонечныйРазвернутыйОстатокДт` |
    
    Suffixes without Дт/Кт (e.g. `СуммаОстаток`, `СуммаОборот`) are for balanced resources.
    
    ```
    // Example - accounting register balances and turnovers:
    ВЫБРАТЬ
        Об.Счет,
        Об.Субконто1,
        Об.СуммаНачальныйОстатокДт КАК НачОстДт,
        Об.СуммаОборотДт,
        Об.СуммаОборотКт,
        Об.СуммаКонечныйОстатокДт КАК КонОстДт
    ИЗ
        РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(
            &НачДата, &КонДата, Авто, , Счет = &Счет, , ) КАК Об
    ```
    
    ### Table aliases
    
    ```
    Справочник.Номенклатура КАК Товары
    ```
    
    Always assign **informative** aliases - they must be understandable without context:
    
    - **No** single-letter (`Р`, `Т`, `С`) or cryptic abbreviations (`ВТДок`, `ДокГР`)
    - For long table names, shorten meaningfully: `РасчетыНДФЛ`, `РезидентствоФЛ`, `ВедомостиЗП`
    - For temp tables as sources, reuse the temp table name or shorten it meaningfully
    
    ```
    // Bad:
    РегистрНакопления.РасчетыНалогоплательщиковСБюджетомПоНДФЛ КАК Р
    
    // Good:
    РегистрНакопления.РасчетыНалогоплательщиковСБюджетомПоНДФЛ КАК РасчетыНДФЛ
    
    // Bad:
    ВТДокументОснованияДляУвольнений КАК ВТУвольнения
    
    // Good:
    ВТДокументОснованияДляУвольнений КАК ДокументыУвольнений
    ```
    
    Aliases are required when self-joining or using the same table twice.
    
    ### Hierarchical catalogs
    
    Catalogs with hierarchy support nested groups:
    
    ```
    // Direct children (one level) - preferred:
    ВЫБРАТЬ Наименование
    ИЗ Справочник.Номенклатура
    ГДЕ Родитель = &Родитель
    // params: {"Родитель": {"_objectRef": true, "УникальныйИдентификатор": "...",
    //                        "ТипОбъекта": "СправочникСсылка.Номенклатура", "Представление": "..."}}
    
    // Or by name:
    ГДЕ Родитель.Наименование = "Бытовая техника"
    
    // All items in group and subgroups - preferred:
    ВЫБРАТЬ Наименование
    ИЗ Справочник.Номенклатура
    ГДЕ Ссылка В ИЕРАРХИИ (&Группа)
    // params: {"Группа": {"_objectRef": true, "УникальныйИдентификатор": "...",
    //                      "ТипОбъекта": "СправочникСсылка.Номенклатура", "Представление": "..."}}
    
    // Or by name:
    ГДЕ Ссылка В ИЕРАРХИИ (
        ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура
        ГДЕ Наименование = "Бытовая техника"
    )
    
    // Only leaf items (not groups):
    ГДЕ ЭтоГруппа = ЛОЖЬ
    
    // Only groups:
    ГДЕ ЭтоГруппа = ИСТИНА
    ```
    
    **Rules:**
    - `Родитель = &Родитель` - direct children only (one level)
    - `Ссылка В ИЕРАРХИИ (&Группа)` - all nested levels
    - `ЭтоГруппа` - `ИСТИНА` = groups only, `ЛОЖЬ` = leaf items only
    - **AVOID:** `В ИЕРАРХИИ (ПустаяСсылка)` - very slow
    
    ## Field Selection
    
    - `*` selects all real fields (virtual fields are NOT included)
    - Aliases: `<expression> КАК <Alias>` - aliases must be unique within the query
    - Access nested fields with dot notation: `Товары.Номенклатура.Наименование`
    
    ### CRITICAL: Compound-type field dereferencing
    
    When a field can reference multiple table types (compound/composite type), accessing it through dots creates implicit JOINs to **ALL** possible target tables. This severely degrades performance.
    
    **Always narrow the type with ВЫРАЗИТЬ:**
    
    ```
    // BAD - joins to every possible Регистратор table:
    ВЫБРАТЬ Регистратор.Номер ИЗ РегистрНакопления.ОстаткиТоваров
    
    // GOOD - single join:
    ВЫБРАТЬ ВЫРАЗИТЬ(Регистратор КАК Документ.РеализацияТоваровУслуг).Номер
    ИЗ РегистрНакопления.ОстаткиТоваров
    ГДЕ Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
    ```
    
    ### NULL handling
    
    - Use `ЕСТЬNULL(field, default)` for fields that may be NULL (e.g., from LEFT JOIN)
    - Check NULL with `ЕСТЬ NULL` / `НЕ ЕСТЬ NULL` (not `= NULL`)
    
    ### Empty table for UNION
    
    When unioning queries with different nested table structures:
    ```
    ПУСТАЯТАБЛИЦА.(Номенклатура, Количество, Цена)
    ```
    
    ## WHERE and HAVING
    
    ### Operators
    
    | Operator | 1C syntax | Notes |
    |----------|-----------|-------|
    | Equals | `=` | |
    | Not equals | `<>` | |
    | Comparison | `<`, `>`, `<=`, `>=` | |
    | AND | `И` | |
    | OR | `ИЛИ` | Avoid in WHERE - see caveats |
    | NOT | `НЕ` | |
    | Range | `МЕЖДУ X И Y` | Inclusive both ends |
    | In list | `В (val1, val2, ...)` | |
    | In subquery | `В (ВЫБРАТЬ ...)` | |
    | NULL check | `ЕСТЬ NULL` / `НЕ ЕСТЬ NULL` | Never use `= NULL` |
    | Type check | `ССЫЛКА Документ.Реализация...` | Checks reference type |
    | Pattern | `ПОДОБНО "шаблон"` | `%` any string, `_` one char |
    | CASE | `ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ` | Only in non-indexed conditions |
    
    **Operator precedence:** `НЕ` > `И` > `ИЛИ`. Use parentheses `()` for explicit priority.
    
    ### Key rules
    
    - **ИЛИ (OR) degrades index usage.** Replace with `В (...)` where possible, or split into `ОБЪЕДИНИТЬ ВСЕ`
    - **ВЫБОР (CASE) in WHERE:** Only in additional (non-indexed) conditions
    - **String comparison:** Case-insensitive, ignores trailing spaces
    - **Arithmetic in WHERE:** Only in additional conditions (prevents index use)
    - **Pattern ПОДОБНО:** Must not start with `%` or `_` if in indexed condition
    
    For index-aware optimization strategy, see [optimization-and-pitfalls.md](references/optimization-and-pitfalls.md).
    
    ## Joins
    
    ```
    ИЗ Документ.РеализацияТоваровУслуг КАК Док
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Конт
        ПО Док.Контрагент = Конт.Ссылка
    ```
    
    | Type | 1C syntax |
    |------|-----------|
    | Inner | `ВНУТРЕННЕЕ СОЕДИНЕНИЕ ... ПО` |
    | Left outer | `ЛЕВОЕ [ВНЕШНЕЕ] СОЕДИНЕНИЕ ... ПО` |
    | Right outer | `ПРАВОЕ [ВНЕШНЕЕ] СОЕДИНЕНИЕ ... ПО` |
    | Full outer | `ПОЛНОЕ [ВНЕШНЕЕ] СОЕДИНЕНИЕ ... ПО` |
    
    **Rules:**
    - **NEVER use nested joins** (join of a subquery that itself contains joins). Replace with temporary tables or sequential joins
    - For LEFT JOIN: index the right table's join fields
    - For INNER JOIN: index the larger table's join fields
    
    ## Grouping and Totals
    
    ### GROUP BY
    
    ```
    ВЫБРАТЬ
        Контрагент,
        СУММА(СуммаДокумента) КАК Итого,
        КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Ссылка) КАК КолДок
    ИЗ Документ.РеализацияТоваровУслуг
    СГРУППИРОВАТЬ ПО Контрагент
    ИМЕЮЩИЕ СУММА(СуммаДокумента) > 1000
    ```
    
    **Aggregate functions:** `СУММА` (SUM), `СРЕДНЕЕ` (AVG), `МИНИМУМ` (MIN), `МАКСИМУМ` (MAX), `КОЛИЧЕСТВО` (COUNT), `КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...)` (COUNT DISTINCT).
    
    Every non-aggregated field in SELECT must appear in GROUP BY.
    
    ### TOTALS (brief)
    
    ```
    ИТОГИ СУММА(СуммаДокумента) ПО ОБЩИЕ, Контрагент
    ```
    
    Computes subtotal rows interleaved with detail rows. For full syntax (ПЕРИОДАМИ, hierarchical control points, grouping sets), see [query-syntax-reference.md](references/query-syntax-reference.md).
    
    ## Temporary Tables
    
    Use temporary tables to break complex queries into steps, avoid nested subqueries, and improve performance.
    
    ```
    // Step 1: collect items into temp table
    ВЫБРАТЬ Ссылка КАК Номенклатура
    ПОМЕСТИТЬ ВТ_Товары
    ИЗ Справочник.Номенклатура
    ГДЕ Наименование ПОДОБНО &Маска
    ИНДЕКСИРОВАТЬ ПО Номенклатура
    ;
    // Step 2: get balances for those items
    ВЫБРАТЬ
        Ост.Номенклатура КАК Номенклатура,
        Ост.КоличествоОстаток КАК Остаток
    ИЗ РегистрНакопления.ОстаткиТоваров.Остатки(
            ,
            Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ ВТ_Товары)
        ) КАК Ост
    ```
    
    **Rules:**
    - Separate queries in a batch with `;`
    - `ПОМЕСТИТЬ <Name>` creates the temp table (place right after SELECT fields, before ИЗ)
    - `ИНДЕКСИРОВАТЬ ПО <field>` - add after the query for temp tables with >1000 rows used in joins or `В` subqueries
    - Minimize data volume and field count in temp tables
    - **NEVER** create/drop temp tables in a loop
    - Prefer temp tables over nested subqueries in JOIN conditions
    
    ## Parameters
    
    Parameters are external values passed into the query. Syntax: `&ParameterName`.
    
    ```
    ВЫБРАТЬ * ИЗ Справочник.Контрагенты ГДЕ Наименование ПОДОБНО &Маска
    ```
    
    Passed via `execute_query` params: `{"Маска": "%Рога%"}`.
    
    **Rules:**
    - Always use parameters for external values - never concatenate strings into query text
    - Enum values: use `ЗНАЧЕНИЕ()` in query text, not as parameter: `ГДЕ Тип = ЗНАЧЕНИЕ(Перечисление.ТипыЦен.Оптовая)`
    - Date format in params: ISO 8601 (`"2024-01-15"` or `"2024-01-15T10:30:00"`)
    - Boolean: `ИСТИНА` / `ЛОЖЬ` in query text, or pass `true`/`false` as parameter
    
    ## Comparing Reference Fields
    
    When comparing reference fields (link-type attributes), **pass the reference as a parameter**:
    
    ```
    // GOOD - reference passed as parameter from previous query result:
    ВЫБРАТЬ * ИЗ Документ.ПродажаТоваров
    ГДЕ Контрагент = &Контрагент
    // params: {"Контрагент": {"_objectRef": true, "УникальныйИдентификатор": "...",
    //                           "ТипОбъекта": "СправочникСсылка.Контрагенты", "Представление": "..."}}
    
    // ALSO GOOD - compare via primitive attribute:
    ГДЕ Контрагент.Наименование = "ООО Ромашка"
    ГДЕ Контрагент.Код = "000001"
    
    // AVOID - direct comparison with another table's reference:
    ГДЕ Документ.Контрагент = Справочник.Контрагенты.Ссылка
    ```
    
    **Rules:**
    - **First choice:** pass reference object from previous query result as `&Parameter`
    - **Fallback:** compare via primitive fields (Наименование, Код, etc.)
    - Never compare reference fields directly from different sources
    
    ## Common Patterns
    
    **1. Find by name (fuzzy):**
    ```
    ВЫБРАТЬ Ссылка, Наименование ИЗ Справочник.Контрагенты ГДЕ Наименование ПОДОБНО &Маска
    // params: {"Маска": "%рога%"}
    ```
    
    **2. Latest N documents:**
    ```
    ВЫБРАТЬ ПЕРВЫЕ 10 Ссылка, Дата, Номер, СуммаДокумента
    ИЗ Документ.РеализацияТоваровУслуг
    УПОРЯДОЧИТЬ ПО Дата УБЫВ
    ```
    
    **3. Current balances (virtual table, no date = now):**
    ```
    ВЫБРАТЬ Номенклатура, КоличествоОстаток
    ИЗ РегистрНакопления.ОстаткиТоваров.Остатки(, Номенклатура = &Ном) КАК Ост
    ```
    
    **4. Latest register slice:**
    ```
    ВЫБРАТЬ Валюта, Курс ИЗ РегистрСведений.КурсыВалют.СрезПоследних(&Дата,) КАК Курсы
    ```
    
    **5. Count by group:**
    ```
    ВЫБРАТЬ Контрагент, КОЛИЧЕСТВО(*) КАК Кол
    ИЗ Документ.РеализацияТоваровУслуг
    СГРУППИРОВАТЬ ПО Контрагент
    УПОРЯДОЧИТЬ ПО Кол УБЫВ
    ```
    
    **6. Check existence:**
    ```
    ВЫБРАТЬ ПЕРВЫЕ 1 Ссылка ИЗ Справочник.Контрагенты ГДЕ ИНН = &ИНН
    ```
    
    **7. Exclude items marked for deletion:**
    ```
    ГДЕ НЕ ПометкаУдаления
    ```
    
    **8. Explore table structure (zero-row query with schema):**
    ```
    ВЫБРАТЬ ПЕРВЫЕ 0 * ИЗ Справочник.Контрагенты
    // use with include_schema: true in execute_query
    ```
    
    ## References
    
    - [Query syntax reference](references/query-syntax-reference.md) - ВЫБОР (CASE), ОБЪЕДИНИТЬ, УПОРЯДОЧИТЬ ПО, ИТОГИ, ПОДОБНО patterns, ССЫЛКА, subqueries
    - [Optimization and caveats](references/optimization-and-pitfalls.md) - index strategy, ИЛИ alternatives, compound types, virtual table rules, RLS impact
    - [Functions and expressions](references/functions-and-expressions.md) - aggregate, date, string, type, math functions and type casting with ВЫРАЗИТЬ
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related