Переключение на Главную Страницу Страницы: [1] 2  ОтправитьПечать
Горячая тема (более 10 ответов) Группировка по дням (число прочтений - 6370 )
Rubin
Junior Member
**
Отсутствует


I Love YaBB 2!

Сообщений: 70
Зарегистрирован: 31. Июля 2007
Группировка по дням
28. Сентября 2007 :: 06:28
Печать  
Есть регистр партии товаров. Нужно получить итог (остаток регистра) на каждый день из заданной границы. Подстажите, как это можно реализовать?

В текущем виде запрос выглядит так:

Код
Выбрать все
SELECT
	Товар as [Товар $Справочник.Номенклатура],
	Склад as [Склад $Справочник.МестаХранения],  
	ДатаДок,				  
	SUM(КонКол) as КонКол,
	SUM(КонСтоим) as КонСтоим
FROM (
	SELECT
		$ОстПТ.Товар as Товар,
		$ОстПТ.Склад as Склад,  
		:ДатаНач as ДатаДок,
		$ОстПТ.ОстатокТовара as КонКол,
		$ОстПТ.Стоимость as КонСтоим
	FROM
		$РегистрИтоги.ПартииТоваров as ОстПТ
	WHERE
		period = :НачалоПрошПериода
		AND	$ОстПТ.Фирма = :ПустаяФирма

	UNION ALL

	SELECT
		$ПТ.Товар as Товар,
		$ПТ.Склад as Склад,						    
		CAST(LEFT(Журн.Date_Time_IDDoc, 8) as DateTime) as ДатаДок,
		CASE WHEN ПТ.debkred = 0 THEN $ПТ.ОстатокТовара ELSE -$ПТ.ОстатокТовара END as КонКол,
		CASE WHEN ПТ.debkred = 0 THEN $ПТ.Стоимость ELSE -$ПТ.Стоимость END as КонСтоим
	FROM
		$Регистр.ПартииТоваров as ПТ
	INNER JOIN
		_1SJourn as Журн On Журн.IDDoc = ПТ.IDDoc
			AND Журн.Date_Time_IDDoc BETWEEN :КонецПрошПериода AND :ДатаНач~
	WHERE
		$ПТ.Фирма = :ПустаяФирма
	) as tmp
GROUP BY
	Товар,Склад,ДатаДок WITH ROLLUP 



Возможно во втором подзапросе (после UNION ALL) надо присоединить таблицу с датами из заданного диапазона при помощи JOINа? Но как её сгенерировать? Её можно сгенерить на языке 1с и записать в дбф как временный файл, но это как-то не практично.. Хотя нет, так не прокатит, это надо запрос на каждый день выполнить...
  
Наверх
 
IP записан
 
alexdd
Senior Member
****
Отсутствует


I Love YaBB 2!

Сообщений: 347
Зарегистрирован: 25. Июня 2007
Re: Группировка по дням
Ответ #1 - 28. Сентября 2007 :: 16:02
Печать  
можно так

