Полнотекстовый поиск на основе SQL для заданных аргументов в группе строк - PullRequest
0 голосов
/ 28 июня 2019

Я пытаюсь найти конкретные данные в таблице базы данных (Oracle 12c). Я хочу искать конкретные тексты в группах строк. У каждой группы есть определенный идентификатор, поэтому я хотел бы получить идентификатор группы, если можно найти все аргументов поиска.

Я подготовил таблицу образцов, но с некоторыми упрощениями: - В реальной таблице более 20 столбцов и миллионы строк. - Я преобразовал реальные значения в более короткую версию, такую ​​как a или b, в реальной таблице есть столбцы VARCHAR (500) - В одной группе могут быть тысячи строк (один и тот же идентификатор) - Поиск должен быть быстрым, поэтому манипулирование слишком большим количеством этих данных или многими вложенными запросами может оказаться невозможным

Пример таблицы:

+----+----+---+---+----+
| ID | A  | B | C | D  |
+----+----+---+---+----+
|  1 | aq | a | a | a  |
|  1 | a  | a | c | ad |
|  1 | a  | a | a | a  |
|  2 | a  | a | a | a  |
|  2 | a  | a | a | a  |
|  2 | a  | a | a | a  |
|  3 | a  | a | a | a  |
|  3 | a  | a | a | a  |
|  3 | a  | d | a | a  |
+----+----+---+---+----+

Примеры случаев:

+------+-------------+-----------+
| Case |  Searching  |  Expected |
+------+-------------+-----------+
|    1 | `q` and `c` | [1]       |
|    2 | `a` and `d` | [1, 3]    |
|    3 | `a` and `q` | [1]       |
|    4 | `a`         | [1, 2, 3] |
+------+-------------+-----------+

Случай 1: ID = 1 - совпадение q и c в двух строках Результат = строка [1]

+----+----+---+---+----+
| ID | A  | B | C | D  |
+----+----+---+---+----+
|  1 | aq | a | a | a  | <-- q
|  1 | a  | a | c | ad | <-- c
|  1 | a  | a | a | a  |
|  2 | a  | a | a | a  |
|  2 | a  | a | a | a  |
|  2 | a  | a | a | a  |
|  3 | a  | a | a | a  |
|  3 | a  | a | a | a  |
|  3 | a  | d | a | a  |
+----+----+---+---+----+

Случай 2: ID = 2 - не имеет d нигде Результат: ряды [1, 3]

+----+----+---+---+----+
| ID | A  | B | C | D  |
+----+----+---+---+----+
|  1 | aq | a | a | a  | <-- a
|  1 | a  | a | c | ad | <-- a, d
|  1 | a  | a | a | a  | <-- a
|  2 | a  | a | a | a  | <-- a
|  2 | a  | a | a | a  | <-- a
|  2 | a  | a | a | a  | <-- a
|  3 | a  | a | a | a  | <-- a
|  3 | a  | a | a | a  | <-- a
|  3 | a  | d | a | a  | <-- a, d
+----+----+---+---+----+

Случай 3: ID = 1, соответствующие q и c в одной строке Результат: Строка [1]

+----+----+---+---+----+
| ID | A  | B | C | D  |
+----+----+---+---+----+
|  1 | aq | a | a | a  | <-- a, q
|  1 | a  | a | c | ad | <-- a
|  1 | a  | a | a | a  | <-- a
|  2 | a  | a | a | a  | <-- a
|  2 | a  | a | a | a  | <-- a
|  2 | a  | a | a | a  | <-- a
|  3 | a  | a | a | a  | <-- a
|  3 | a  | a | a | a  | <-- a
|  3 | a  | d | a | a  | <-- a
+----+----+---+---+----+

Случай 4: У нас a везде Результат: ряды [1, 2, 3]

+----+----+---+---+----+
| ID | A  | B | C | D  |
+----+----+---+---+----+
|  1 | aq | a | a | a  | <-- a
|  1 | a  | a | c | ad | <-- a
|  1 | a  | a | a | a  | <-- a
|  2 | a  | a | a | a  | <-- a
|  2 | a  | a | a | a  | <-- a
|  2 | a  | a | a | a  | <-- a
|  3 | a  | a | a | a  | <-- a
|  3 | a  | a | a | a  | <-- a
|  3 | a  | d | a | a  | <-- a
+----+----+---+---+----+

Любая помощь приветствуется :), спасибо

Ответы [ 2 ]

2 голосов
/ 28 июня 2019

Вы можете использовать listagg для:

  • Объединить все столбцы в один
  • Сгруппировать строки для каждого идентификатора в одну строку

Что дает:

create table t (
  id int, a varchar2(2), b varchar2(1), c varchar2(1), d varchar2(2)
);

insert into t values (1, 'aq', 'a', 'a', 'a');
insert into t values (1, 'a', 'a', 'c', 'ad');
insert into t values (1, 'a', 'a', 'a', 'a');
insert into t values (2, 'a', 'a', 'a', 'a');
insert into t values (2, 'a', 'a', 'a', 'a');
insert into t values (2, 'a', 'a', 'a', 'a');
insert into t values (3, 'a', 'a', 'a', 'a');
insert into t values (3, 'a', 'a', 'a', 'a');
insert into t values (3, 'a', 'd', 'a', 'a');
commit;

with vals as (
  select t.id, 
         listagg ( a || b || c || d ) 
           within group ( order by a ) str
  from   t
  group  by t.id
)
  select * from vals
  where  str like '%q%'
  and    str like '%c%';

ID   STR              
    1 aaaaaacadaqaaa    

with vals as (
  select t.id, 
         listagg ( a || b || c || d ) 
           within group ( order by a ) str
  from   t
  group  by t.id
)
  select * from vals
  where  str like '%a%'
  and    str like '%d%';

ID   STR              
    1 aaaaaacadaqaaa    
    3 aaaaaaaaadaa    

Справедливое предупреждение: это, вероятно, будет медленно!

Вы можете решить эту проблему, разместив запрос listagg в материализованном представлении.

Также с 20+ столбцами длиной до 500 символов, вероятно, вы взорветепредел символов для listagg.Если вы не включили расширенные типы данных , чтобы разрешить 32 767 длинных varchar2s в SQL.

1 голос
/ 28 июня 2019

Вы можете попробовать следующий код:

SELECT
    ID
FROM
    (
        SELECT
            ID,
            RTRIM(XMLAGG(XMLELEMENT(E, A || B || C || D, ',').EXTRACT('//text()')).GETCLOBVAL(), ',') 
            AS CONSOLIDATED_VALUE
        FROM
            T
        GROUP BY
            ID
    )
WHERE
    CONSOLIDATED_VALUE LIKE '%q%'
    AND CONSOLIDATED_VALUE LIKE '%c%'

Демо

Ура !!

...