Имя: Пароль:
1C
1С v8
Перенос колонок у дублирующихся строк
,
0 Штурман
 
15.11.13
14:37
Есть результат запроса, в виде таблицы:


Первое      Второе      Третье
------      -------     -------
Иванов      А           М
Иванов      А           Н
Иванов      А           О
Иванов      Б          
Петров      А           П
Петров      А           Р
Сидоров     А          


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

Первое      Второе      Третье        Четвертое     Пятое
------      -------     -------       ------        ---------  
Иванов      А           М             Н             О
Иванов      Б          
Петров      А           П             Р
Сидоров     А          

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

Как бы это в запросе реализовать или в таблице значений?

Подскажите, плиз :)
1 regniws
 
15.11.13
14:46
кажется только программно, сортируешь первое, второе, бежишь циклом и если равны, то модифицируешь предыдущую и удаляешь текущую.
2 Штурман
 
15.11.13
14:55
(1) программно, это цикл по таблице значений?
3 regniws
 
15.11.13
14:57
(2) угу
4 kosts
 
15.11.13
14:58
(0) Можно сделать запросом, если значения М,Н,О заданы заранее
5 Штурман
 
15.11.13
15:00
(4) допустим они известны заранее, т.е. предопределенные, как примерно?
6 Штурман
 
15.11.13
15:03
(3) Так примерно пойдет:

    тз = Новый ТаблицаЗначений;
    тз.Колонки.Добавить("Первое");
    тз.Колонки.Добавить("Второе");
    тз.Колонки.Добавить("Третье");
    тз.Колонки.Добавить("Четвертое");
    тз.Колонки.Добавить("Пятое");
    
    стр = тз.Добавить();
    стр.Первое = "Иванов";
    стр.Второе = "А";
    стр.Третье = "M";
    стр = тз.Добавить();
    стр.Первое = "Иванов";
    стр.Второе = "А";
    стр.Третье = "N";
    стр = тз.Добавить();
    стр.Первое = "Иванов";
    стр.Второе = "А";
    стр.Третье = "O";
    стр = тз.Добавить();
    стр.Первое = "Иванов";
    стр.Второе = "B";
    стр = тз.Добавить();
    стр.Первое = "Петров";
    стр.Второе = "А";
    стр.Третье = "M";
    
    СтаршийИндекс = тз.Количество()-1;
    Для сч=0 по СтаршийИндекс Цикл
        если тз[сч].Первое = тз[сч+1].Первое тогда
            сообщить(тз[сч+1].Первое)
        иначе
        конецесли;        
    КонецЦикла;


Только потом выдает ошибку:

"Индекс находится за границами массива
        если тз[сч].Первое = тз[сч+1].Первое тогда"
7 kosts
 
15.11.13
15:05

Выбрать
Первое,
Второе,
Выбор когда Таблица.Третье = &М Тогда Таблица.Третье Иначе 0 Конец как Третье1,
и т.д.
...
8 kosts
 
15.11.13
15:07
(7) Потом нужно сгруппировать. Да и ограничение нарисовалось, МНО должны быть числами, что бы могло суммироваться.
9 regniws
 
15.11.13
15:09
(6)  СтаршийИндекс = тз.Количество()-2, очевидно ж
если тз[сч].Первое = тз[сч+1].Первое И тз[сч].Второе = тз[сч+1].Второе тогда
(7) ну и прикинь что это сделает с (0), мндэ
10 kosts
 
15.11.13
15:17
(6) Можно такой подход.
Создать таблицу с 5 колонками.

Цикл по первой таблице
Ищем строку по ключевым данным во второй таблице.
Если не находим строку, то добавляем.
В найденную(додавленную) строку пишем значение в нужную колонку (М или Н или О)
Повторить цикл сначала

Т.е. примерно 10 строк вполне можно уложиться.
11 regniws
 
15.11.13
15:27
(10) оценка времени работы алгоритма о(н^2)
12 kosts
 
