Имя: Пароль:
1C
1С v8
Объединение двух таблиц запроса с датами
0 Chelovek1C
 
22.09.17
01:27
Приветствую Всех! Подскажите в следующем вопросе:

Есть две таблицы запроса, которые надо объединить, но что то не выходит.

Вот например

ВЫБРАТЬ
    ВТДанныеПлан.Сотрудник КАК Сотр,
    ВТДанныеПлан.ДатаНачалаПлан КАК ДНП,
    ВТДанныеПлан.ДатаОкончанияПлан КАК ДОП,
    ВТДанныеПлан.КолвоДнейПлан КАК КДП,
    ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0) КАК ДНФ,
    ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0) КАК ДОФ,
    0 КАК КолвоДнейФакт
ИЗ
    ВТДанныеПлан

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ВТДанныеФакт.Сотрудник,
    ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0),
    ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0),
    0,
    ВТДанныеФакт.ДанаНачалаФакт,
    ВТДанныеФакт.ДатаОкончанияФакт,
    ВТДанныеФакт.КолвоДнейФакт
ИЗ
    ВТДанныеФакт

На выходе нужно получить что то вроде

Сотр|ДНП|ДОП|КДП|ДНФ|ДОФ|КДФ|
C1  |Д1 |Д1 |К1 |Д4 |Д4 |К4 |
C1  |Д2 |Д2 |К2 |Д6 |Д6 |К6 |

А Получается...

Сотр|ДНП|ДОП|КДП|ДНФ|ДОФ|КДФ|
C1  |Д1 |Д1 |К1 |Д4 |Д4 |К4 |
C1  |Д1 |Д1 |К1 |Д6 |Д6 |К6 |
C1  |Д2 |Д2 |К2 |Д4 |Д4 |К4 |
C1  |Д2 |Д2 |К2 |Д6 |Д6 |К6 |

Не знаю, доходчиво ли объяснил.
1 gerroin
 
22.09.17
02:00
Сделай не объединить все, а просто объединить.
2 patria0muerte
 
22.09.17
04:36
Помести во временную таблицу и потом сгруппируй. Даты по МАКСИМУМ, количество дней по СУММА
3 Antony8x
 
22.09.17
04:48
+1
4 Chelovek1C
 
22.09.17
06:19
(1) Пробовал, результат одинаковый
5 Chelovek1C
 
22.09.17
06:21
(2) Нельзя группировать, все данные по датам и количеству в таблицах самостоятельны и все нужно сохранить
6 patria0muerte
 
22.09.17
07:31
(5) Тогда обьясни нормально, что именно есть и что хочешь получить. А то непонятны критерии объединения.

Если просто одна таблица над другой - то твой запрос и так должен корректно отрабатывать
7 Chieftain
 
22.09.17
08:08
(7) Получается, что в одной таблице планы, в другой факты.
Видимо хочет по какому-то непонятному критерию соединить периоды плана и факта.
8 lodger
 
22.09.17
08:16
(0) тебе не объединить а связать надо.
9 Chelovek1C
 
22.09.17
10:13
Есть отчет Т-7 График отпусков, в нем есть колонки плановая дата ухода в отпуск и есть фактическая (эти данные получаются из разных регистров). План и факт в идеале должны сходится, тогда да, можно связать две таблицы по колонкам сотрудник и дата начала, но так не всегда бывает. Поэтому при попытке связи только по полю сотрудник получается много дублирующих строк, от которых группировкой никак не избавится. При объединении получается лучше, строки не дублируются, но тут получаются, что сначала идут строки по плану с пустыми строками факта, затем идут строки с пустыми датами плана и заполненными датами факт. И вот тут затык
10 h-sp
 
22.09.17
10:18
(9) чем лучше объединение? Ведь понятно, что это полный тупик, никакого просвета. А связи наоборот, там всё путем, надо только вам документацию почитать, поизучать немного, и всё получится.
11 Chelovek1C
 
22.09.17
10:59
(10) При связи получается, что на каждую дату плана выходят все записи факта т.е. приблизительно так