Код
Выбрать все
	Дата1 = Формат('03.06.2007',"ДГГГГММДД");
	Дата2 = Формат('04.06.2007',"ДГГГГММДД");

	RS = СоздатьОбъект("ODBCRecordSet");
	RS.УстБД1С();

	RS.Выполнить("drop table #tmp__");

	ТекстЗапроса = "
	|create table #tmp__
	|         (
	|           Товар         char(9)       not null,
	|           Склад         char(9)       not null,
	|           ОстатокТовара numeric(12,3) not null,
	|           Стоимость     numeric(11,2) not null,
	|           Дата          datetime      not null
	|         )
	|";  

	рез = RS.Выполнить(ТекстЗапроса);
    
	Если рез = 0 Тогда
		Сообщить(RS.ПолучитьОписаниеОшибки());
		Возврат;
	КонецЕсли;

	ТекстЗапроса = "
	|declare @@curDate datetime
	|
	|set @@curDate = cast('"+Дата1+"' as datetime)
	|
	|while @@curDate<=cast('"+Дата2+"' as datetime)
	|begin
	|     insert into #tmp__(Товар,Склад,ОстатокТовара,Стоимость,Дата)
	|     select
	|       Рег.Товар              [Товар],
	|       Рег.Склад              [Склад],
	|       sum(Рег.ОстатокТовара) [ОстатокТовара],  
	|       sum(Рег.Стоимость)     [Стоимость],  
	|       @@curDate              [Дата]
	|     from
	|        (  
	|           select
	|             $rg.Товар         [Товар],
	|             $rg.Склад         [Склад],  
	|             $rg.ОстатокТовара [ОстатокТовара],  
	|             $rg.Стоимость     [Стоимость]  
	|           from
	|             $РегистрИтоги.ПартииТоваров as rg (nolock)
	|           where
	|              rg.period = dateadd(m,-1,dateadd(dd,-day(@@curDate)+1,@@curDate)) and
	|             $rg.Фирма = $ПустойИд
	|           union all
	|           select
	|             $ra.Товар                          [Товар],
	|             $ra.Склад                          [Склад],  
	|             $ra.ОстатокТовара*(1-ra.debkred*2) [ОстатокТовара],  
	|             $ra.Стоимость*(1-ra.debkred*2)     [Стоимость]  
	|           from
	|             $Регистр.ПартииТоваров ra (nolock)
	|           inner join
	|             _1sjourn j (nolock) on j.iddoc = ra.iddoc
	|           where
	|              cast(left(j.date_time_iddoc,8) as datetime) between dateadd(dd,-day(@@curDate)+1,@@curDate) and @@curDate and
	|             $ra.Фирма = $ПустойИд
	|        ) Рег  
	|     group by
	|        Рег.Товар,
	|        Рег.Склад
	|     set @@curDate = dateadd(dd,1,@@curDate)
	|  end
	|";

	рез = RS.Выполнить(ТекстЗапроса);
	Если рез = 0 Тогда
		Сообщить(RS.ПолучитьОписаниеОшибки());
		Возврат;
	КонецЕсли;  

	ТекстЗапроса = "
	|select
	|  Товар         [Товар $Справочник.ТМЦ],
	|  Склад         [Склад $Справочник.Склады],
	|  ОстатокТовара [ОстатокТовара],
	|  Стоимость     [Стоимость],      
	|  Дата          [Дата]    
	|from
	|  #tmp__
	|";

	Попытка
		тз = RS.ВыполнитьИнструкцию(ТекстЗапроса);
	Исключение    
		Сообщить(RS.ПолучитьОписаниеОшибки());
		Возврат;
	КонецПопытки;
                
	тз.ВыбратьСтроку();


 

  
Наверх
 
IP записан
 
Вадимко
God Member
*****
Отсутствует


Нам бы чего про ОдноЦэ...

Сообщений: 1048
Местоположение: Минск
Зарегистрирован: 24. Мая 2006
Пол: Мужской
Re: Группировка по дням
Ответ #2 - 28. Сентября 2007 :: 21:22
Печать  
Я уже как-то писал безумный способ как одним запросом без курсоров и переменных
Только надо создать таблицу дат свою и с ней соединится левым соединением 1=1 (чтобы тупо все попало)
А в выборке использовать case на предмет того что вывести - ноль или значение из регистра
  

Кампутер, кофе и сигареты - это очень плохо для моего здоровья...
Наверх
IP записан
 
Rubin
Junior Member
**
Отсутствует


I Love YaBB 2!

Сообщений: 70
Зарегистрирован: 31. Июля 2007
Re: Группировка по дням
Ответ #3 - 02. Октября 2007 :: 08:08
Печать  
alexdd писал(а) 28. Сентября 2007 :: 16:02:
можно так


Ужос )) Я примерно так же сделал, только цикл работает не на SQL, а на 1с. Единственно, что смущает - это если за год формировать отчёт, то нужно все 350 запросов выполнить! Но с другой стороны, по другому ведь не получится......?
  
Наверх
 
IP записан
 
kiruha
1c++ power user
Отсутствует



Сообщений: 1249
Зарегистрирован: 11. Апреля 2007
Re: Группировка по дням
Ответ #4 - 02. Октября 2007 :: 08:18
Печать  
Тут же написали - создаешь временную таблицу и соединяешься без проблем.
В ДБФ таблица у меня создается 3000 элементов в сек, и то только потому,
что нет оптимизированных способов ТЗ -> временная таблица.
На SQL думаю в разы быстрее.
За год получается 0.1 сек. Дальше оптимизировать смысла нет.
  
