Страница 1 из 1

Нужно составить отчет

Добавлено: 19 фев 2008, 14:30
Matveih1
Проблема следующая.
Есть таблица
Create Table1
( ID Integer,
DStart Date,
DStop Date,
Hour_Work integer
)
Нужно получить отчет за период дат, то есть с клиента на сервер передаю 2 даты и на первое число каждого месяца из этого интервала нужно получить сумму часов.
Бьюсь два дня но ничего гениального придумать не смог. Может кто делал заранее спасибо.

Добавлено: 19 фев 2008, 15:07
kdv
это шутка? или Вы про SQL вообще ничего не читали? ок, приведите пример "негениального", что пытались сделать.

Добавлено: 20 фев 2008, 09:14
Matveih1
Гениальный запрос я вчера написал и он отработал. Видимо ты меня не так понял попытаю описать задачу более подробно.
Есть период дат скажем с ’01.01.2008’ по ’01.04.2008’ так вот мне надо получить сначала
select count(Hour_Work)
from Table1 t
where t.DStart >= ’01.01.2008’ and t.DStart <= ’01.02.2008’
Потом следующий интервал из переданного т.е.
select count(Hour_Work)
from Table1 t
where t.DStart >= ’01.02.2008’ and t.DStart <= ’01.03.2008’
И так далее до ’01.04.2008’ так как это сделать в в одном запросе или ХП?
Может так будет понятней ибо вчера я спросил у товарища он тоже сначала так среагировал и прислал запрос типа where t.DStart >= ’01.01.2008’ and t.DStart <= ’01.04.2008’ но это мне не подходит т.к. мне нужно кол- во часов на первое число каждого месяца из интервала дат!

Добавлено: 20 фев 2008, 09:47
stix-s
Matveih1 писал(а):Гениальный запрос я вчера написал и он отработал. Видимо ты меня не так понял попытаю описать задачу более подробно.
Есть период дат скажем с ’01.01.2008’ по ’01.04.2008’ так вот мне надо получить сначала
select count(Hour_Work)
from Table1 t
where t.DStart >= ’01.01.2008’ and t.DStart <= ’01.02.2008’
Потом следующий интервал из переданного т.е.
select count(Hour_Work)
from Table1 t
where t.DStart >= ’01.02.2008’ and t.DStart <= ’01.03.2008’
И так далее до ’01.04.2008’ так как это сделать в в одном запросе или ХП?
Может так будет понятней ибо вчера я спросил у товарища он тоже сначала так среагировал и прислал запрос типа where t.DStart >= ’01.01.2008’ and t.DStart <= ’01.04.2008’ но это мне не подходит т.к. мне нужно кол- во часов на первое число каждого месяца из интервала дат!
а Group By по месяцу не спасает?

Добавлено: 20 фев 2008, 10:05
kdv
Потом следующий интервал из переданного т.е.
открой для себя sum и group by.

Добавлено: 20 фев 2008, 10:22
Matveih1
Естественно Sum (перепутал)
Но причем здесь Group by??? Не понимаю напишите пример

Добавлено: 20 фев 2008, 10:38
Attid
Не понимаю напишите пример
книжки почитай по sql

что-то типа

Код: Выделить всё

select SUM(Hour_Work)
from Table1 t
where t.DStart >= ’01.01.2008’ and t.DStart <= ’01.12.2008’ 
GROUP BY EXTRACT(month from t.DStart)
также можно substring в group использовать

Добавлено: 20 фев 2008, 11:06
Matveih1
не совсем так
работает нормально если все даты за период в БД заполнены и начинаются с 1 числа, а если с 01.02.2008 по 01.03.2008 в базе ничего нет, а в отчете все ранодолжно быть на 01.03.2008 хоть и 0. И даты в базе не обязательно с 01 начинаются!!!

Добавлено: 20 фев 2008, 11:21
Attid
создаешь таблицу МоиМесяцы
там 12 записей
делаешь туда джойн.

или процедура.

Добавлено: 20 фев 2008, 11:26
WildSery
На этот случай у нормальных людей "производственный календарь" есть, с которым слева уже можно твоё безобразие клеить.
В календаре есть все месяца, следовательно, и в результирующей выборке будут все.

PS. А в твоей SUM(Hours) нуля не будет, будет null.

Добавлено: 20 фев 2008, 11:37
Matveih1
Причем тут таблица с 12 месяцами? Интервал дат может быть и несколько лет! Ладно как я уже сказал проблему я решил создав цикл в цикле. В первом цикле я получаю нужные мне даты, а во втором собственно запрос с использование этих дат. Вот и все и никого не посылал читать книги и не писал типа открой для себя SQL. А всякие таблички и группировки мне не подходят. Так что не так все просто как кажется на первый взгляд! И бросить фразу создай табличку типа тут и так все понятно это не решение! Если так все просто то напиши запрос который вернет данные в виде:
01.02.2008 40
01.03.2008 3
01.04.2008 0
01.05.2008 15
И так далее до конца интервала! А не пустые фразы!

Добавлено: 20 фев 2008, 11:54
Attid
Matveih1 ну если у тебя все работает что ты еще хочешь, если периуд больше года может быть, то да календарик заводить.

а ты не кипятись, а то прийдет kdv с битой и оппа.

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