15.11.13
15:34
(11) Если есть уверенность, что таблица 1 упорядочена, то без поиска можно сделать.
13 bolobol
 
15.11.13
15:40
Задача сводится к тому. чтобы выбрать для каждого уникальные записи без повторов, затем в каждой следующей колонке разместить значения, меньшие, чем в предыдущей колонке.
14 Штурман
 
15.11.13
15:45
(12) (13) да, таблица предположительно упорядочена, т.е. самые первые значения дубликатов и будут первыми уникальными значениями, к которым потом добавляются колонки остальных дубликатов
15 Штурман
 
15.11.13
15:49
Получается что на основе этой таблицы значений создаем новую таблицу значений, которую сворачиваем, потом перебрасываем туда колонки,

а в запросе группируем и перекидываем в таблицу значений

так?
16 bolobol
 
15.11.13
15:53
Запросом сложно сделать транспонирование. Запрос это выборки, соединения и - группировки. Группируем и подсчитываем максимум различных значений в каждой группе, чтобы знать количество итоговых колонок.
Обходя группировки - заполняем новую ТЗ. Один цикл по результату запроса.
17 bolobol
 
15.11.13
15:54
Млин... не "в каждой группе", а просто - максимум различных значений "из всех групп"
18 Штурман
 
18.11.13
12:29
Товарищи, написал вот так:


з = тз.Количество();
    СтаршийИндекс = тз.Количество()-2;
    //пока з> 0 цикл
    Для сч = 0 по СтаршийИндекс цикл
        если тз[сч].Первое= тз[сч+1].Первое И тз[сч].Второе= тз[сч+1].Второе тогда
            тз[сч].Четвертое = тз[сч+1].Третье;
            тз.Удалить(сч+1);
        конецесли;        
    конеццикла;


При работе выводит ошибку

"Индекс находится за границами массива"
19 Штурман
 
18.11.13
13:04
^
20 kosts
 
18.11.13
13:14
(18) > "Индекс находится за границами массива"

Естественно, ты же удаляешь строки.
21 Штурман
 
18.11.13
13:24
(20) а что сделать, чтобы такой ошибки не возникало?
22 kosts
 
18.11.13
13:31
(21) Не обращаться за границы таблицы
23 Штурман
 
18.11.13
13:47
(22) а как кодом это сделать?
24 George Wheels
 
18.11.13
14:03
(23)

сч = 0;
Пока Истина Цикл
  Если сч = ТЗ.Количество() - 1 Тогда
    Прервать;
  КонецЕсли;
  если тз[сч].Первое= тз[сч+1].Первое И тз[сч].Второе= тз[сч+1].Второе тогда
    тз[сч].Четвертое = тз[сч+1].Третье;
    тз.Удалить(сч+1);
  Иначе
    сч = сч + 1
  конецесли;
КонецЦикла
25 Штурман
 
18.11.13
15:08
(24) Но тогда так удаляются все строки. А как потом добавить к Пятой колонке значение второго дубликата, что-то уже запутался...

тз[сч].Пятое = тз[сч+...].Второе
26 George Wheels
 
18.11.13
15:16
(25) Удаляется только то, что ты хотел, т.е. строки с индексом сч+1 (которые уже перенесены). Если совпадения в условии Если нет, то индекс увеличивается на 1.

Только алгоритм переноса нужно переписать.
27 Штурман
 
18.11.13
16:03
(26) сделал вот так: добавил в таблицу значений еще одну колонку "Счетчик"

