Имя: Пароль:
1C
1С v8
Можно ли запросом "свернуть" таблицу периодов?
,
0 nvs
 
05.03.14
08:20
Есть таблица из двух колонок: дата начала, дата окончания.
Надо свернуть таблицу так, чтобы в итоге остались непересекаемые между собой периоды.
Например:
периоды (01.01.2012 - 31.12.2012) и (01.01.2013 - 31.12.2013) должны сложиться в (01.01.2012 - 31.12.2013)

периоды (01.01.2012 - 31.08.2012) и (01.07.2012 - 31.12.2012) должны свернуться в (01.01.2012 - 31.12.2012)

Можно это сделать одним запросом?
1 butterbean
 
05.03.14
08:32
(0) в твоем примере в итоге должен остаться только период (01.01.2012 - 31.12.2013) , правильно??
2 shuhard
 
05.03.14
08:34
(0)[Можно это сделать одним запросом?]
в общем случае - нет
3 catena
 
05.03.14
09:19
А если периоды (01.01.2012 - 30.11.2012) и (01.01.2013 - 31.12.2013) ?
4 mikecool
 
05.03.14
09:20
(0) началопериода(год) и складывай
5 nvs
 
05.03.14
09:28
(1) - да в итоге один период останется, но в общем случае может быть множество непересекаемых периодов
(3) - в это м случае в итоговой таблице останется два периода, поскольку они не пересекаются и не соприкасаются

(2) - тоже так кажется
6 catena
 
05.03.14
10:20
Дайте примеров.

ВЫБРАТЬ
    Отрезки.А КАК А,
    Отрезки.Б КАК Б
Поместить тз
Из &Отрезки КАК Отрезки;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    тз.А,
    Максимум(тз2.Б) как Б
Поместить тзОбъединенныеОтрезки    
Из тз КАК тз
    Левое Соединение тз как тз2 по (тз.Б >= ДобавитьКДате(тз2.А,День,-1) и тз.Б<=тз2.Б)
Сгруппировать по тз.А;
////////////////////////////////////////////////////////////////////////////////
Выбрать тз.А,тз.Б из тзОбъединенныеОтрезки как тз
Левое Соединение тзОбъединенныеОтрезки как тз2 по (тз2.А<тз.А и тз.Б между тз2.А и тз2.Б)или(тз2.Б>тз.Б и тз.А между тз2.А и тз2.Б)
Где тз2.А есть NULL
7 grigo
 
05.03.14
10:29
Запросом в общем случае не решается.
8 nvs
 
05.03.14
10:32
(6) тут есть такая проблема: после первого выполнения данного запроса появится новая таблица периодов, которые также могут свернуться.
тут как-то булеву матрицу пересечений периодов надо строить или что-то в этом духе...
9 George Wheels
 
05.03.14
10:36
(8) Сделай рекурсивный вызов или запрос в цикле. Сравнивай количество строк в ТЗ до обработки запросом и после. Если количество строк одинаково, то все периоды свернулись.
10 catena
 
05.03.14
11:01
(8)Не поняла, какая новая таблица? Я отбираю периоды, которые не вложены ни в один другой. Может где накосячила, дайте пример с недосвернутыми оборотами.
11 kumena
 
05.03.14
11:12
>>> периоды (01.01.2012 - 31.12.2012) и (01.01.2013 - 31.12.2013) должны сложиться в (01.01.2012 - 31.12.2013)

я такое делал запросом, результат можно посмотреть здесь
http://www.kumena.ru/products/pechatnaya-forma-t-6-alternativnaya-zup-25



>>> периоды (01.01.2012 - 31.08.2012) и (01.07.2012 - 31.12.2012) должны свернуться в (01.01.2012 - 31.12.2012)

думаю что тоже можно, но на халяву думать не интересно.
12 nvs
 
05.03.14
11:22
(10)ваш алгоритм попробуйте на данных:
15.06.1987    21.04.2005
01.09.2000    01.05.2005
01.05.2005    31.08.2006
01.09.2006    11.09.2008
12.09.2008    31.12.2013
02.02.2009    01.02.2010
не срастается
13 catena
 
05.03.14
12:40
(12)Ага.
Идея такая:
тзТочки - собираем вообще все точки из наших периодов.
тзОтрезкиПоПорядку - это все отрезки между нашими точками.
тзНевходящиеОтрезки - находим среди отрезков по порядку те, которые не входят ни в один период.
тзОбъединенныеОтрезки - вообще все варианты отрезков из наших точек, исключая отрезки, которые содержат никуда невходящие периоды.
Итог - из всех отрезков выбираем самые большие, т.е. те, которые не входят ни в один другой отрезок.


ВЫБРАТЬ
    Отрезки.А КАК А,Отрезки.Б КАК Б
