Каталог решений - Минимализмы 3

Минимализмы 3

Минимализмы 3

В наличии

Очередная серия «минимализмов» [http://infostart.ru/public/306536/, https://infostart.ru/public/460935/]. Также, как и в предыдущих статьях, здесь приведена подборка коротких оригинальных авторских решений некоторых задач. Ранее эти решения были разбросаны по моим комментариям к чужим публикациям.

Категория:

Описание

Содержание:

72. Очистка строки от нецифровых символов 
71. Определение суммарного покрытия перекрывающихся интервалов 
70. Определение пересечения интервалов в кольце 
69. Быстрое удаление строк в таблице значений 
68. Получение интервалов неизменности курсов валют 
67. Определение пропусков в последовательности чисел 
66. Инвертирование периодов в запросе 
65. Проверка совпадения таблиц 
64. Проверка совпадения таблиц путем сравнения полного и внутреннего соединения 
63. Получение списка простых чисел в запросе 
62. Определение периодов работы сотрудников по данным СКУД 
61. Найти документы, во всех строках которых колонка количество меньше либо равна нулю 
60. Определение плановых остатков товара с учетом предшествующих фактических и будущих плановых продаж 
59. Сравнение плановых и фактических дней отпуска 
58. Получить дату по номеру дня недели и его порядковому номеру в месяце 
57. Получение предпоследнего курса валюты 
56. Определить элементарные интервалы, образующиеся при пересечении всех исходных интервалов 
55. Найти количество записей, повторяющихся подряд несколько дней 
54. Сравнение набора товаров, проданных сменами 
53. Найти документ, состав табличной части которого соответствует параметру — таблице значений 
52. Распределение товаров по ячейкам в запросе 
51. Объединение пересекающихся периодов в запросе 
50. Выделение разрядов числа без использования округления и деления по модулю 
49. Посчитать запросом суммарную длительность различных состояний 
48. Разбиение произвольного периода на интервалы в запросе 
47. Поиск свободного штрихкода внутри одного префикса 
46. Выбор записи по номеру из НЕПРОНУМЕРОВАННОЙ таблицы 
45. Как в запросе секунды преобразовать в часы и минуты 
44. Убрать префикс и лидирующие нули из номера 
43. Перебор всех строковых комбинаций "0" и "1" в порядке возрастания числа единиц ("00000"->"00001"->"00010"-> …"01011"…) 
42. Транслитерация в запросе 
41. Заполнение пропусков в таблице цветов 
40. Количество дней недели (понедельников/вторников/…) в заданном диапазоне запросом 
39. Свернуть строки в таблице значений конкатенацией

 

72. Очистка номера телефона от "мусора" (нецифровых символов)

Ускорить код?

Очевидным решением этой задачи является организация цикла, в котором по одному просматриваются символы исходной строки и к результату добавляются символы, являющиеся цифрами. Но, во-первых, здесь требуется цикл, на организацию которого будет потрачено время, во-вторых, без стринг-билдера посимвольная конкатенация не эффективна.

В платформе 8.3.6 появились функции СтрРазделить и СтрСоединить, которые позволяют решить эту задачу в одну строку без цикла:

СтрСоединить(СтрРазделить(СтрокаСЦифрами, СтрСоединить(СтрРазделить(СтрокаСЦифрами, "0123456789"))))

 Если список ненужных символов известен, например, "(", ")" и "-", то выражение может быть еще короче:

СтрСоединить(СтрРазделить(СтрокаСЦифрами, "()-"))

 Очевидно, что данный прием легко обобщается на фильтрацию или отбор любого набора символов.

71. Определение суммарного покрытия перекрывающихся интервалов

За период получить количество дней, в которые проходило хотя бы одно мероприятие

Еще одна задача на интервалы (Gaps and Islands Problem). Имеется множество интервалов времени "занятости" помещений, оборудования, других ресурсов. Интервалы могут произвольным образом перекрываться. Требуется определить общее время занятости ресурсов.

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

Оказывается, что воспользовавшись идеями статьи "Расчет средних по периодам в запросе — это элементарно!", можно исключить необходимость второго соединения, поскольку суммарная занятость может быть определена как сумма расстояний до правого края "островов" минус сумма расстояний до левого края островов без необходимости определения длины каждого острова.

Если исходные интервалы  заданы в таблице "Дано" с колонками "ДатаНачала" и "ДатаОкончания", то общее время  занятости ресурсов в днях можно получить следующим достаточно простым запросом:

ВЫБРАТЬ
    СУММА(ВложенныйЗапрос.Разность) КАК ЗанятыхДней
ИЗ
    (ВЫБРАТЬ РАЗЛИЧНЫЕ
        1 - РАЗНОСТЬДАТ(ДАТАВРЕМЯ(1, 1, 1), Дано.ДатаНачала, ДЕНЬ) КАК Разность
    ИЗ
        Дано КАК Дано
            ЛЕВОЕ СОЕДИНЕНИЕ Дано КАК Левее
            ПО (Левее.ДатаНачала < Дано.ДатаНачала)
                И Дано.ДатаНачала <= Левее.ДатаОкончания
    ГДЕ
        Левее.ДатаНачала ЕСТЬ NULL

    ОБЪЕДИНИТЬ ВСЕ

    ВЫБРАТЬ РАЗЛИЧНЫЕ
        РАЗНОСТЬДАТ(ДАТАВРЕМЯ(1, 1, 1), Дано.ДатаОкончания, ДЕНЬ)
    ИЗ
        Дано КАК Дано
            ЛЕВОЕ СОЕДИНЕНИЕ Дано КАК Правее
            ПО (Правее.ДатаНачала <= Дано.ДатаОкончания)
                И Дано.ДатаОкончания < Правее.ДатаОкончания
    ГДЕ
        Правее.ДатаОкончания ЕСТЬ NULL) КАК ВложенныйЗапрос

Во вложенном запросе здесь определяются левые и правые края островов соответственно. Точнее, расстояние до этих краев от начала времен. Расстояние для левого края сразу берется с минусом.

Если занятость требуется измерять не в днях, а в часах, минутах, секундах и тому подобное, достаточно изменить параметр в функции "РазностьДат".

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

70. Определение пересечения интервалов в кольце

Вычисление пересекающихся интервалов в линейных и замкнутых пространствах имен

Пусть есть две смены: одна с 20:00 до 8: 00, а вторая с 6:00 до 18:00. Пересекаются ли они? Ответ на данный конкретный вопрос вроде бы вполне очевиден, а вот сформулировать общее правило оказывается совсем не так просто.

В результате  запрос, выбирающий смены, пересекающиеся с интервалом времени, заданными переменными @start  и @end, выглядит вот так:

select * from tab
where (@start - start) * (start - @end) * (@start - @end) <= 0 
      or (@start - start) * (@start - end) * (start - end) >= 0;

Это запрос на языке SQL. Для языка запросов 1С время начала и окончания смен потребуется заранее перевести в числовой тип (например, секунды) или использовать встроенную функцию языка запросов "РАЗНОСТЬДАТ".

Данный прием основан на эмуляции логического выражения XOR арифметическим произведением с оценкой знака получившегося результата. 

69. Быстрое удаление строк в таблице значений

Удаление строк в таблице значений

Быстрее всего удаляются строки путем копирования оставшихся строк по условию, обратному к условию удаления:

РабочаяТаблица = РабочаяТаблица.Скопировать(Новый Структура("КУдалению", Ложь))

68. Получение интервалов неизменности курсов валют

Запрос по курсам валют

ВЫБРАТЬ
    Дано.Период,
    Дано.Валюта,
    Дано.Курс,
    КОЛИЧЕСТВО(Было.Курс) КАК Номер
ПОМЕСТИТЬ Интервалы
ИЗ
    Дано КАК Дано
        ЛЕВОЕ СОЕДИНЕНИЕ Дано КАК Было
        ПО (Было.Валюта = Дано.Валюта)
            И (Было.Период <= Дано.Период)
            И (Было.Курс <> Дано.Курс)
СГРУППИРОВАТЬ ПО
    Дано.Период,
    Дано.Валюта,
    Дано.Курс
;
ВЫБРАТЬ
    МИНИМУМ(Интервалы.Период) КАК ДатаС,
    МАКСИМУМ(Интервалы.Период) КАК ДатаПо,
    Интервалы.Валюта,
    Интервалы.Курс
ИЗ
    Интервалы КАК Интервалы
СГРУППИРОВАТЬ ПО
    Интервалы.Валюта,
    Интервалы.Курс,
    Интервалы.Номер
УПОРЯДОЧИТЬ ПО
    Интервалы.Валюта,
    ДатаС

Как и в других подобных задачах, в этой ключ к решению — в выборе подходящего инварианта. Здесь инвариантом является количество отличающихся курсов перед данным.

Запрос составлялся без оглядки на эффективность. Если данных много и эффективность важна, то можно взять метод решения из http://catalog.mista.ru/public/402534/ . 

67. Определение пропусков в последовательности чисел

как в запросе найти дырку в последовательности чисел?

В обсуждении много разных вариантов решения. Из моих быстрее всего работает вот этот:

ВЫБРАТЬ ПЕРВЫЕ 2
    Дано.Х + ВЗ.У КАК Х
ИЗ
    Дано КАК Дано,
    (ВЫБРАТЬ
        0 КАК У    
    ОБЪЕДИНИТЬ
    ВЫБРАТЬ
        1) КАК ВЗ
СГРУППИРОВАТЬ ПО
    Дано.Х + ВЗ.У
ИМЕЮЩИЕ
    КОЛИЧЕСТВО(*) = 1
УПОРЯДОЧИТЬ ПО
    Дано.Х + ВЗ.У

В первой строке всегда 0, во второй нужное значение.

66. Инвертирование периодов в запросе

"Вывернуть" периоды в запросе

Есть запрос с выборкой периодов исключения: ДатаНачалаИсключения — ДатаОкончанияИсключения, а также основной период ДатаНачалаОсновная — ДатаОкончанияОсновная. Нужно составить запрос так, чтобы образовались периоды на основании основного периода, в которые не входят периоды исключения.

Вот решение:

ВЫБРАТЬ
    &ДатаНачалаОсновная КАК Дата
ПОМЕСТИТЬ Даты
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
    ДОБАВИТЬКДАТЕ(Дано.ДатаНачалаИсключения, ДЕНЬ, -1)
ИЗ
    Дано КАК Дано
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
    ДОБАВИТЬКДАТЕ(Дано.ДатаОкончанияИсключения, ДЕНЬ, 1)
ИЗ
    Дано КАК Дано
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
    &ДатаОкончанияОсновная
;
ВЫБРАТЬ
    МИНИМУМ(Даты.Дата) КАК ДатаНачала,
    МАКСИМУМ(Даты.Дата) КАК ДатаОкончания
ИЗ
    (ВЫБРАТЬ
        КОЛИЧЕСТВО(Раньше.Дата) КАК Номер,
        Даты.Дата КАК Дата
    ИЗ
        Даты КАК Раньше
            ВНУТРЕННЕЕ СОЕДИНЕНИЕ Даты КАК Даты
            ПО Раньше.Дата <= Даты.Дата
    СГРУППИРОВАТЬ ПО
        Даты.Дата) КАК Даты
СГРУППИРОВАТЬ ПО
    ВЫРАЗИТЬ(Даты.Номер / 2 КАК ЧИСЛО(10, 0))

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

65. Проверка совпадения таблиц

полное совпадение таблиц

Есть массив А из элементов некоторого справочника и есть справочник Б с табличной частью  из элементов того же справочника. Найти элемент Б, где список точно совпадает с массивом А (ни больше ни меньше).

На примере справочника "Контрагенты" (Как справочник Б). Приведенным далее запросом находятся контрагенты, у которых в табличной части имеются менеджеры из справочника "Пользователи" (Справочник А), список которых точно определен массивом &Массив. Требуется заранее определить размер массива и передать его в параметр &МассивКоличество.

ВЫБРАТЬ
	Менеджеры.Ссылка
ИЗ
	Справочник.Контрагенты.МенеджерыПокупателя КАК Менеджеры

СГРУППИРОВАТЬ ПО
	Менеджеры.Ссылка

ИМЕЮЩИЕ
	КОЛИЧЕСТВО(*) = &МассивКоличество И
	МИНИМУМ(Менеджеры.МенеджерПокупателя В (&Массив)) = ИСТИНА

64. Проверка совпадения таблиц путем сравнения полного и внутреннего соединения

ВЫБРАТЬ
	Товары.Номенклатура,
	Товары.Количество
ПОМЕСТИТЬ Эталон
ИЗ
	&Товары КАК Товары
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	Товары.Ссылка
ИЗ
	Документ.ЗаказПокупателя.Товары КАК Товары
		ПОЛНОЕ СОЕДИНЕНИЕ Эталон КАК Эталон
		ПО Товары.Номенклатура = Эталон.Номенклатура
			И Товары.Количество = Эталон.Количество

СГРУППИРОВАТЬ ПО
	Товары.Ссылка

ИМЕЮЩИЕ
	КОЛИЧЕСТВО(Товары.Номенклатура) МЕЖДУ КОЛИЧЕСТВО(*) И КОЛИЧЕСТВО(Эталон.Номенклатура)

Это более простой вариант сравнения таблиц с эталоном, чем, например, в 53. Здесь используется тот факт, что КОЛИЧЕСТВО(*) показывает общее количество строк полного соединения, а КОЛИЧЕСТВО(Товары.Номенклатура) и КОЛИЧЕСТВО(Эталон.Номенклатура) только число строк не ЕСТЬNULL. При совпадении таблиц все эти количества должны быть равны, что и проверяется самым коротким способом с использованием тернарного логического условия МЕЖДУ.

63. Получение списка простых чисел в запросе

Как получить список простых чисел в запросе

 

has been added to your cart:
Оформление заказа