Имя: Пароль:
1C
1С v8
Запрос к периодическому регистру сведений
0 first_may
 
12.07.17
20:36
Добрый день.

В базе есть периодический регистр сведений с измерением «Контрагент» и ресурсом «Менеджер».

Подскажите пож, как с помощью запроса собрать данные по периодам, в течение которых у контрагента был тот или иной менеджер?
1 Лефмихалыч
 
12.07.17
20:47
Выбрать
Период
ИЗ регистрСведений.ПериодическийРегистрСведений
ГДЕ Контрагент = &Контрагент и Менеджер = &ОпределенныйМенеджер
2 first_may
 
12.07.17
21:25
(1) так получается  только дата.. а как получить таблицу
из колонок
С     По    Контрагент     Менеджер
3 Cyberhawk
 
12.07.17
21:35
Кастуй Ildarovich в ветку ))
4 first_may
 
12.07.17
21:45
(3) почему он? :)
5 Cyberhawk
 
12.07.17
22:23
(4) Славится умением (и пониманием) в запросах мутить всякую магию
6 kumena
 
12.07.17
22:30
(5) есть и другие, которые как минимум не хуже пишут.
7 first_may
 
12.07.17
22:33
Хотелось бы научиться :)
8 Лефмихалыч
 
12.07.17
22:37
Тогда (1) во временную, потом ещё одну временную с менеджер<>, потом ту с этой соединить по условию период<период и выбрать максимум периодов, и результат ещё раз соединить с самой первой временной.

Поищи 'срез последних на каждую дату' - это один и самых распространенных шаблонов проектирования у 1сников
9 SleepyHead
 
гуру
13.07.17
07:31
Если запросы не знаешь, выгружай в таблицу значений результат простого запроса, в виде

дата начала, менеджер, контрагент,

сортируй по дате начала, добавляй колонку "дата окончания", пробегайся по строкам таблицы и проставляй дату окончания. Не буду писать, как это сделать, догадайся.
10 KishMish
 
13.07.17
07:43
я так понял, есть данные на каждую дату
Дата Контрагент Менеджер

Надо сделать эту таблицу периодами?
ДатаНач  ДатаКон  КОнтрагент Менеджер

Если да то вот этот кусок кода это делает

////////////////////////////////////////////////////////////////////////////////                                                    
ВЫБРАТЬ                                                    
    в_Графики.Сотрудник,                                                
    в_Графики.ДатаВыхода,                                                
    в_Графики.ОтработаноЧасов - ЕСТЬNULL(вт_УказанныеРанее.ОтработаноЧасов, 0) КАК ОтработаноЧасов                                                
ПОМЕСТИТЬ вт_Данные                                                    
ИЗ                                                    
    в_Графики КАК в_Графики                                                
        ЛЕВОЕ СОЕДИНЕНИЕ вт_УказанныеРанее КАК вт_УказанныеРанее                                            
        ПО в_Графики.Сотрудник = вт_УказанныеРанее.Сотрудник                                            
            И в_Графики.ДатаВыхода = вт_УказанныеРанее.ДатаВыхода                                        
ГДЕ                                                    
    в_Графики.ОтработаноЧасов - ЕСТЬNULL(вт_УказанныеРанее.ОтработаноЧасов, 0) > 0                                                
;                                                    
                                                    
////////////////////////////////////////////////////////////////////////////////                                                    
ВЫБРАТЬ                                                    
    вт_Данные.ДатаВыхода КАК ДатаВыхода,                                                
    вт_Данные.Сотрудник,                                                
    вт_ДанныеП.ДатаВыхода ЕСТЬ NULL КАК Начало,                                                
    вт_ДанныеС.ДатаВыхода ЕСТЬ NULL КАК Конец                                                
ПОМЕСТИТЬ вт_ПоискГраниц                                                    
ИЗ                                                    
    вт_Данные КАК вт_Данные                                                
        ПОЛНОЕ СОЕДИНЕНИЕ вт_Данные КАК вт_ДанныеС                                            
        ПО (ДОБАВИТЬКДАТЕ(вт_Данные.ДатаВыхода, ДЕНЬ, 1) = вт_ДанныеС.ДатаВыхода)                                            
            И вт_Данные.Сотрудник = вт_ДанныеС.Сотрудник                                        
        ПОЛНОЕ СОЕДИНЕНИЕ вт_Данные КАК вт_ДанныеП                                            
        ПО (ДОБАВИТЬКДАТЕ(вт_Данные.ДатаВыхода, ДЕНЬ, -1) = вт_ДанныеП.ДатаВыхода)                                            
            И вт_Данные.Сотрудник = вт_ДанныеП.Сотрудник                                        