ПОМЕСТИТЬ тз
ИЗ &Отрезки КАК Отрезки;
///////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ точка
ПОМЕСТИТЬ тзТочки
из (Выбрать Отрезки.А КАК Точка ИЗ тз КАК Отрезки ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ Отрезки.Б ИЗ тз КАК Отрезки) как Отр;
///////////////////////
ВЫБРАТЬ КрайА.Точка КАК А,МИНИМУМ(КрайБ.Точка) КАК Б
ПОМЕСТИТЬ тзОтрезкиПоПорядку
ИЗ тзТочки КАК КрайА ЛЕВОЕ СОЕДИНЕНИЕ тзТочки КАК КрайБ    ПО КрайА.Точка<КрайБ.Точка СГРУППИРОВАТЬ ПО КрайА.Точка
имеющие КрайА.Точка<>ДобавитьКДате(МИНИМУМ(КрайБ.Точка),День,-1);
///////////////////////
ВЫБРАТЬ различные тзОтрезкиПоПорядку.А,тзОтрезкиПоПорядку.Б
Поместить тзНевходящиеОтрезки    
ИЗ тзОтрезкиПоПорядку КАК тзОтрезкиПоПорядку
    Левое соединение тз по
            тзОтрезкиПоПорядку.А между тз.А и тз.Б
            и тзОтрезкиПоПорядку.Б между тз.А и тз.Б
где (тз.А есть NULL или тз.Б есть NULL);
///////////////////////
Выбрать ВащеВсеотрезки.а,ВащеВсеотрезки.б
Поместить тзОбъединенныеОтрезки    
из (Выбрать тз1.Точка как А,тз2.Точка как Б
из тзТочки как тз1, тзТочки как тз2
Где тз1.Точка< ДобавитьКДате(тз2.Точка,День,-1)) как ВащеВсеотрезки
Левое соединение тзНевходящиеОтрезки как тзНевходящиеОтрезки по
(тзНевходящиеОтрезки.а>ВащеВсеотрезки.А и тзНевходящиеОтрезки.а<ВащеВсеотрезки.Б)
или (тзНевходящиеОтрезки.б>ВащеВсеотрезки.А и тзНевходящиеОтрезки.б<ВащеВсеотрезки.Б)
или (тзНевходящиеОтрезки.а=ВащеВсеотрезки.А и тзНевходящиеОтрезки.б=ВащеВсеотрезки.Б)
Где тзНевходящиеОтрезки.А есть NULL или тзНевходящиеОтрезки.Б есть NULL;
///////////////////////
Выбрать тз.А,тз.Б из тзОбъединенныеОтрезки как тз
Левое Соединение тзОбъединенныеОтрезки как тз2 по (тз2.А<тз.А и тз.Б между тз2.А и тз2.Б)или(тз2.Б>тз.Б и тз.А между тз2.А и тз2.Б)
Где тз2.А есть NULL
14 nvs
 
05.03.14
13:20
(13) ага вроде рабочий вариант, сейчас еще по полочкам у себя в голове разложу запрос. Большое спасибо!
15 kosts
 
05.03.14
13:26
(0)
1. Создаем служебную ВТ с календарем.
2. Соединяем свои периоды с календарем. Для дней которые попали в период ставим в новом поле - 1, для тех дней, которые  не попали - 0. Имеем календарь дней, назовем График.
Например, получим:
ДатаКалендаря, Поле1
1.1.2012, 0
2.1.2012, 0
3.1.2012, 1
4.1.2012, 1
5.1.2012, 0
6.1.2012, 0

3. Теперь соединяя и группируя Календарю из (1) и График из (2), условие соединения: к дню из календаря присоединим СЛЕДУЮЩИЙ день из Графика. Этим мы найдем граничные дни.
Например должны получить:
ДатаС, Поле1
1.1.2012, 0
3.1.2012, 1
5.1.2012, 0

4. Теперь соединяя саму с собой таблицу (3), группируя и минимизируя получим
ДатаС, ДатаПо, Поле1
1.1.2012, 2.1.2012, 0
3.1.2012, 4.1.2012, 1
5.1.2012, 31.12.2012, 0

Может в (13) и такой же принцип, но анализировать лень...
16 catena
 
05.03.14
13:30
(15)Не, вариант с подсчетом попадающих точек я не стала доделывать еще когда объем пересекающихся кубов считали. Не помню почему)
17 kosts
 
05.03.14
14:36
Другой вариант, найти периоды пустот

ВЫБРАТЬ
    ВТПериоды.ДатаС,
    ВТПериоды.ДатаПо,
    ДОБАВИТЬКДАТЕ(ВТПериоды.ДатаПо, ДЕНЬ, 1) КАК ДатаНачалаПустоты