С1 ДНП1 ДОП1 ДНФ1 ДНФ1
----------------------
С1 ДНП1 ДОП1 ДНФ2 ДНФ2
----------------------
С1 ДНП2 ДОП2 ДНФ1 ДНФ1
----------------------
С1 ДНП2 ДОП2 ДНФ2 ДНФ2
С1 ДНП3 ДОП3 ДНФ1 ДНФ1
С1 ДНП3 ДОП3 ДНФ2 ДНФ2
12 Chelovek1C
 
22.09.17
10:59
При связи получается, что на каждую дату плана выходят все записи факта т.е. приблизительно так

1. С1 ДНП1 ДОП1 ДНФ1 ДНФ1
2. С1 ДНП1 ДОП1 ДНФ2 ДНФ2
3. С1 ДНП2 ДОП2 ДНФ1 ДНФ1
4. С1 ДНП2 ДОП2 ДНФ2 ДНФ2
5. С1 ДНП3 ДОП3 ДНФ1 ДНФ1
6. С1 ДНП3 ДОП3 ДНФ2 ДНФ2
13 Chelovek1C
 
22.09.17
11:00
(12) При связи получается, что на каждую дату плана выходят все записи факта т.е. приблизительно так

1. С1 ДНП1 ДОП1 ДНФ1 ДОФ1
2. С1 ДНП1 ДОП1 ДНФ2 ДОФ2
3. С1 ДНП2 ДОП2 ДНФ1 ДОФ1
4. С1 ДНП2 ДОП2 ДНФ2 ДОФ2  
5. С1 ДНП3 ДОП3 ДНФ1 ДОФ1  
6. С1 ДНП3 ДОП3 ДНФ2 ДОФ2

Вот так
14 catena
 
22.09.17
11:05
"При связи получается, что на каждую дату плана выходят все записи факта т.е. приблизительно так "

Вам нужно определиться с критерием, как факт связан с планом кроме сотрудника. Даты начала всегда совпадают?
15 lodger
 
22.09.17
11:13
(11) это ты, Кеволеч, связь плохо придумал.
например, попробуй добавить еще одно расчетное поле к каждой таблице: началопериода(КакаятоКлючеваяДата,Месяц)
и вяжи еще и по ней.
16 lodger
 
22.09.17
11:16
+ к (15) ну и посмотри шо таке "Внутреннее, Полное, Левое" соединения.
17 Chelovek1C
 
22.09.17
11:18
(14) Нет, в том то и дело что не всегда
18 Chelovek1C
 
22.09.17
11:30
(15) Ура! Спасибо! Уже лучше, теперь надо проверять.
19 Chelovek1C
 
22.09.17
11:32
Вот так получается, может кому то пригодится


ВЫБРАТЬ
    ВТДанныеПлан.Сотрудник КАК Сотрудник,
    ВТДанныеПлан.ДатаНачалаПлан КАК ДатаНачалаПлан,
    ВТДанныеПлан.ДатаОкончанияПлан,
    ВТДанныеПлан.КолвоДнейПлан,
    МИНИМУМ(ВТДанныеФакт.ДанаНачалаФакт) КАК ДанаНачалаФакт,
    МАКСИМУМ(ВТДанныеФакт.ДатаОкончанияФакт) КАК ДатаОкончанияФакт,
    СУММА(ВТДанныеФакт.КолвоДнейФакт) КАК КолвоДнейФакт
ИЗ
    ВТДанныеПлан КАК ВТДанныеПлан
        ЛЕВОЕ СОЕДИНЕНИЕ ВТДанныеФакт КАК ВТДанныеФакт
        ПО ВТДанныеПлан.Сотрудник = ВТДанныеФакт.Сотрудник
            И ВТДанныеПлан.МесяцОтпускаПлан = ВТДанныеФакт.МесяцОтпускаФакт

СГРУППИРОВАТЬ ПО
    ВТДанныеПлан.Сотрудник,
    ВТДанныеПлан.ДатаНачалаПлан,
    ВТДанныеПлан.ДатаОкончанияПлан,
    ВТДанныеПлан.КолвоДнейПлан,
20 Вафель
 
22.09.17
11:34
я бы делела так:
Выбрать всех содрудников из 2х таблиц, а потом присоеденить эти таблицы
21 Вафель
 
