Oberon space
General Category => Общий раздел => Тема начата: 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
Для простоты можно полагать, что исходная таблица отсортирована по первым двум полям.
-
Для простоты можно полагать, что исходная таблица отсортирована по первым двум полям.
Сортировать надо, как минимум по трём первым полям, или даже по четырём... если для простоты.
-
... а после сортировки см http://oberspace.dyndns.org/index.php/topic,288.0.html (http://oberspace.dyndns.org/index.php/topic,288.0.html) - любым методом (в зависимости от степени личной извращенности)
-
Для простоты можно полагать, что исходная таблица отсортирована по первым двум полям.
Сортировать надо, как минимум по трём первым полям, или даже по четырём... если для простоты.
Да как угодно в общем.
Вопрос старый: Какой цикл самый правильный? (и нужен ли тут цикл вообще)
-
Выходные и праздники, видимо, надо исключить?
-
В реальной задаче нужно было. Но тут не надо.
-
Вопрос старый: Какой цикл самый правильный?
Самый правильный это в МАМПСе, потому что я в нём работаю и эта задачка решается там влёт без особых мозговых усилий :D
-
Код в студию!
-
Ну, код может убить впечатлительного человека. :)
А словами можно описать так, естественно используя привычную мне терминологию.
Есть исходный массив (сортирован или не сортирован значения не имеет)
Перебирая все записи этого массива (получая при этом #чела, #начисл, дата_с, дата_по)
Пишем в временный массив TMP(#чела,#начисл) строку флагов дней в году
Затем перебирая этот массив заменяем строку флагов на к-во единиц в строке
Грубо говоря - две строки на МАМПСе
-
Ну, код может убить впечатлительного человека. :)
Да, код на мапсе лучше в пятницу публиковать, ближе к вечеру :-)
-
Ну вы прям классическое решение задачи о покрытиях описали. :)
Может кто иначе решение предложит.
ps А код все равно хотелось бы увидеть (тем более на таком экзотичном языке)
-
SELECT Sotr, Nach, count(Nach) FROM TABLE
GROUP BY Sotr, Nach
WHERE Data not in [...] // исключение праздников
ORDER BY Sotr, Nach - где то так...
-
разумеется это решение верно ТОЛЬКО в том случае когда в один день сотруднику было сделано не более одного однотипного начисления...
-
Но это не решение поставленной задачи.
Нужно считать дни в периодах.
-
На SQL в общем решается так же как описал albobin. (с привлечением дополнительной таблицы-календаря, или, иначе говоря, тупо списка всех дней в году)
-
Примерно так:
оформлен код как процедура '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
-
Но это не решение поставленной задачи.
Нужно считать дни в периодах.
:) точно , а так?
SELECT Sotr, Nach, max(Data_Fin-Data_Nach) FROM TABLE
GROUP BY Sotr, Nach
ORDER BY Sotr, Nach
-
И так не так :)
Что будет в результате, если два периода (по данному сотр. и нач.) не пересекаются?
-
:) :) :) тогда самым простым будет банальное создание псевдо набора (представления)
SELECT Sotr, Nach, Data_Nach, Data_Fin FROM TABLE
ORDER BY Sotr, Nach, Data_Nachи цикл по этому набору в хранимой процедуре...
с чего начали тем и закончили ;D
-
Исправить сразу 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