ПОМЕСТИТЬ ВТПериоды2
ИЗ
    ВТПериоды КАК ВТПериоды
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТПериоды2.ДатаНачалаПустоты,
    МИНИМУМ(ДОБАВИТЬКДАТЕ(ВТПериоды.ДатаС, ДЕНЬ, -1)) КАК ДатаОкончанияПустоты
ПОМЕСТИТЬ ВТПериодыПустот
ИЗ
    ВТПериоды2 КАК ВТПериоды2
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТПериоды2 КАК ВТПериоды
        ПО ВТПериоды2.ДатаНачалаПустоты <= ВТПериоды.ДатаПо

СГРУППИРОВАТЬ ПО
    ВТПериоды2.ДатаНачалаПустоты

ИМЕЮЩИЕ
    ВТПериоды2.ДатаНачалаПустоты <= МИНИМУМ(ДОБАВИТЬКДАТЕ(ВТПериоды.ДатаС, ДЕНЬ, -1))

Затем из общего периода убрать пустоты, получим нужные итоговые периоды. (уже лень опять стало делать).
18 kosts
 
05.03.14
14:59
(17)+ Т.е. что бы получить итоговые периоды нужно добавить 2 искусственных периода сверху и снизу и сделать совершенные аналогичные действия как в (17).
19 nvs
 
05.03.14
15:11
Вот чего я накопал:
Построил матрицу связей периодов (по вертикали периоды, по горизонтали тоже, элемент матрицы = 1 если периоды граничат или пересекаются, иначе 0).
Далее необходимо построить матрицу достижимости
Элементы матрицы достижимости по Алгоритму Флойда — Уоршелла
for k = 1 to n
  for i = 1 to n
    for j = 1 to n
      W[i][j] = W[i][j] or (W[i][k] and W[k][j])

Далее клеим по этой матрице наши периоды и выбираем минимумы дат начала и максимум дат окончания

только вот этот цикл в запросом выполнить надо
20 nvs
 
05.03.14
15:12
и еще вариант:
ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 1, 1) КАК НачалоПериода,
ДАТАВРЕМЯ(2014, 1, 5) КАК КонецПериода
ПОМЕСТИТЬ Т

ОБЪЕДИНИТЬ

ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 1, 3),
ДАТАВРЕМЯ(2014, 1, 10)

ОБЪЕДИНИТЬ

ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 1, 15),
ДАТАВРЕМЯ(2014, 1, 25)
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
0 КАК Цифра
ПОМЕСТИТЬ СписокЦифр

ОБЪЕДИНИТЬ

ВЫБРАТЬ
1

ОБЪЕДИНИТЬ

ВЫБРАТЬ
2

ОБЪЕДИНИТЬ

ВЫБРАТЬ
3

ОБЪЕДИНИТЬ

ВЫБРАТЬ
4

ОБЪЕДИНИТЬ

ВЫБРАТЬ
5

ОБЪЕДИНИТЬ

ВЫБРАТЬ
6

ОБЪЕДИНИТЬ

ВЫБРАТЬ
7

ОБЪЕДИНИТЬ

ВЫБРАТЬ
8

ОБЪЕДИНИТЬ

ВЫБРАТЬ
9
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
ДОБАВИТЬКДАТЕ(Т.НачалоПериода, ДЕНЬ, ЦифрыПорядка3.Цифра * 1000 + ЦифрыПорядка2.Цифра * 100 + ЦифрыПорядка1.Цифра * 10 + ЦифрыПорядка0.Цифра) КАК Дата
ПОМЕСТИТЬ Т2
{ВЫБРАТЬ
Дата}
ИЗ
Т КАК Т,
СписокЦифр КАК ЦифрыПорядка3,
СписокЦифр КАК ЦифрыПорядка2,
СписокЦифр КАК ЦифрыПорядка1,
СписокЦифр КАК ЦифрыПорядка0
ГДЕ
ЦифрыПорядка3.Цифра * 1000 + ЦифрыПорядка2.Цифра * 100 + ЦифрыПорядка1.Цифра * 10 + ЦифрыПорядка0.Цифра <= РАЗНОСТЬДАТ(Т.НачалоПериода, Т.КонецПериода, ДЕНЬ)
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Т2_11.Дата
ПОМЕСТИТЬ НачалаПериодов
ИЗ
Т2 КАК Т2_11
ЛЕВОЕ СОЕДИНЕНИЕ Т2 КАК Т2_21
ПО (Т2_11.Дата = ДОБАВИТЬКДАТЕ(Т2_21.Дата, ДЕНЬ, 1))
ГДЕ
Т2_21.Дата ЕСТЬ NULL
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
НачалаПериодов.Дата,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ НачалаПериодов1.Дата) КАК НомерСтроки
ПОМЕСТИТЬ НачалаПериодовСНомеромСтроки
ИЗ
НачалаПериодов КАК НачалаПериодов
ВНУТРЕННЕЕ СОЕДИНЕНИЕ НачалаПериодов КАК НачалаПериодов1
ПО НачалаПериодов.Дата >= НачалаПериодов1.Дата

