демо: дБ <> скрипка
WITH words AS (
SELECT phrase, unnest, row_number() OVER ()
FROM (
SELECT phrase, unnest(string_to_array(phrase, ' '))
FROM phrases
)s
), phrase_parts AS (
SELECT
phrase, array_to_string(array_agg, ' ') as check_phrase
FROM (
SELECT
w1.phrase, array_agg(w2.unnest) OVER (PARTITION BY w1.row_number ORDER BY w2.row_number)
FROM words w1
JOIN words w2
ON w1.phrase = w2.phrase and w1.row_number <= w2.row_number
ORDER BY w1.row_number, w2.row_number
) s
WHERE array_length(array_agg, 1) = 3
)
SELECT p.phrase as a, pp.phrase as b, pp.check_phrase
FROM
phrases p
JOIN
phrase_parts pp
ON p.phrase LIKE '%' || pp.check_phrase || '%' and p.phrase <> pp.phrase
Расширенный набор данных:
phrase
my foo bar baz
foo baz whatever bar
foo bar baz whatever
blah my foo bar blah
blah my foo baz blah
Результат:
a b check_phrase
blah my foo bar blah my foo bar baz my foo bar
foo bar baz whatever my foo bar baz foo bar baz
my foo bar baz foo bar baz whatever foo bar baz
blah my foo baz blah blah my foo bar blah blah my foo
my foo bar baz blah my foo bar blah my foo bar
blah my foo bar blah blah my foo baz blah blah my foo
CTE words
создает список всех слов всех фраз.Все слова получают индекс для обеспечения оригинального порядка в их фразах.
CTE phrase_parts
создает все возможные фразы из 3 слов: для каждой исходной фразы объединяются все слова.
После объединения результат выглядит следующим образом:
phrase unnest row_number phrase unnest row_number
my foo bar baz my 1 my foo bar baz my 1
my foo bar baz my 1 my foo bar baz foo 2
my foo bar baz my 1 my foo bar baz bar 3
my foo bar baz my 1 my foo bar baz baz 4
my foo bar baz foo 2 my foo bar baz foo 2
my foo bar baz foo 2 my foo bar baz bar 3
my foo bar baz foo 2 my foo bar baz baz 4
my foo bar baz bar 3 my foo bar baz bar 3
my foo bar baz bar 3 my foo bar baz baz 4
my foo bar baz baz 4 my foo bar baz baz 4
foo baz whatever bar foo 5 foo baz whatever bar foo 5
foo baz whatever bar foo 5 foo baz whatever bar baz 6
foo baz whatever bar foo 5 foo baz whatever bar whatever 7
foo baz whatever bar foo 5 foo baz whatever bar bar 8
foo baz whatever bar baz 6 foo baz whatever bar baz 6
...
С оконной функцией array_agg()
Я могу объединить второй столбец unnest
таким образом:
array_agg
{my}
{my,foo}
{my,foo,bar}
{my,foo,bar,baz}
{foo}
{foo,bar}
{foo,bar,baz}
{bar}
{bar,baz}
{baz}
{foo}
{foo,baz}
{foo,baz,whatever}
{foo,baz,whatever,bar}
...
Это фильтруется для array length = 3
и преобразовывается в строку.Результатом являются 3 словосочетания:
Последний шаг - проверить все фразы в таблице на наличие любой из трех фраз (и не совпадающих с их исходными фразами)