22.09.17
11:34
никаких группировок не нужно
22 Chieftain
 
22.09.17
13:24
(19) Если это отпуска, то логичнее будет делать не месяц, а год (НачалоПериода(Дата,Год)).
Кроме того, при левом соединении и отсутствии в "плане" ключевых полей "факта" (Сотрудник, месяц), данные по "факту" в выборку совсем не попадут.
И еще необходимо учесть, что периодов отпуска может быть несколько - не всегда отпуск идет одним непрерывным куском.
23 catena
 
22.09.17
13:26
(22)Хорошо, если у вас сотрудники ходят в отпуск раз в год. У нас, например, могут и два раза в месяц. Я уж не говорю о том, что расхождение плана с фактом может быть не месяц.
24 Chieftain
 
22.09.17
13:45
(23) Так я в 3 абзаце именно про это и написал, не нужно читать по диагонали.
В решении из (19) это не учтено, да и при "плане" в январе и "факте" в марте - факта в выборке не будет вообще.
При выборке по году можно свернуть по максимуму дат начала и конца и суммировать дни отпуска. Да и то белиберда получится.
25 Ildarovich
 
24.09.17
14:04
Решение в (19) неправильное. План и факт отпуска нужно рассматривать как списание по партиям. Запланированный отпуск должен добавлять неотгулянные дни, а фактический - их списывать. Поэтому критерием соединения плановых и фактических отпусков должен быть сквозной (по всем отпускам) номер дня отпуска.
Вот два запроса, которые более правильно (на мой взгляд) решают поставленную задачу. Запросы приведены в вариантах, предусматривающих задание исходных данных (два первых подзапроса), что позволяет поэкспериментировать с ними в консоли запросов.
Первый запрос - это буквальное списание по партиям. Находится наростающий итог дней планового и отдельно - фактического отпуска. Затем отрезки пересекаются. И их пересечения и дают соответствия того, когда отпуск был запланирован и когда реально отгулян. Многословие этого запроса вызвано необходимостью выравнивания числа запланированных и отгулянных дней фантомными отпусками, иначе не будет отражаться ситуация, когда отпуск был полностью или частично не отгулян или отгуливался авансом.
ВЫБРАТЬ
    "Иванов" КАК Сотрудник,
    ДАТАВРЕМЯ(2017, 9, 1) КАК Начало,
    ДАТАВРЕМЯ(2017, 9, 4) КАК Окончание,
    4 КАК Длина
ПОМЕСТИТЬ План
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    "Иванов" КАК Сотрудник,
    ДАТАВРЕМЯ(2017, 9, 6) КАК Начало,
    ДАТАВРЕМЯ(2017, 9, 8) КАК Окончание,
    3 КАК Длина
ПОМЕСТИТЬ Факт
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    План.Сотрудник КАК Сотрудник,
    СУММА(План.Длина) КАК Сумма
ПОМЕСТИТЬ ПланСумма
ИЗ
    План КАК План

СГРУППИРОВАТЬ ПО
    План.Сотрудник
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Факт.Сотрудник КАК Сотрудник,
    СУММА(Факт.Длина) КАК Сумма
ПОМЕСТИТЬ ФактСумма
ИЗ
    Факт КАК Факт

СГРУППИРОВАТЬ ПО
    Факт.Сотрудник
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    План.Сотрудник,
    План.Начало,
    План.Окончание,
    План.Длина,
    ЕСТЬNULL(СУММА(Прошлое.Длина), 0) КАК НакопленоРанее
ПОМЕСТИТЬ ПланПлюс
ИЗ
    План КАК План
        ЛЕВОЕ СОЕДИНЕНИЕ План КАК Прошлое
        ПО План.Сотрудник = Прошлое.Сотрудник
            И План.Начало > Прошлое.Начало

СГРУППИРОВАТЬ ПО
    План.Сотрудник,
    План.Начало,
    План.Окончание,
    План.Длина

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    План.Сотрудник,
    ДАТАВРЕМЯ(1, 1, 1),
    ДАТАВРЕМЯ(1, 1, 1),
    Факт.Сумма - План.Сумма,
    План.Сумма