ГДЕ                                                    
    НЕ вт_Данные.Сотрудник ЕСТЬ NULL                                                
    И (вт_ДанныеП.ДатаВыхода ЕСТЬ NULL                                                
            ИЛИ вт_ДанныеС.ДатаВыхода ЕСТЬ NULL)                                        
;                                                    
                                                    
////////////////////////////////////////////////////////////////////////////////                                                    
ВЫБРАТЬ                                                    
    вт_Начало.Сотрудник КАК Сотрудник,                                                
    вт_Начало.ДатаВыхода КАК ДатаНачала,                                                
    МИНИМУМ(вт_Конец.ДатаВыхода) КАК ДатаОкончания                                                
ПОМЕСТИТЬ вт_ГотовыеПериоды                                                    
ИЗ                                                    
    вт_ПоискГраниц КАК вт_Начало                                                
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ вт_ПоискГраниц КАК вт_Конец                                            
        ПО (вт_Начало.Начало)                                            
            И (вт_Конец.Конец)                                        
            И вт_Начало.Сотрудник = вт_Конец.Сотрудник                                        
ГДЕ                                                    
    вт_Конец.ДатаВыхода >= вт_Начало.ДатаВыхода                                                
                                                    
СГРУППИРОВАТЬ ПО                                                    
    вт_Начало.Сотрудник,                                                
    вт_Начало.ДатаВыхода                                                
;                                                    
                                                    
////////////////////////////////////////////////////////////////////////////////                                                    
ВЫБРАТЬ                                                    
    вт_ГотовыеПериоды.Сотрудник КАК Сотрудник,                                                
    вт_ГотовыеПериоды.ДатаНачала,                                                
    вт_ГотовыеПериоды.ДатаОкончания,                                                
    СУММА(1) КАК День,                                                
    СУММА(вт_Данные.ОтработаноЧасов) КАК ОтработаноЧасов                                                
ИЗ                                                    
    вт_ГотовыеПериоды КАК вт_ГотовыеПериоды                                                
        ЛЕВОЕ СОЕДИНЕНИЕ вт_Данные КАК вт_Данные                                            
        ПО вт_ГотовыеПериоды.Сотрудник = вт_Данные.Сотрудник                                            
            И (вт_Данные.ДатаВыхода МЕЖДУ вт_ГотовыеПериоды.ДатаНачала И вт_ГотовыеПериоды.ДатаОкончания)                                        
                                                    
СГРУППИРОВАТЬ ПО                                                    
    вт_ГотовыеПериоды.Сотрудник,                                                
    вт_ГотовыеПериоды.ДатаНачала,                                                
    вт_ГотовыеПериоды.ДатаОкончания                                                
                                                    
УПОРЯДОЧИТЬ ПО                                                    
    Сотрудник,                                                
    вт_ГотовыеПериоды.ДатаНачала
11 KishMish
 
13.07.17
07:46
+(10) если есть вопросы тексту запроса задавай
Основная тема такая
Ищем Границы периодов - вт_ПоискГраниц
Потом получаем периоды - вт_ГотовыеПериоды
А потом соединяем вт_ГотовыеПериоды с данными
12 first_may
 
13.07.17
10:08
(11) СПСАИБО!!!
13 first_may
 
13.07.17
11:21
(11) а вот тут

ВЫБРАТЬ                                                    
    вт_Данные.ДатаВыхода КАК ДатаВыхода,                                                
    вт_Данные.Сотрудник,                                                
    вт_ДанныеП.ДатаВыхода ЕСТЬ NULL КАК Начало,                                                
    вт_ДанныеС.ДатаВыхода ЕСТЬ NULL КАК Конец                                                