Наверх
 
IP записан
 
Rubin
Junior Member
**
Отсутствует


I Love YaBB 2!

Сообщений: 70
Зарегистрирован: 31. Июля 2007
Re: Группировка по дням
Ответ #5 - 02. Октября 2007 :: 08:57
Печать  
попробую)
  
Наверх
 
IP записан
 
sergeystav
YaBB Newbies
*
Отсутствует


I Love YaBB 2!

Сообщений: 13
Зарегистрирован: 02. Октября 2007
Re: Группировка по дням
Ответ #6 - 02. Октября 2007 :: 10:04
Печать  

Я получаю остатки так:

           |SELECT
           |   Спр.ID AS [Товар $Справочник.Номенклатура],
           |   Ост.Период AS Период,
           |   Ост.ОстатокПериод AS ОстатокПериод,
           |   SUM(Ост.ОстатокКон) AS ОстатокКон
           |
           |FROM
           |   (
           |      SELECT
           |            РегОб.Товар AS Товар,
           |       РегОб.ОстатокТовараКонечныйОстаток as ОстатокПериод,
           |            РегОб.Период AS Период,
         |              (SELECT Sum(Рег.ОстатокТовараОстаток)
           |               FROM $РегистрОстатки.ОстаткиТоваров(:КонДата~,, ,
           |             (Товар),(ОстатокТовара)) AS Рег
           |            WHERE Рег.Товар= РегОб.Товар) AS ОстатокКон
           |
           |            FROM
           |            $РегистрОстаткиОбороты.ОстаткиТоваров(:НачДата, :КонДата~, День,,,,
           |                  (Товар),(ОстатокТовара)) AS РегОб 
           |    ) AS Ост
           |   
           |RIGHT JOIN
           |   $Справочник.Номенклатура as Спр (nolock)
           |      ON Спр.ID = Ост.Товар
       |
           |GROUP BY
           |   Спр.ID,
           |   Ост.Период,
           |   Ост.ОстатокПериод
           |
        
   Правда период будет когда были движения.
   
   В принципе можно попробовать так:
   
   Построить СписокЗначений с календарными днями за период, проще сделать запрос 1С к любому справочнику:
      
         Запрос = СоздатьОбъект("Запрос");
     ТекстЗапроса =
     "//{{ЗАПРОС(Сформировать)
     |Номенклатура = Справочник.Номенклатура.ТекущийЭлемент;
     |Группировка День все;
     |"//}}ЗАПРОС
     ;
     
     Из запроса в СписокЗначений загрузить список дат.
     
     RS.УложитьСписокОбъектов13(СписокЗначенийДаты,"#ТаблицаДаты");
     
     И попробовать использовать в запросе:
     
    "INNER  JOIN (SELECT Val FROM #ГруппаТ) ";

  
Наверх
 
IP записан
 
sergeystav
YaBB Newbies
*
Отсутствует


I Love YaBB 2!

Сообщений: 13
Зарегистрирован: 02. Октября 2007
Re: Группировка по дням
Ответ #7 - 02. Октября 2007 :: 10:06
Печать  
Последние читать как "INNER  JOIN (SELECT Val FROM #ТаблицаДаты) ";
  
Наверх
 
IP записан
 
kiruha
1c++ power user
Отсутствует



Сообщений: 1249
Зарегистрирован: 11. Апреля 2007
Re: Группировка по дням
Ответ #8 - 02. Октября 2007 :: 11:55
Печать  
А что по твоему делает УложитьСписокОбъектов ? Улыбка
  
Наверх
 
IP записан
 
DmitrO
1c++ power user
Отсутствует


ex developer

Сообщений: 579
Местоположение: г. Киров
Зарегистрирован: 22. Мая 2006
Пол: Мужской
Re: Группировка по дням
Ответ #9 - 02. Октября 2007 :: 12:30
Печать  
Так это и делается. В базе содержат таблицу со всеми датами по порядку, для всего рабочего периода (3-5 лет). В этом нет ничего криминального.
Ее не надо каждый раз формировать при построении отчета, путь она там лежит всегда.
Поле с датой надо поставить в качестве первичного ключа.
  
Наверх
ICQ  
IP записан
 
alexdd
Senior Member
****
Отсутствует


I Love YaBB 2!

