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

Запросы, планы, оптимизация запросов, ...

Модераторы: kdv, CyberMax

Ответить
Matveih1
Сообщения: 41
Зарегистрирован: 11 дек 2007, 14:50

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

Сообщение Matveih1 » 19 фев 2008, 14:30

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

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 19 фев 2008, 15:07

это шутка? или Вы про SQL вообще ничего не читали? ок, приведите пример "негениального", что пытались сделать.

Matveih1
Сообщения: 41
Зарегистрирован: 11 дек 2007, 14:50

Сообщение Matveih1 » 20 фев 2008, 09:14

Гениальный запрос я вчера написал и он отработал. Видимо ты меня не так понял попытаю описать задачу более подробно.
Есть период дат скажем с ’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’ но это мне не подходит т.к. мне нужно кол- во часов на первое число каждого месяца из интервала дат!

stix-s
Заслуженный разработчик
Сообщения: 557
Зарегистрирован: 13 дек 2005, 11:52

Сообщение stix-s » 20 фев 2008, 09:47

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 по месяцу не спасает?

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 20 фев 2008, 10:05

Потом следующий интервал из переданного т.е.
открой для себя sum и group by.

Matveih1
Сообщения: 41
Зарегистрирован: 11 дек 2007, 14:50

Сообщение Matveih1 » 20 фев 2008, 10:22

Естественно Sum (перепутал)
Но причем здесь Group by??? Не понимаю напишите пример

Attid
Спец
Сообщения: 377
Зарегистрирован: 14 ноя 2006, 09:58

Сообщение Attid » 20 фев 2008, 10:38

Не понимаю напишите пример
книжки почитай по 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 использовать

Matveih1
Сообщения: 41
Зарегистрирован: 11 дек 2007, 14:50

Сообщение Matveih1 » 20 фев 2008, 11:06

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

Attid
Спец
Сообщения: 377
Зарегистрирован: 14 ноя 2006, 09:58

Сообщение Attid » 20 фев 2008, 11:21

создаешь таблицу МоиМесяцы
там 12 записей
делаешь туда джойн.

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

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 20 фев 2008, 11:26

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

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

Matveih1
Сообщения: 41
Зарегистрирован: 11 дек 2007, 14:50

Сообщение Matveih1 » 20 фев 2008, 11:37

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

Attid
Спец
Сообщения: 377
Зарегистрирован: 14 ноя 2006, 09:58

Сообщение Attid » 20 фев 2008, 11:54

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

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

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

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

Matveih1
Сообщения: 41
Зарегистрирован: 11 дек 2007, 14:50

Сообщение Matveih1 » 20 фев 2008, 12:05

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

Attid
Спец
Сообщения: 377
Зарегистрирован: 14 ноя 2006, 09:58

Сообщение Attid » 20 фев 2008, 12:16

какой вопрос такой ответ, про пустые месяцы в первом посте не обозначено.

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


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

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

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 20 фев 2008, 12:22

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

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

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

Matveih1
Сообщения: 41
Зарегистрирован: 11 дек 2007, 14:50

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

Сообщение Matveih1 » 20 фев 2008, 12:30

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

Attid
Спец
Сообщения: 377
Зарегистрирован: 14 ноя 2006, 09:58

Сообщение Attid » 20 фев 2008, 13:47

для начало создаем календарик данные туда забиваем один раз (к примеру можно ежегодно на год вперед или один раз лет на 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
ЗЫ календарик у себя не использую так как особеность моей системы
придумал все сейчас, ДикоСерж сейчас добавит критики

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

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 20 фев 2008, 16:56

Attid писал(а):

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

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

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

Attid
Спец
Сообщения: 377
Зарегистрирован: 14 ноя 2006, 09:58

Сообщение Attid » 21 фев 2008, 12:44

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

Matveih1
Сообщения: 41
Зарегистрирован: 11 дек 2007, 14:50

Сообщение Matveih1 » 27 фев 2008, 12:13

Я оказался не прав признаю и приношу извинение за грубое поведение. Этот способ работает в том как я описал задачу но задача немного сложнее и он мне не подошел, решение нашел в динамическом запросе.

Ответить