СГРУППИРОВАТЬ ПО
НачалаПериодов.Дата
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Т2_11.Дата
ПОМЕСТИТЬ КонцыПериодов
ИЗ
Т2 КАК Т2_11
ЛЕВОЕ СОЕДИНЕНИЕ Т2 КАК Т2_21
ПО (Т2_11.Дата = ДОБАВИТЬКДАТЕ(Т2_21.Дата, ДЕНЬ, -1))
ГДЕ
Т2_21.Дата ЕСТЬ NULL
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
КонцыПериодов.Дата,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ КонцыПериодов1.Дата) КАК НомерСтроки
ПОМЕСТИТЬ КонцыПериодовСНомеромСтроки
ИЗ
КонцыПериодов КАК КонцыПериодов
ВНУТРЕННЕЕ СОЕДИНЕНИЕ КонцыПериодов КАК КонцыПериодов1
ПО КонцыПериодов.Дата >= КонцыПериодов1.Дата

СГРУППИРОВАТЬ ПО
КонцыПериодов.Дата
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
НачалаПериодовСНомеромСтроки.Дата КАК НачалоПериода,
КонцыПериодовСНомеромСтроки.Дата КАК КонецПериода
ИЗ
НачалаПериодовСНомеромСтроки КАК НачалаПериодовСНомеромСтроки
ВНУТРЕННЕЕ СОЕДИНЕНИЕ КонцыПериодовСНомеромСтроки КАК КонцыПериодовСНомеромСтроки
ПО НачалаПериодовСНомеромСтроки.НомерСтроки = КонцыПериодовСНомеромСтроки.НомерСтроки
21 catena
 
06.03.14
06:35
Вариант (15) будет выглядеть так:
Выбрать 0 как ч поместить линейка1 объединить все выбрать 1 объединить все выбрать 2 объединить все выбрать 3 объединить все выбрать 4;
Выбрать различные л6.ч*3125+л5.ч*625+л4.ч*125+л3.ч*25+л2.ч*5+л1.ч как ч поместить линейка из линейка1 как л1,линейка1 как л2,линейка1 как л3,линейка1 как л4,линейка1 как л5,линейка1 как л6;
///////////////////////
ВЫБРАТЬ
    Отрезки.А КАК А,Отрезки.Б КАК Б
ПОМЕСТИТЬ тз
ИЗ &Отрезки КАК Отрезки;
///////////////////////
ВЫБРАТЬ
    ДобавитьКДате(Минимум(Отрезки.А),День,-1) как минА,ДобавитьКДате(Максимум(Отрезки.Б),День,1) КАК максБ
ПОМЕСТИТЬ Минимакс
ИЗ тз КАК Отрезки;
///////////////////////
Выбрать ДобавитьКДате(Минимакс.МаксБ,День,-линейка.ч) как ДатаКалендаря
Поместить тзКалендарь
из Минимакс как Минимакс,линейка как линейка
Где ДобавитьКДате(Минимакс.МаксБ,День,-линейка.ч)>=Минимакс.МинА;
///////////////////////
Выбрать ДатаКалендаря, Выбор когда ДатаКалендаря между тз.А и тз.Б тогда 1 иначе 0 конец как Попадание
Поместить тзГрафик
из тзКалендарь как тзКалендарь
Левое соединение тз как тз по ДатаКалендаря между тз.А и тз.Б;
///////////////////////
Выбрать  тзГрафик.ДатаКалендаря,тзГрафик.Попадание
Поместить тзГраничныеДни
из тзГрафик как тзГрафик
Левое соединение тзГрафик как СледДень
по тзГрафик.ДатаКалендаря=ДобавитьКДате(СледДень.ДатаКалендаря,День,1)
Где тзГрафик.Попадание<>СледДень.Попадание;
///////////////////////
Выбрать тзГраничныеДни.ДатаКалендаря как А, ДобавитьКДАте(Минимум(СледПериод.ДатаКалендаря),День,-1) как Б
из тзГраничныеДни как тзГраничныеДни
Левое Соединение тзГраничныеДни как СледПериод по
тзГраничныеДни.ДатаКалендаря<СледПериод.ДатаКалендаря
Где тзГраничныеДни.Попадание=1
Сгруппировать по тзГраничныеДни.ДатаКалендаря
22 APXi
 
06.03.14
07:56
Интересно как потом такие запросы сопровождать, особенно если нет описания.
Компьютеры — прекрасное средство для решения проблем, которых до их появления не было.