ИЗ
    ПланСумма КАК План
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ФактСумма КАК Факт
        ПО План.Сотрудник = Факт.Сотрудник
            И (Факт.Сумма > План.Сумма)
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Факт.Сотрудник,
    Факт.Начало,
    Факт.Окончание,
    Факт.Длина,
    ЕСТЬNULL(СУММА(Прошлое.Длина), 0) КАК НакопленоРанее
ПОМЕСТИТЬ ФактПлюс
ИЗ
    Факт КАК Факт
        ЛЕВОЕ СОЕДИНЕНИЕ Факт КАК Прошлое
        ПО (Факт.Сотрудник = Факт.Сотрудник)
            И Факт.Начало > Прошлое.Начало

СГРУППИРОВАТЬ ПО
    Факт.Сотрудник,
    Факт.Начало,
    Факт.Окончание,
    Факт.Длина

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    План.Сотрудник,
    ДАТАВРЕМЯ(1, 1, 1),
    ДАТАВРЕМЯ(1, 1, 1),
    План.Сумма - Факт.Сумма,
    Факт.Сумма
ИЗ
    ПланСумма КАК План
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ФактСумма КАК Факт
        ПО План.Сотрудник = Факт.Сотрудник
            И (Факт.Сумма < План.Сумма)
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    План.Сотрудник КАК СотрудникПлан,
    План.Начало КАК НачалоПлан,
    План.НакопленоРанее КАК НакопленоРанееПлан,
    Факт.Сотрудник КАК СотрудникФакт,
    Факт.Начало КАК НачалоФакт,
    Факт.НакопленоРанее КАК НакопленоРанееФакт,
    ВЫБОР
        КОГДА План.НакопленоРанее > Факт.НакопленоРанее
            ТОГДА План.НакопленоРанее
        ИНАЧЕ Факт.НакопленоРанее
    КОНЕЦ КАК От,
    ВЫБОР
        КОГДА План.НакопленоРанее + План.Длина - 1 < Факт.НакопленоРанее + Факт.Длина - 1
            ТОГДА План.НакопленоРанее + План.Длина - 1
        ИНАЧЕ Факт.НакопленоРанее + Факт.Длина - 1
    КОНЕЦ КАК До
ПОМЕСТИТЬ ПланФакт
ИЗ
    ПланПлюс КАК План
        ПОЛНОЕ СОЕДИНЕНИЕ ФактПлюс КАК Факт
        ПО План.Сотрудник = Факт.Сотрудник
            И (План.НакопленоРанее + План.Длина - 1 >= Факт.НакопленоРанее)
            И (Факт.НакопленоРанее + Факт.Длина - 1 >= План.НакопленоРанее)
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ПланФакт.СотрудникПлан,
    ДОБАВИТЬКДАТЕ(ПланФакт.НачалоПлан, ДЕНЬ, ПланФакт.От - ПланФакт.НакопленоРанееПлан) КАК НачалоПлан,
    ДОБАВИТЬКДАТЕ(ПланФакт.НачалоПлан, ДЕНЬ, ПланФакт.До - ПланФакт.НакопленоРанееПлан) КАК ОкончаниеПлан,
    ПланФакт.СотрудникФакт,
    ДОБАВИТЬКДАТЕ(ПланФакт.НачалоФакт, ДЕНЬ, ПланФакт.От - ПланФакт.НакопленоРанееФакт) КАК НачалоФакт,
    ДОБАВИТЬКДАТЕ(ПланФакт.НачалоФакт, ДЕНЬ, ПланФакт.До - ПланФакт.НакопленоРанееФакт) КАК ОкончаниеФакт,
    ПланФакт.До - ПланФакт.От + 1 КАК Длина
ИЗ
    ПланФакт КАК ПланФакт

Второй запрос проще. Он основан на предварительной развертке отпусков по дням, нумерации дней, их полном соединении по порядковому номеру дня отпуска и свертке (группировке) по смежным дням.
ВЫБРАТЬ
    "Иванов" КАК Сотрудник,
    ДАТАВРЕМЯ(2017, 9, 1) КАК Начало,
    ДАТАВРЕМЯ(2017, 9, 5) КАК Окончание