ПОМЕСТИТЬ вт_ПоискГраниц                                                    
ИЗ                                                    
    вт_Данные КАК вт_Данные                                                
        ПОЛНОЕ СОЕДИНЕНИЕ вт_Данные КАК вт_ДанныеС                                            
        ПО (ДОБАВИТЬКДАТЕ(вт_Данные.ДатаВыхода, ДЕНЬ, 1) = вт_ДанныеС.ДатаВыхода)                                            
            И вт_Данные.Сотрудник = вт_ДанныеС.Сотрудник                                        
        ПОЛНОЕ СОЕДИНЕНИЕ вт_Данные КАК вт_ДанныеП                                            
        ПО (ДОБАВИТЬКДАТЕ(вт_Данные.ДатаВыхода, ДЕНЬ, -1) = вт_ДанныеП.ДатаВыхода)                                            
            И вт_Данные.Сотрудник = вт_ДанныеП.Сотрудник                                        
ГДЕ                                                    
    НЕ вт_Данные.Сотрудник ЕСТЬ NULL                                                
    И (вт_ДанныеП.ДатаВыхода ЕСТЬ NULL                                                
            ИЛИ вт_ДанныеС.ДатаВыхода ЕСТЬ NULL)                                        
;                                                    


почему именно
(ДОБАВИТЬКДАТЕ(вт_Данные.ДатаВыхода, ДЕНЬ, 1) = вт_ДанныеС.ДатаВыхода)


??
14 KishMish
 
13.07.17
12:38
(13) таблица вт_Данные должна содержать данные на каждый день интерисуемого периода без пропусков.
То есть в твоем случае тебе в таблице Данные нужно сделать так чтобы было
Период     Контрагент   Менеджер
01.01.2017 Контрагент1 Менеджер1
02.01.2017 Контрагент1 Менеджер1
03.01.2017 Контрагент1 Менеджер1
03.01.2017 Контрагент1 Менеджер2
04.01.2017 Контрагент1 Менеджер2
05.01.2017 Контрагент1 Менеджер2 ...

01.01.2017 Контрагент2 Менеджер3
02.01.2017 Контрагент2 Менеджер3
03.01.2017 Контрагент2 Менеджер3
03.01.2017 Контрагент2 Менеджер3
04.01.2017 Контрагент2 Менеджер2
05.01.2017 Контрагент2 Менеджер2 ... и так далее. то есть

то есть состояние на каждый день, для каждой совокупности Контрагент Менеджер.
Ты сможешь ее получить?

и далее при получении вт_ПоискГраниц код твой будет такой

ВЫБРАТЬ                                                    
    вт_Данные.Период КАК Период,                                                
    вт_Данные.Контрагент,
    вт_Данные.Менеджер,                                                                                                
    вт_ДанныеП.Период ЕСТЬ NULL КАК Начало,                                                
    вт_ДанныеС.Период ЕСТЬ NULL КАК Конец                                                
ПОМЕСТИТЬ вт_ПоискГраниц                                                    
ИЗ                                                    
    вт_Данные КАК вт_Данные                                                
        ПОЛНОЕ СОЕДИНЕНИЕ вт_Данные КАК вт_ДанныеС                                            
        ПО (ДОБАВИТЬКДАТЕ(вт_Данные.Период, ДЕНЬ, 1) = вт_ДанныеС.Период)                                            
            И вт_Данные.Контрагент = вт_ДанныеС.Контрагент   И вт_Данные.Менеджер = вт_ДанныеС.Менеджер  //тут вообще столько условий сколько у тебя ключевых полей                                  
        ПОЛНОЕ СОЕДИНЕНИЕ вт_Данные КАК вт_ДанныеП                                            
        ПО (ДОБАВИТЬКДАТЕ(вт_Данные.Период, ДЕНЬ, -1) = вт_ДанныеП.Период)                                            
            И вт_Данные.Контрагент = вт_ДанныеП.Контрагент     И вт_Данные.Менеджер = вт_ДанныеП.Менеджер
15 KishMish
 
13.07.17
12:39
+(14)
ГДЕ                                                    
    НЕ вт_Данные.Контрагент ЕСТЬ NULL                                                
    И (вт_ДанныеП.ДатаВыхода ЕСТЬ NULL                                                
            ИЛИ вт_ДанныеС.ДатаВыхода ЕСТЬ NULL)
16 KishMish
 
13.07.17
12:42
(13) и ответ на почему именно
(ДОБАВИТЬКДАТЕ(вт_Данные.ДатаВыхода, ДЕНЬ, 1) = вт_ДанныеС.ДатаВыхода)