сч=0;
    Пока истина цикл
        Если сч=тз.Количество()-1 тогда
            прервать;
        конецесли;
        если тз[сч].Первое = тз[сч+1].Первое И тз[сч].Второе = тз[сч+1].Второе тогда
            тз[сч].Четвертое = тз[сч+1].Третье;
            тз[сч].Счетчик = сч;
        //    тз.Удалить(сч+1);
        //иначе
            сч = сч + 1;
        конецесли;        
    конеццикла;
    
    Индекс = тз.Количество()-1;
    для сч=0 по Индекс цикл
        если тз[сч].Счетчик = Неопределено тогда
            тз.Удалить(сч);
        конецесли;
    конеццикла;
    
    сч=0;
    Пока истина цикл
        Если сч=тз.Количество()-1 тогда
            прервать;
        конецесли;
        если тз[сч].Первое = тз[сч+1].Первое И тз[сч].Второе = тз[сч+1].Второе тогда
            тз[сч].Пятое = тз[сч+1].Четвертое;
            тз[сч].Счетчик = сч;
        //    тз.Удалить(сч+1);
        //иначе
            сч = сч + 1;
        конецесли;        
    конеццикла;
    
    Индекс = тз.Количество()-1;
    для сч=0 по Индекс цикл
        если тз[сч].Счетчик = 1 тогда
            тз.Удалить(сч);
        конецесли;
    конеццикла;

Работает как-бы нормально, но что-то код великоват получился, можно ли проще решить задачу из (0) ?
28 George Wheels
 
18.11.13
16:26
если тз[сч].Первое = тз[сч+1].Первое И тз[сч].Второе = тз[сч+1].Второе тогда
  Если Не ЗначениеЗаполнено(тз[сч].Четвертое) Тогда
    тз[сч].Четвертое = тз[сч+1].Третье;
  ИначеЕсли Не ЗначениеЗаполнено(тз[сч].Пятое) Тогда
    тз[сч].Пятое = тз[сч+1].Третье;
  Иначе
    Сообщить("Сюда попасть не должен, или есть шестой элемент");
  КонецЕсли;
  тз.Удалить(сч+1);
Иначе
  сч = сч + 1;
КонецЕсли;
29 Штурман
 
18.11.13
16:55
(28) спасибо, попробую :)
30 Prince-Sentido
 
19.11.13
19:59
Доброго времени суток, Штурман! Не знаю, когда сможете прочесть... Заинтересовался поставленной Вами задачей, написал алгоритм.
ТекущаяСтрока = Табличка[0].Первое; й = 3;
    ТаблицаДляУдаления = Новый ТаблицаЗначений;
    ТаблицаДляУдаления.Колонки.Добавить("Первое");
    ТаблицаДляУдаления.Колонки.Добавить("Индекс", ОписаниеТипаЧисло);
    Для Каждого строка из Табличка Цикл
        Если строка.Первое = ТекущаяСтрока и Табличка.Индекс(строка) <> 0 Тогда
            Если Табличка.Колонки.Найти("Поле"+й) = Неопределено Тогда                 
                Табличка.Колонки.Добавить("Поле"+й, ОписаниеТипаСтрока, "Поле"+й, 15);
            КонецЕсли;
            Табличка[Табличка.Индекс(строка)-ТаблицаДляУдаления.НайтиСтроки(Новый Структура("Первое", строка.Первое)).Количество()-1][Табличка.Колонки.Индекс(Табличка.Колонки.Найти("Поле"+й))] =
            строка.Второе;            
            ТекущаяСтрока = строка.Первое;
            нс = ТаблицаДляУдаления.Добавить();
            нс.Первое = строка.Первое;
            нс.Индекс = Табличка.Индекс(строка);            
            й = й + 1;
        Иначе
            ТекущаяСтрока = строка.Первое;
            й = 3;
        КонецЕсли;
    КонецЦикла;
Это основная функция преобразующая данные, согласно заданию(только лишь ключ состоит из одного поля!). Для удаления ненужных строк(ТаблицаДляУдаления) упорядочиваю строки по колонке Индекс в порядке убывания, а затем уже удаляю их. Это связано с тем, чтобы не менялся индекс у еще не удаленных строк. Преимущество в том, что заранее не нужно знать количество будущих колонок
Функция работает в обработке. Если есть вопросы, буду рад пообщаться.
31 Штурман
 
20.11.13
14:38
(30) Попробую ваш алгоритм :)