ПОМЕСТИТЬ План

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    "Иванов",
    ДАТАВРЕМЯ(2017, 9, 11),
    ДАТАВРЕМЯ(2017, 9, 15)
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    "Иванов" КАК Сотрудник,
    ДАТАВРЕМЯ(2017, 9, 6) КАК Начало,
    ДАТАВРЕМЯ(2017, 9, 9) КАК Окончание
ПОМЕСТИТЬ Факт
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    План.Сотрудник,
    План.Начало,
    Календарь.ДатаКалендаря КАК День
ПОМЕСТИТЬ ПланДни
ИЗ
    План КАК План
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК Календарь
        ПО (Календарь.ДатаКалендаря МЕЖДУ План.Начало И План.Окончание)
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Факт.Сотрудник,
    Факт.Начало,
    Календарь.ДатаКалендаря КАК День
ПОМЕСТИТЬ ФактДни
ИЗ
    Факт КАК Факт
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК Календарь
        ПО (Календарь.ДатаКалендаря МЕЖДУ Факт.Начало И Факт.Окончание)
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    План.Сотрудник,
    План.Начало,
    План.День,
    КОЛИЧЕСТВО(Прошлое.День) КАК НомерДня
ПОМЕСТИТЬ ПланПлюс
ИЗ
    ПланДни КАК План
        ЛЕВОЕ СОЕДИНЕНИЕ ПланДни КАК Прошлое
        ПО План.Сотрудник = Прошлое.Сотрудник
            И План.День >= Прошлое.День

СГРУППИРОВАТЬ ПО
    План.Сотрудник,
    План.Начало,
    План.День
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Факт.Сотрудник,
    Факт.Начало,
    Факт.День,
    КОЛИЧЕСТВО(Прошлое.День) КАК НомерДня
ПОМЕСТИТЬ ФактПлюс
ИЗ
    ФактДни КАК Факт
        ЛЕВОЕ СОЕДИНЕНИЕ ФактДни КАК Прошлое
        ПО Факт.Сотрудник = Прошлое.Сотрудник
            И Факт.День >= Прошлое.День

СГРУППИРОВАТЬ ПО
    Факт.Сотрудник,
    Факт.Начало,
    Факт.День
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ПланПлюс.Сотрудник КАК СотрудникПлан,
    МИНИМУМ(ПланПлюс.День) КАК НачалоПлан,
    МАКСИМУМ(ПланПлюс.День) КАК ОкончаниеПлан,
    ФактПлюс.Сотрудник КАК СотрудникФакт,
    МИНИМУМ(ФактПлюс.День) КАК НачалоФакт,
    МАКСИМУМ(ФактПлюс.День) КАК ОкончаниеФакт,
    ЕСТЬNULL(КОЛИЧЕСТВО(ПланПлюс.День), КОЛИЧЕСТВО(ФактПлюс.День)) КАК Длина
ИЗ
    ПланПлюс КАК ПланПлюс
        ПОЛНОЕ СОЕДИНЕНИЕ ФактПлюс КАК ФактПлюс
        ПО ПланПлюс.Сотрудник = ФактПлюс.Сотрудник
            И ПланПлюс.НомерДня = ФактПлюс.НомерДня

СГРУППИРОВАТЬ ПО
    ПланПлюс.Сотрудник,
    ФактПлюс.Сотрудник,
    ПланПлюс.Начало,
    ФактПлюс.Начало

УПОРЯДОЧИТЬ ПО
    СотрудникПлан,
    НачалоПлан,
    НачалоФакт

В первом варианте запроса 130 строк (без учета строк ввода исходных данных), во втором - 85. Навскидку первый вариант должен работать чуть быстрее. Хотя в нем три тэта-соединения, а во втором - два, но в первом соединяются таблицы с отпусками, а во втором - с днями отпусков, которых, естественно больше. А там квадратичная зависимость!

Вообще задачи на интервалы - одни из самых сложных и интересных в 1С. На сайте infostart.ru в моем профиле http://catalog.mista.ru/profile/28527/public/ можно найти другие интересные задачи на интервалы с решениями.
Основная теорема систематики: Новые системы плодят новые проблемы.