я соеденяю таблицу со следующим днем (ДОБАВИТЬКДАТЕ(вт_Данные.ДатаВыхода, ДЕНЬ, 1) = вт_ДанныеС.ДатаВыхода)
и с предыдущим  ПО (ДОБАВИТЬКДАТЕ(вт_Данные.Период, ДЕНЬ, -1) = вт_ДанныеП.Период)
17 first_may
 
13.07.17
12:58
(16) а у меня нет следующего дня, так как есть например запись
01.05.2011 ..
03.08.2011 ..
18 first_may
 
13.07.17
13:02
(14) "то есть состояние на каждый день" - такого нет, есть большой промежуток между датами..
19 KishMish
 
13.07.17
13:04
(17) сделай из нее таблицу на все даты.
как делать? найти в инете как запросом получить курсы валют на каждый день. и сделай по тому типу свою
например http://catalog.mista.ru/public/337365/
там используется ПроизводсвенныйКалендарь.
Если у тебя нет календаря, то тогда тебе нужно сформировать  таблицу дат. это запрос тоже можно в инете найти.
20 Diman000
 
13.07.17
13:18
В детали сабжа я не вникал, но навскидку в (9) не самый плохой вариант предложен.
Сервер SQL мощная штука, смекалистая и многое умеет оптимизировать. Я про MS, с остальными в промышленном масштабе не работал.
Но задачи сложные для запросов частенько лучше решать кодом на сервере приложений, чем придумывать или искать хитрые решения, которые могут прилично нагрузить сервер СУБД.
21 1dvd
 
13.07.17
13:20
(20) +1
22 first_may
 
13.07.17
14:12
(20) надо одним запросом :), без таблиц.
23 1dvd
 
13.07.17
14:13
(22) кому надо?
24 Naf2017
 
13.07.17
14:16
25 Diman000
 
13.07.17
15:07
(22)
Присоединяюсь к вопросу (23)
Кому надо?

Есть процедура или функция которая обрабатывает именно результат запроса? Тогда ее надо немного подправить, это недолго.

Есть динамический список в который хочется зафигачить этот запрос? Тогда этого делать нельзя, это прилично затормозит форму. Лучше переписать на статическую таблицу. Но это долго. Но надо.

Ну и третий вариант, тебе поставили задачу выдать именно РезультатЗапроса? В таком случае надо включить свою голову и обосновать постановщику почему это плохо.

Могут быть и еще варианты, мне было бы интересно их услышать.
26 KishMish
 
13.07.17
15:23
(25) метод решения зависит от предполагаемого количества строк в результате. При большом количество строк в выходной таблице обработка строк в цикле будет намного дольше чем запросом.
27 Diman000
 
13.07.17
15:24
(26) Согласен, хороший аргумент.
28 first_may
 
13.07.17
15:25
Для саморазвития надо сделать только с помощью запроса :).
29 Diman000
 
14.07.17
01:03
(28) Если все так серьезно, то загляните сразу в профайлер SQL. Для саморазвития очень полезно)
30 first_may
 
14.07.17
09:33
(10) добрый день..

тут
ВЫБРАТЬ                                                    
    в_Графики.Сотрудник,                                                
    в_Графики.ДатаВыхода,                                                
    в_Графики.ОтработаноЧасов - ЕСТЬNULL(вт_УказанныеРанее.ОтработаноЧасов, 0) КАК ОтработаноЧасов                                                
ПОМЕСТИТЬ вт_Данные                                                    
ИЗ                                                    
    в_Графики КАК в_Графики                                                
        ЛЕВОЕ СОЕДИНЕНИЕ вт_УказанныеРанее КАК вт_УказанныеРанее                                            
        ПО в_Графики.Сотрудник = вт_УказанныеРанее.Сотрудник                                            
            И в_Графики.ДатаВыхода = вт_УказанныеРанее.ДатаВыхода                                        
ГДЕ                                                    
    в_Графики.ОтработаноЧасов - ЕСТЬNULL(вт_УказанныеРанее.ОтработаноЧасов, 0) > 0                                                

я понимаю, что в_Графики - это календарь дней, то есть 01.01.., 02.01.. и  тд..

а вт_УказанныеРанее - ?
31 first_may
 
14.07.17
11:08
Спасибо всем. Разобрался.