Oberon space

General Category => Общий раздел => Тема начата: ilovb от Август 02, 2012, 01:02:04 pm

Название: Продолжаем тему правильных циклов (реальная задача из
Отправлено: ilovb от Август 02, 2012, 01:02:04 pm
Как бы вы решали такую задачу?:
Дана таблица.
Колонки:
1. Сотрудник
2. Вид начисления
3. Дата начала
4. Дата окончания

3 и 4 - это период действия начисления (2) по данному сотруднику (1)

например:

1 | 1 | 01.01.2012 | 10.01.2012
1 | 1 | 20.01.2012 | 24.01.2012
2 | 1 | 05.01.2012 | 10.01.2012
2 | 2 | 10.02.2012 | 13.06.2012

По сотруднику #1 были начисления #1 в периодах с 01.01.2012 по 10.01.2012 и с 20.01.2012 по 24.01.2012
По сотруднику #2 было начисление #1 в периоде с 05.01.2012 по 10.01.2012, а также начисление #2 в периоде с 10.02.2012 по 13.06.2012

Все даты в таблице находятся в пределах одного года. Периоды могут пересекаться даже по одному тому же сотруднику и начислению.
например:

1 | 1 | 01.01.2012 | 10.01.2012
1 | 1 | 05.01.2012 | 24.01.2012

Нужно получить результат в виде таблицы с колонками:
1. Сотрудник
2. Вид начисления
3. Количество дней (с учетом пересечений периодов)

например для таблицы:

1 | 1 | 01.01.2012 | 10.01.2012
1 | 1 | 05.01.2012 | 24.01.2012
2 | 1 | 05.01.2012 | 10.01.2012
2 | 2 | 10.02.2012 | 13.02.2012

результат будет:

1 | 1 | 23
2 | 1 | 5
2 | 2 | 3

Для простоты можно полагать, что исходная таблица отсортирована по первым двум полям.
Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: alexus от Август 02, 2012, 01:06:19 pm
Для простоты можно полагать, что исходная таблица отсортирована по первым двум полям.
Сортировать надо, как минимум по трём первым полям, или даже по четырём... если для простоты.
Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: DIzer от Август 02, 2012, 01:26:45 pm
... а после сортировки см http://oberspace.dyndns.org/index.php/topic,288.0.html (http://oberspace.dyndns.org/index.php/topic,288.0.html)  - любым  методом (в зависимости от степени личной извращенности)
Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: ilovb от Август 02, 2012, 01:29:48 pm
Для простоты можно полагать, что исходная таблица отсортирована по первым двум полям.
Сортировать надо, как минимум по трём первым полям, или даже по четырём... если для простоты.

Да как угодно в общем.
Вопрос старый: Какой цикл самый правильный? (и нужен ли тут цикл вообще)
Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: Peter Almazov от Август 02, 2012, 01:40:55 pm
Выходные и праздники, видимо, надо исключить?
Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: ilovb от Август 02, 2012, 01:42:34 pm
В реальной задаче нужно было. Но тут не надо.
Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: albobin от Август 02, 2012, 01:43:39 pm
Вопрос старый: Какой цикл самый правильный?
Самый правильный это в МАМПСе, потому что я в нём работаю и эта задачка решается  там влёт без особых мозговых усилий  :D
Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: ilovb от Август 02, 2012, 01:48:54 pm
Код в студию!
Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: albobin от Август 02, 2012, 01:59:42 pm
Ну, код может убить впечатлительного человека.   :)
А словами можно описать так, естественно используя привычную мне терминологию.

Есть исходный массив (сортирован или не сортирован значения не имеет)
Перебирая все записи этого массива (получая при этом #чела,  #начисл, дата_с, дата_по)
Пишем в временный массив TMP(#чела,#начисл)  строку флагов дней в году
Затем перебирая этот массив заменяем строку флагов на к-во единиц в строке

Грубо говоря - две строки на МАМПСе

Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: valexey от Август 02, 2012, 02:01:35 pm
Ну, код может убить впечатлительного человека.   :)
Да, код на мапсе лучше в пятницу публиковать, ближе к вечеру :-)
Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: ilovb от Август 02, 2012, 02:03:27 pm
Ну вы прям классическое решение задачи о покрытиях описали.  :)