выигрыша никакого, но можно будет один код использовать в разных запросах.

Добавлено: 20 фев 2008, 12:05
Matveih1
Ды я не злюсь! Просто первый вопрос и такая реакция, какие то общие фразы, теперь и угрозы. Проблему решил сегодня утром, а тему завел вчера. Было интересно рассмотреть другие (альтернативные) пути решения, но видимо не судьба. И писать про группировку и сумму думаю не самый красивый ответ вы же не знаете мой уровень. Понятно, что у меня не такая табличка и записи там не такие, простоя попытался вынести основу вопроса, а не выкладывать всю БД.

Добавлено: 20 фев 2008, 12:16
Attid
какой вопрос такой ответ, про пустые месяцы в первом посте не обозначено.

альтернативно тебе уже 2 вариана привели "производственный календарь" и вынести цыкл в процедуру и джойн с ней делать. других вариантов и не будет.


а про уровень, воспользовался тегом [code] привел пример как ты сделал и что не устраивает и т.д.

прочитай свой первы пост и сделай вывод умеет ли человек пользоватьс групировкой или нет. а про sum ты сам привел примерчто не знаешь его =)

Добавлено: 20 фев 2008, 12:22
WildSery
"Производственный календарь" содержит месяца (и дни, но это не важно) за весь период данных, и обычно на год вперёд.
Потому запрос выглядит так:

Код: Выделить всё

select c.firstDateOfMonth, sum(t.Hour_Work)
  from calendar c
       left join Table1 t on extract(month from t.DStart) = c.month_
  where t.DStart between '01.01.2007' and '01.03.2008'
Календарь используется для тучи разных запросов в отчётах и расчётов, потому без него плохо.
Но тоже можно. Вот мой пример (многократный запрос к Table1 плохо всё же, потому обращаюсь 1 раз, хотя так сложнее).

Код: Выделить всё

execute block (DStart date, DEnd date)
  returns (DateStart date, HSum int)
as
  declare variable cur_date date;
  declare variable hour_sum int;
begin
  /* Находим 1й день месяца (если входная дата не 1-е) */
  DateStart = DStart - extract(day from DStart) + 1;

  for select (DStart - extract(day from DStart) + 1),
             sum(Hour_Work)
    from Table1
    where DStart between :DStart and :DEnd
    group by 1
    into cur_date, hour_sum
  do begin
    HSum = 0;
    while (DateStart < cur_date) do begin
      suspend;
      /* Прибавляем месяц */
      DateStart = DateStart + 31;
      DateStart = DateStart - extract(day from DateStart) + 1;
    end
    HSum = hour_sum;
    suspend;
  end


  /* Тут долистываем месяца, на случай, если пустые в конце */
  HSum = 0;
  while (DateStart <= DEnd) do begin
    suspend;
    /* Прибавляем месяц */
    DateStart = DateStart + 31;
    DateStart = DateStart - extract(day from DateStart) + 1;
  end
end

Re: Нужно составить отчет

Добавлено: 20 фев 2008, 12:30
Matveih1
По поводу пустых месяцев я писал
Matveih1 писал(а):с клиента на сервер передаю 2 даты и на первое число каждого месяца из этого интервала нужно получить сумму часов.
там написано на 1 число каждого месяца из интервала.
Не понимаю я альтернативы с календарем. Если не трудно напиши небольшой пример и если он окажется рабочим то я признаю ошибку и извинюсь.
По поводу SUM банально ошибся, описался ды как угодно суть вопроса была не в том как посчитать кол-во часов а как период разбить на несколько периодов. Как проще описать что я хотел не знаю.

Добавлено: 20 фев 2008, 13:47
Attid
для начало создаем календарик данные туда забиваем один раз (к примеру можно ежегодно на год вперед или один раз лет на 50) года и месяцы в итоге получаем таблицу в которой

Код: Выделить всё

mm yy
02  2008 
03  2008 
04  2008 
05  2008 
06  2008 
07  2008 
08  2008 
и до посинениея
а потом запросом

Код: Выделить всё

select cast('01.'||my.mm||'.'||my.yy as date) ,COALESCE(SUM(Hour_Work),0)
from Table1 t
left outer join my on my.mm = extract(month  from t.DStart) and my.yy=extract(year from t.DStart) 
where t.DStart >= ’01.01.2008’ and t.DStart <= ’01.12.2008’
GROUP BY my.fdate
ЗЫ календарик у себя не использую так как особеность моей системы
придумал все сейчас, ДикоСерж сейчас добавит критики

ЗЫЫ а вообще в календарике обычно все дни бывают тогда и запрос проще будет

Добавлено: 20 фев 2008, 16:56
WildSery
Attid писал(а):

Код: Выделить всё

GROUP BY my.fdate
Это откуда взялось? Наверное, group by 1

Кстати, я у себя в простом примере год не написал. Ну да ладно.

Добавлено: 21 фев 2008, 12:44
Attid
WildSery писал(а): Это откуда взялось? Наверное, group by 1
наверно =) видать что-то другое написать хотел =)

Добавлено: 27 фев 2008, 12:13
Matveih1
Я оказался не прав признаю и приношу извинение за грубое поведение. Этот способ работает в том как я описал задачу но задача немного сложнее и он мне не подошел, решение нашел в динамическом запросе.