--naf --naf

четверг, 25 июня 2015 г.

Алгоритм Нарайаны для 1С 8.2

Данный код реализует алгоритм Нарайаны на движке 1С 8.2.

Функция ВсеПерестановки(ЧислоЭлементов) Экспорт

	Результат = Новый Массив;
	Массив = Новый Массив;
	Для й=1 По ЧислоЭлементов Цикл
		Массив.Добавить(й);	
	КонецЦикла; 
	Результат.Добавить(Массив);
	
	Пока Истина Цикл
		Список = Новый СписокЗначений;
		Список.ЗагрузитьЗначения(Массив);
		Массив = Список.ВыгрузитьЗначения();
		
		Ключ = Неопределено;
		Для й=0 по ЧислоЭлементов-2 Цикл
			Если Массив[й]<Массив[й+1] Тогда
				Ключ = й;			
			КонецЕсли; 			
		КонецЦикла; 
		
		Если Ключ=Неопределено Тогда
			Прервать;		
		КонецЕсли; 
		
		Для й=1-ЧислоЭлементов По 0 Цикл
			Если Массив[Ключ]<Массив[-й] Тогда
				Прервать;			
			КонецЕсли; 		
		КонецЦикла; 	
		Поменять(Массив[Ключ],Массив[-й]);
		
		й = Ключ+1;
		к = ЧислоЭлементов-1;
		Пока й<к Цикл
			Поменять(Массив[й],Массив[к]);
			й = й+1;
			к = к-1;
		КонецЦикла; 
		
		Результат.Добавить(Массив);
		
	КонецЦикла; 
	
    Возврат Результат;
	
КонецФункции

Процедура Поменять(А,Б)

	Т = А;
	А = Б;
	Б = Т;

КонецПроцедуры


среда, 8 апреля 2015 г.

Библиотека функций работы с наборами записей регистров

Реально неудобно сделан в 1С 8 отбор для наборов записей регистров.
Начну с независимых регистров сведений. Зачем столько писать?
НЗ = РегистрыСведений.СохраненныеНастройки.СоздатьНаборЗаписей();
НЗ.Отбор.Пользователь.Установить(ВыборкаПольз.Пользователь);
НЗ.Отбор.ИмяОбъекта.Установить(Выборка.ИмяОбъекта);
НЗ.Отбор.НаименованиеНастройки.Установить(Выборка.НаименованиеНастройки);
Если все равно отбор можно установить только на равенство? Мне кажется структура тут была бы гораздо удобнее:
НЗ = СоздатьНаборЗаписейНезависимогоРС(РегистрыСведений.СохраненныеНастройки, Новый Структура("Пользователь,ИмяОбъекта,НаименованиеНастройки",Пользователь,ИмяОбъекта,НаименованиеНастройки));
Вот и сама функция:
//Создает набор записей независимого непериодического регистра сведений
//Параметры:
//Менеджер - менеджер региста сведений
//СтруктураОтбора - структура, содержащая измерения отбора для набора записей
Функция СоздатьНаборЗаписейНезависимогоРС(Менеджер,СтруктураОтбора) Экспорт
  
 НЗ = Менеджер.СоздатьНаборЗаписей();
 
 Для каждого Эл Из НЗ.Отбор Цикл
  ЗначениеОтбора = Неопределено;
  Если СтруктураОтбора.Свойство(Эл.Имя,ЗначениеОтбора) Тогда
   Эл.Установить(ЗначениеОтбора);
  КонецЕсли; 
 КонецЦикла; 
 
 Возврат НЗ;
 
КонецФункции
Для периодических РС в структуру отбора можно добавить период.
Наборы записей регистров (любых), подчиненных регистраторам. Вынуждены писать так:
НЗ = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
НЗ.Отбор.Регистратор.Установить(Ссылка);
Считаю более удобной запись такую:
НЗ = СоздатьНаборЗаписейРегистратора(РегистрыСведений.ЦеныНоменклатуры,Ссылка);
И соответствующая функция:
Функция СоздатьНаборЗаписейРегистратора(Менеджер,Регистратор) Экспорт
  
 НЗ = Менеджер.СоздатьНаборЗаписей();
 НЗ.Отбор.Регистратор.Установить(Ссылка); 
 Возврат НЗ;
 
