PostgreSQL Выберите отдельные значения столбца значений, разделенных запятыми, за исключением подмножеств - PullRequest
0 голосов
/ 29 мая 2018

Предположим, что есть таблица foo со столбцом bar содержит значения, разделенные запятыми ('a, b', 'a, b, c', 'a, b,c, d ',' d, e ') Как выбрать наибольшую комбинацию и исключить все подмножества, включенные в эту комбинацию (наибольшую):

пример для вышеуказанного набора данных,результат должен быть:

('a, b, c, d', 'd, e') и первые два объекта ('a, b', 'a, b, c ') исключаются, поскольку они являются подмножеством (' a, b, c, d ') .

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

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

select distinct a.bar from foo a   inner join foo b
on a.bar like '%'|| b.bar||'%' 
and a.bar != b.bar

Ответы [ 2 ]

0 голосов
/ 29 мая 2018

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

Далее, агрегируйте и используйте BOOL_ORв предложении HAVING, чтобы отфильтровать любой набор символов, который является подмножеством любого другого набора символов

С образцом таблицы, разделенной в cte, запрос становится:

WITH foo(bar) AS (SELECT '("a,b" , "a,b,c" , "a,b,c,d" , "d,e")'::TEXT)
SELECT bar, string_to_array(elems[1], ',') not_subset
FROM foo
CROSS JOIN regexp_matches(bar, '[\w|,]+', 'g') elems 
CROSS JOIN regexp_matches(bar, '[\w|,]+', 'g') elems2
WHERE elems2[1] != elems[1] 
  -- my regex also matches the ',' between sets which need to be ignored
  -- alternatively, i have to refine the regex
  AND elems2[1] != ','
  AND elems[1] != ','
GROUP BY 1, 2
HAVING NOT BOOL_OR(string_to_array(elems[1], ',') <@ string_to_array(elems2[1], ','))

производит вывод

bar                                     not_subset
'("a,b" , "a,b,c" , "a,b,c,d" , "d,e")' {'d','e'}
'("a,b" , "a,b,c" , "a,b,c,d" , "d,e")' {'a','b','c','d'}

пример в скрипте sql

0 голосов
/ 29 мая 2018

Вы можете использовать string_to_array(), чтобы разбить строки на массив.С помощью оператора содержимого @> вы можете проверить, содержит ли массив другой.(См. "9.18. Функции и операторы массива" .)

Используйте это в предложении NOT EXISTS.fi.ctid <> fo.ctid должен гарантировать, что физические адреса сравниваемой пары строк не равны, поскольку, конечно, массив из одной строки будет содержать массив по сравнению с той же строкой.

SELECT fo.bar
       FROM foo fo
       WHERE NOT EXISTS (SELECT *
                                FROM foo fi
                                WHERE fi.ctid <> fo.ctid
                                      AND string_to_array(fi.bar, ',') @> string_to_array(fo.bar, ','));

SQL Fiddle

Но я не могу удержаться: не используйте разделенные запятыми строки в реляционной базе данных.У тебя есть что-то лучше.Это называется "стол".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...