T-SQL + 1С: нумерация записей табличных частей и наборов регистров по порядку
Обработка данных больших баз 1С часто выполняется средствами SQL. Это может быть свёртка или какая-то другая задача. После выполнения команды DELETE может нарушиться последовательность нумерации записей табличной части или набора регистра. Это может привести к неприятным последствиям, если её не восстановить. В данной публикации приводится достаточно простое решение этой проблемы.
- Описание
- Подробнее
Описание
Предположим, что нам необходимо свернуть все движения по выбывшей из оборота номенклатуре. Мы выполнили удаление движений по регистрам накопления и обнаружили, что нумерация записей наборов нарушилась. Это может выглядеть примерно вот так (значения в ячейках имеют демонстрационный характер для упрощения восприятия):
| _Period | _RecorderTRef | _RecorderRRef | _LineNo | _Fld123RRef |
| 01.01.2010 12:00:00 | 0x12 | 0x01 | 1 | 0x11 |
| 01.01.2010 12:00:00 | 0x12 | 0x01 | 2 | 0x22 |
| 01.01.2010 12:00:00 | 0x12 | 0x01 | 4 | 0x44 |
где
_Period — период регистра накопления;
_RecorderTRef — код типа документа, например, Документ.ПоступлениеТоваровУслуг;
_RecorderRRef — ссылка на документ (имеет тип binary(16), по факту является GUID’ом);
_LineNo — порядковый номер записи набора регистра;
_Fld123RRef — измерение, ссылка на элемент справочника «Номенклатура» (в нашем примере так).
В данной таблице не хватает записи с номером строки _LineNo равным 3. Эта строка была удалена в процессе свёртки. Если мы оставим это так как есть, то, например, при выполнении такого кода 1С (проверялось на платформе 8.3):
Набор = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(ДокументСсылка);
Набор.Прочитать();
Набор.Записать();Можно неожиданно получить вот такой результат:
| _Period | _RecorderTRef | _RecorderRRef | _LineNo | _Fld123RRef |
| 01.01.2010 12:00:00 | 0x12 | 0x01 | 1 | 0x11 |
| 01.01.2010 12:00:00 | 0x12 | 0x01 | 2 | 0x22 |
| 01.01.2010 12:00:00 | 0x12 | 0x01 | 3 | 0x44 |
| 01.01.2010 12:00:00 | 0x12 | 0x01 | 4 | 0x44 |
Последняя строка в наборе регистра задублировалась. Как это произошло? Моя гипотеза такова: набор записей был успешно прочитан в оперативную память, а затем, при его записи обратно в базу данных, 1С восстановила последовательность нумерации и та строка, которая имела значение поля _LineNo равным 4 стала равна 3. В таком виде набор записывается в базу данных, но строка со значением _LineNo равным 4 из базы данных не была удалена и к ней дописываются строки со значениями _LineNo равными 1, 2 и 3, которые они получили в оперативной памяти. Таким образом получается дублирование.
В таких случаях требуется восстановить последовательность нумерации строк. Как это сделать наиболее простым способом? Это можно сделать при помощи следующей команды SQL:
SET
T.[_LineNo] = T.[RowNumber] — Обновляем значения
FROM
(SELECT
T.[_LineNo] AS [_LineNo],
— Нумерация по порядку средствами SQL — используем оконные функции
ROW_NUMBER() OVER(PARTITION BY T.[_RecorderRRef] ORDER BY T.[_LineNo]) AS [RowNumber]
FROM
[ИмяТаблицыРегистра] AS T
INNER JOIN
(SELECT
[_RecorderRRef] AS [_RecorderRRef],
COUNT([_LineNo]) AS [LineCount], — Количество строк в разрезе регистратора
MAX([_LineNo]) AS [LineMax] — Максимальное значение номера строки в разрезе регистратора
FROM
[ИмяТаблицыРегистра]
WHERE
[_Period] < @Period — Здесь может быть любое нужное нам условие отбора записей набора регистра
GROUP BY
[_RecorderRRef]
HAVING
COUNT([_LineNo]) <> MAX([_LineNo]) — Таким образом мы отбираем регистраторы, у которых нарушилась нумерация