КонецФункции 
Наконец совершенно непонятно из каких соображений нужно принудительно заполнять измерения/период/регистратор по которым делается отбор, если все равно нельзя записать набор несоответствующий отбору? Добавим соответствующую процедуру:
//Записывает набор записей с установленными отборами
//Параметры:
//НЗ - набор записей
//Замещать - режим замещения существующих записей, необязательный
Процедура ЗаписатьНаборЗаписей(НЗ,Замещать=Истина) Экспорт

 МассивЗаполнения =  Новый Массив(НЗ.Количество());
 Для каждого Эл Из НЗ.Отбор Цикл
  Если Эл.Использование Тогда
   Для й=0 По МассивЗаполнения.ВГраница() Цикл
    МассивЗаполнения[й] = Эл.Значение;   
   КонецЦикла; 
   НЗ.ЗагрузитьКолонку(МассивЗаполнения,Эл.Имя);
  КонецЕсли; 
 КонецЦикла; 
 НЗ.Записать(Замещать);

КонецПроцедуры

среда, 11 сентября 2013 г.

Альтернатива периодическому регистру сведений в клиент-серверной базе данных 1С 8

Как известно в 1С 8 виртуальная таблица "срез последних" периодического регистра сведений раскрывается в подзапрос, составленный из таблицы регистра, соединенной сама с собой. То есть вот это

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


превращает платформа 1С примерно в такой запрос:

ВЫБРАТЬ
ЦеныНоменклатуры.Номенклатура,
ЦеныНоменклатуры.Валюта,
ЦеныНоменклатуры.Цена,
ЦеныНоменклатуры.ЕдиницаИзмерения
ИЗ
(ВЫБРАТЬ
ЦеныНоменклатуры.Номенклатура КАК Номенклатура,
ЦеныНоменклатуры.ТипЦен КАК ТипЦен,
МАКСИМУМ(ЦеныНоменклатуры.Период) КАК Период
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
ГДЕ
ЦеныНоменклатуры.Период <= &Дата
И ЦеныНоменклатуры.ТипЦен = &ТипЦен
СГРУППИРОВАТЬ ПО
ЦеныНоменклатуры.Номенклатура,
ЦеныНоменклатуры.ТипЦен) КАК ВложенныйЗапрос
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
ПО ВложенныйЗапрос.Номенклатура = ЦеныНоменклатуры.Номенклатура
И ВложенныйЗапрос.ТипЦен = ЦеныНоменклатуры.ТипЦен
И ВложенныйЗапрос.Период = ЦеныНоменклатуры.Период

Аналогичные вещи приходится писать и в случае "среза последних на каждую дату в запросе": Классический вариантАльтернативный и их сравнение.
Гораздо удобнее были бы запросы такого вида:

ВЫБРАТЬ
ЦеныНоменклатуры.Номенклатура,
ЦеныНоменклатуры.Валюта,
ЦеныНоменклатуры.Цена,
ЦеныНоменклатуры.ЕдиницаИзмерения
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
ГДЕ
ЦеныНоменклатуры.ТипЦен = &ТипЦен
И &Дата МЕЖДУ ЦеныНоменклатуры.Период И ЦеныНоменклатуры.ПериодОкончания

Но что это за поле ПериодОкончания и как оно должно быть заполнено?
Это был добавлен реквизит регистра сведений с типом "ДатаВремя". Ни в коем случае это поле не должно быть измерением, но вполне могло быть ресурсом, ведь в запросах ресурсы и реквизиты регистра сведений ничем не различимы. Реквизитом, а не ресурсом оно сделано чисто из эстетических принципов )). Зато встроенный механизм виртуальной таблицы "срез последних" нисколько не поврежден и может по-прежнему использоваться.
Заполняется "период окончания" согласно правилу: Если есть запись с тем же набором измерений, стоящая следующей в хронологии, то берется её период за вычетом одной секунды, в противном случае решено было взять дату 01.01.3000. Пример значений периодов таблицы по одному набору измерений:

Период ПериодОкончания
13.07.09 0:00:00 07.09.09 23:59:59
08.09.09 0:00:00 13.09.09 23:59:59
14.09.09 0:00:00 13.12.09 23:59:59
14.12.09 0:00:00 15.03.10 23:59:59
16.03.10 0:00:00 18.07.10 23:59:59
19.07.10 0:00:00 09.09.10 23:59:59
10.09.10 0:00:00 15.11.10 23:59:59
16.11.10 0:00:00 17.04.11 23:59:59
18.04.11 0:00:00 10.07.11 23:59:59
11.07.11 0:00:00 03.10.11 23:59:59
04.10.11 0:00:00 19.01.12 23:59:59
20.01.12 0:00:00 21.10.12 23:59:59
22.10.12 0:00:00 01.01.3000 0:00:00