Может кто иначе решение предложит.

ps А код все равно хотелось бы увидеть (тем более на таком экзотичном языке)
Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: DIzer от Август 02, 2012, 02:12:35 pm
SELECT Sotr, Nach, count(Nach) FROM TABLE
GROUP BY Sotr, Nach
WHERE  Data not in [...] //  исключение праздников
ORDER BY Sotr, Nach
- где то так...
Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: DIzer от Август 02, 2012, 02:19:07 pm
разумеется это решение верно ТОЛЬКО в том случае когда в один день сотруднику было сделано не более одного однотипного начисления...
Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: ilovb от Август 02, 2012, 02:20:32 pm
Но это не решение поставленной задачи.
Нужно считать дни в периодах.
Название: Продолжаем тему правильных циклов
Отправлено: ilovb от Август 02, 2012, 02:23:54 pm
На SQL в общем решается так же как описал albobin. (с привлечением дополнительной таблицы-календаря, или, иначе говоря, тупо списка всех дней в году)
Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: albobin от Август 02, 2012, 02:37:14 pm
Примерно так:
оформлен код как процедура 'babki'
src  -  ref на исходный массив 
dst  - ref на результирующий массив
date0 - первый день года
все даты в примере  во внутренней форме (номер дня  с определённой  даты 19 века :)
babki(src,dst,date0)
  N (src,dst,date0)
  S s="|"
  S i=$o(@src@(""))
  F  S i=$o(@src@(i))  Q:i=""   S t=@src@(i)  D
  . S chel=$p(t,s,1),babki=$p(t,s,2),from=$p(t,s,3),to=$p(t,s,4)
  . S $e(@dst@(chel,babki),from-date0+1,to-date0+1)=$tr($j("",to-from+1)," ","1")
  S (chel,babki)=""
  F  S chel=$o(@dst@(chel))  Q:chel=""  D
  .  F  S babki=$o(@dst@(chel,babki))  Q:babki=""    S @dst@(chel,babki)=$l(@dst@(chel,babki),"1")-1
  Q

Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: DIzer от Август 02, 2012, 02:40:54 pm
Но это не решение поставленной задачи.
Нужно считать дни в периодах.
:) точно , а так?
SELECT Sotr, Nach, max(Data_Fin-Data_Nach) FROM TABLE
GROUP BY Sotr, Nach
ORDER BY Sotr, Nach
Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: ilovb от Август 02, 2012, 02:44:01 pm
И так не так :)

Что будет в результате, если два периода (по данному сотр. и нач.) не пересекаются?
Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: DIzer от Август 02, 2012, 03:06:52 pm
 :) :) :)  тогда самым простым будет банальное создание псевдо набора (представления)
SELECT Sotr, Nach, Data_Nach, Data_Fin FROM TABLE
ORDER BY Sotr, Nach, Data_Nach
и цикл по этому набору в хранимой процедуре...
с чего начали тем и закончили  ;D
Название: Re: Продолжаем тему правильных циклов (реальная задача
Отправлено: albobin от Август 02, 2012, 07:23:38 pm
Исправить сразу 4 строку не успел, время вышло.
babki(src,dst,date0)
  N (src,dst,date0)
  S s="|"
  S i=""
  F  S i=$o(@src@(i))  Q:i=""   S t=@src@(i)  D
  . S chel=$p(t,s,1),babki=$p(t,s,2),from=$p(t,s,3),to=$p(t,s,4)
  . S $e(@dst@(chel,babki),from-date0+1,to-date0+1)=$tr($j("",to-from+1)," ","1")
  S (chel,babki)=""
  F  S chel=$o(@dst@(chel))  Q:chel=""  D
  .  F  S babki=$o(@dst@(chel,babki))  Q:babki=""    S @dst@(chel,babki)=$l(@dst@(chel,babki),"1")-1
  Q