Свертывание нескольких строк, содержащих подстроки, в одну строку - PullRequest
0 голосов
/ 21 сентября 2018

У меня есть несколько строк записей (id, query,count), которые я хотел бы свернуть, наблюдая за query в нескольких строках.Я хочу сохранить строку с самой длинной query и суммой поля count для свернутых строк.

Пример ввода:

24, que, 2
24, querie, 1
24, queries, 1
25, term1, 3
25, term1+term2, 11
25, term1+term2+term3, 1
26, inventory, 5
26, issues, 10
27, close, 1
27, sclosed, 2
28, abcde, 2
28, abcfe, 2

Требуемый вывод:

24, queries, 4
25, term1+term2+term3, 15
26, inventory, 5
26, issues, 10
27, close, 1
27, sclosed, 2
28, abcde, 2
28, abcfe, 2

Я только после особого случая подстрок: 24,25 свернут, но 27нет, из-за префикса на close.26 также не свернут, так как поле query во втором ряду не является подстрокой (без префикса) первого.

Редактировать: добавлен идентификатор 28, что является еще одним случаем, когда записи не должны быть свернуты.

Ответы [ 5 ]

0 голосов
/ 21 сентября 2018

demo: db <> fiddle

Для более общих случаев (например, "разница может быть на 10-й букве" или "естьстрока с одним символом "), вам нужно определить правильные группы.Поэтому необходимо проверить строки на соответствие следующей: «Является ли текущая строка началом следующей?»

С некоторыми вещами, такими как substring, вы можете проверить специальнуюдлина в начале ( "Группировать все тексты, начинающиеся с одинаковых 3 букв" Но что, если у вас нет 3 букв? Или разница где-то позже?)

Вот почему я рассчиталспециальные группы с помощью оконной функции lag (https://www.postgresql.org/docs/current/static/tutorial-window.html):

SELECT 
    max(id) as id,                                        -- C
    max(phrase) as phrase,
    sum("count") as count
FROM (
    SELECT 
        *,
        SUM(is_diff) OVER (ORDER BY id, phrase) as ranked -- B
    FROM (
        SELECT
            *,
            -- A: 
            CASE WHEN phrase LIKE (lag(phrase) over (order by id, phrase)) || '%' THEN 0 ELSE 1 END as is_diff
        FROM phrases 
    )s
) s
GROUP BY ranked
ORDER BY ranked

Основная идея обсуждается здесь .

A: lagФункция позволяет проверить значение следующей строки. Так что если phrase текущей строки начало phrase следующей строки, то они находятся в одной группе. (current_row LIKE (next_row || '%')). Это работает, потому чтоid группы упорядочены по phrase текстам (и их длинам).

Если строки несовместимы, вспомогательная переменная устанавливается на 1, в противном случае на 0.

B: Вспомогательные переменные могут быть добавлены и группы генерируются. (Для болееПодробности см. по ссылке выше).

C: Остальное - простая группировка по новым сгенерированным значениям группы.

0 голосов
/ 21 сентября 2018

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

Поэтому вам необходимо реализовать собственную функцию возврата множеств:

create table foo(id int, query text, count int);

CREATE OR REPLACE FUNCTION public.reduce()
 RETURNS SETOF foo
 LANGUAGE plpgsql
AS $function$
declare r foo; sr foo;
begin
  for r in select * from foo order by id, query
  loop
    if sr.id is null then
      sr := r;
    else
      if sr.id = r.id then
        if r.query like  sr.query || '%'
           or sr.query like r.query || '%' 
        then
          if length(r.query) > length(sr.query) then
            sr.query := trim(r.query);
          end if;
          sr.count := sr.count + r.count; 
        else
          return next sr;
          sr := r;
        end if;
      else
        return next sr;
        sr = r;
      end if;
    end if;
  end loop;
  if sr.id is not null then
    return next sr;
  end if;
end;
$function$

postgres=# select * from reduce();
+----+-------------------+-------+
| id |       query       | count |
+----+-------------------+-------+
| 24 | queries           |     4 |
| 25 | term1+term2+term3 |    15 |
| 26 | inventory         |     5 |
| 26 | issues            |    10 |
| 27 | close             |     1 |
| 27 | sclosed           |     2 |
+----+-------------------+-------+
(6 rows)

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

0 голосов
/ 21 сентября 2018

Если вам нужно agreagtio для идентификатора, то вы можете использовать сумму для получения суммы и max для получения имени

    select  id, max(col2), sum(col3)
    from my_table 
    group by  id 

, если вам нужно expectio для агрегирования по идентификатору и для получения 27 свернутых, вы можете использовать

    select  id, max(col2), sum(col3)
    from my_table 
    where id <>27
    group by  id 
    union  all
    select  id, col2, sum(col3)
    from my_table 
    where id =27
    group by  id, cold2
    order by id
0 голосов
/ 21 сентября 2018
select  id, max(col2), sum(col3)
    from tablename
    where id in (24,25)
    group by  id 
    union  all
    select  id, col2, sum(col3)
    from tablename
    where id not in (24,25)
    group by  id,col3
    order by id,3;
0 голосов
/ 21 сентября 2018

Использовать агрегацию для макс. И суммы и группировать по столбцу должны быть id и подстрока (column2, от 1 до 3), поскольку вы следуете некоторому шаблону для общего значения

select id, max(column2), sum(column3)
from tablename
group by id, substring(column2,from 1 for 3)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...