Естественно это поле должно заполняться автоматически. А значит  нужно использовать события модуля набора записей ПередЗаписью и ПриЗаписи. Но так как база клиент-серверная в привязке с MS SQL Server, то воспользовались триггерами СУБД After Insert/Update/Delete. Впрочем триггер AfterUpdate был для перестраховки - 1С не изменяет записи регистра сведений, она их удаляет и вставляет заново. Вот пример триггера After Insert.
Индексирование реквизита средствами 1С привело к созданию составного индекса: Период+Все измерения. Помимо этого был добавлен индекс средствами SQL: Период+ПериодОкончания+Период окончания.
Да, все эти манипуляции приводят к уменьшению скорости записи, но когда запись происходит гораздо реже чтения, то затраты оправданы.
Аналогичная операция была сделана с курсами валют. Проведены тесты (1000 выполнений запроса) с разными параметрами на запросах:
1. Стандартные срезы:

ВЫБРАТЬ
ЦеныНоменклатурыСрезПоследних.Номенклатура,
ЦеныНоменклатурыСрезПоследних.Цена * КурсыВалютСрезПоследних.Курс / ЦеныНоменклатурыСрезПоследних.ЕдиницаИзмерения.Коэффициент КАК Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата,
ТипЦен = &ТипЦен
И Номенклатура В ИЕРАРХИИ (&Номенклатура)) КАК ЦеныНоменклатурыСрезПоследних
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют.СрезПоследних(&Дата, ) КАК КурсыВалютСрезПоследних
ПО ЦеныНоменклатурыСрезПоследних.Валюта = КурсыВалютСрезПоследних.Валюта

2. Модифицированные регистры:

ВЫБРАТЬ
ЦеныНоменклатуры.Номенклатура,
ЦеныНоменклатуры.Цена * КурсыВалют.Курс / ЦеныНоменклатуры.ЕдиницаИзмерения.Коэффициент КАК Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют КАК КурсыВалют
ПО ЦеныНоменклатуры.Валюта = КурсыВалют.Валюта
И (&Дата МЕЖДУ ЦеныНоменклатуры.Период И КурсыВалют.ПериодОкончания)
ГДЕ
&Дата МЕЖДУ ЦеныНоменклатуры.Период И ЦеныНоменклатуры.ПериодОкончания
И ЦеныНоменклатуры.ТипЦен = &ТипЦен
И ЦеныНоменклатуры.Номенклатура В ИЕРАРХИИ(&Номенклатура)

Срез последних Модификация   Экономия времени,   %
0,235 0,191 18,72
0,232 0,199 14,22
0,228 0,206 9,65
0,210 0,189 10,00
Замечание 1: срез последних без указания параметра даты, это срез на самую последнюю дату в таблице. У нас это запрос:

ВЫБРАТЬ
ЦеныНоменклатуры.Номенклатура,
ЦеныНоменклатуры.Валюта,
ЦеныНоменклатуры.Цена,
ЦеныНоменклатуры.ЕдиницаИзмерения
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
ГДЕ
ЦеныНоменклатуры.ТипЦен = &ТипЦен
И ЦеныНоменклатуры.ПериодОкончания=ДАТАВРЕМЯ(3000,1,1)

Замечание 2: все записи считаются активными..
Замечание 3: здесь не рассматривается случай периодичности "позиция регистратора".

четверг, 5 сентября 2013 г.

Жесткая связанность таблиц и реструктуризация таблиц в 1С 8

Речь идёт о  проблеме уменьшения жесткой связанности таблиц через реструктуризацию. Сразу скажу, что отнюдь не призываю крушить типовые конфигурации, однако пример возьму из типовых, потому как они знакомы всем и каждому.

Как известно в типовых справочники Контрагенты и Договоры контрагентов жестко связаны. Договор ссылается на Контрагента, как владельца, в свою очередь контрагент ссылается на основной договор.

Попробуем избавиться от жесткой связи, вынеся отношение "основной договор" в отдельный регистр сведений. Измерением будет "хвост" отношения - контрагент, а ресурсом "остриё" - договор. Не забываем и про связь по владельцу.

А в чем же бонус этих манипуляций? А в том, что это отношение можно более гибко расширять, например сделать "основной договор" для каждой из организаций.


Надеюсь нарисовал и написал понятно.