Сообщений: 347
Зарегистрирован: 25. Июня 2007
Re: Группировка по дням
Ответ #10 - 02. Октября 2007 :: 13:28
Печать  
(6) ВТ РегистрОстаткиОбороты насколько я помню выдавала неправильные результаты, когда она с периодичностью. Или что-то изменилось?

Еще вот такой вариант(используя таблицу с датами):
Код
Выбрать все
ТекстЗапроса = "  
|select  
| vt.Товар              [Товар $Справочник.ТМЦ],
| vt.Склад              [Склад $Справочник.Склады],  
| sum(vt.ОстатокТовара) [ОстатокТовара],  
| sum(vt.Стоимость)     [Стоимость],
| vt.Дата               [Дата]
|from
| (
|  select
|   $rg.Товар                   [Товар],
|   $rg.Склад                   [Склад],  
|   isnull($rg.ОстатокТовара,0) [ОстатокТовара],  
|   isnull($rg.Стоимость,0)     [Стоимость],
|   Даты_vt.date                [Дата]
|  from
|    tmp__ Даты_vt
|  left join
|    $РегистрИтоги.ПартииТоваров as rg (nolock) on rg.period = dateadd(m,-1,dateadd(dd,-day(Даты_vt.date)+1,Даты_vt.date))
|  where
|    rg.period = dateadd(m,-1,dateadd(dd,-day(Даты_vt.date)+1,Даты_vt.date)) and
|    $rg.Фирма = $ПустойИд
|  union all
|  select
|    $ra.Товар                                       [Товар],
|    $ra.Склад                                       [Склад],  
|    isnull($ra.ОстатокТовара*(1-ra.debkred*2),0)    [ОстатокТовара],  
|    isnull($ra.Стоимость*(1-ra.debkred*2),0)        [Стоимость],
|    Даты_vt.date 	                             [Дата]  
|  from
|    tmp__ Даты_vt
|  left join
|   _1sjourn j (nolock) on (left(j.date_time_iddoc,8) between dateadd(m,-1,dateadd(dd,-day(Даты_vt.date)+1,Даты_vt.date)) and Даты_vt.date)
|  left join
|    $Регистр.ПартииТоваров ra (nolock) on ra.iddoc = j.iddoc
|  where
|    $ra.Фирма = $ПустойИд
| ) vt
|group by
|  vt.Товар,
|  vt.Склад,
|  vt.Дата    
|order by
| vt.Дата
|";
 


  
Наверх
 
IP записан
 
sergeystav
YaBB Newbies
*
Отсутствует


I Love YaBB 2!

Сообщений: 13
Зарегистрирован: 02. Октября 2007
Re: Группировка по дням
Ответ #11 - 03. Октября 2007 :: 07:24
Печать  
Вопрос к DmitrO:

ВТ РегистрОстаткиОбороты действительно выдает неправильные результаты, когда она с периодичностью?

На вскидку проверял вроде цифры правильные.
  
Наверх
 
IP записан
 
DmitrO
1c++ power user
Отсутствует


ex developer

Сообщений: 579
Местоположение: г. Киров
Зарегистрирован: 22. Мая 2006
Пол: Мужской
Re: Группировка по дням
Ответ #12 - 03. Октября 2007 :: 07:29
Печать  
Ну, я ничего не менял с тех пор, когда неоднократно писал об этом. Я точно уже не помню ошибка в периодичности Документ или вообще в любой периодичности, но она была, если никто ничего не правил, то она есть.
  
Наверх
ICQ  
IP записан
 
sergeystav
YaBB Newbies
*
Отсутствует


I Love YaBB 2!

Сообщений: 13
Зарегистрирован: 02. Октября 2007
Re: Группировка по дням
Ответ #13 - 03. Октября 2007 :: 10:47
Печать  
Таак, понятно, что ничего не понятно.
Тогда вопрос к ALL.
Корректно ли работают у Вас ОстаткиИОбороты с переодичностью? Или их ни кто не использует?
Переписывать мне теперь отчеты или нет?
  
Наверх
 
IP записан
 
U_zer
Экс-Участник


Re: Группировка по дням
Ответ #14 - 03. Октября 2007 :: 11:13
Печать  
Корректно.
  
Наверх
 
IP записан
 
Переключение на Главную Страницу Страницы: [1] 2 
ОтправитьПечать