Ищите текст в одном поле, содержащемся в другом поле Oracle SQL

#sql #oracle #text #sql-like

#sql #Oracle #текст #sql-подобный

Вопрос:

Я прошу прощения, если этот вопрос был задан, у меня возникли проблемы с выражением его словами.

Меня попросили отфильтровать строки в запросе, где текст из одного поля содержится в другом поле. Пример, вероятно, объяснил бы это лучше:

     Column_1         Column_2
    Low Static       Static
    Static           Static
    Static           Clear
                     Static
    Very Low Freq    Freq
  

Результат запроса должен возвращать только строки 3 и 4, поскольку строки 1, 2 и 5 содержат похожие строки. Прямо сейчас у меня есть следующее условие:

     WHERE
    ((Column_2 NOT LIKE '%' || Column_1 || '%')
    OR (Column_1 NOT LIKE '%' || Column_2 || '%' OR Column_1 IS NULL))
  

Однако он возвращает строки 1, 3, 4 и 5, когда я хочу вернуть только строки 3 и 4. Это всего лишь пример данных, мой фактический набор данных содержит много разных текстовых строк в столбцах 1 и 2, поэтому я не могу просто написать конкретные инструкции case, чтобы исключить определенные случаи, когда столбцы похожи.

Может быть, это просто невозможно, поскольку я не могу определить строку как нечто, содержащееся в пределах 2 пробелов, в то же время принимая во внимание случаи, когда пробелов нет?

Спасибо

Комментарии:

1. измените первое или на и WHERE (column_2 not like '%' || column_1 || '%' and column_1 not like '%' || column_2 || '%') OR Column_1 is null OR column_2 is null

2. Заголовок вопроса говорит обратное последней части вашего вопроса, где вы говорите «Я хочу возвращать только строки 3 и 4», поэтому я в замешательстве.

3. Спасибо, что нашли это. Я изменил его на И, который исправил несколько случаев, но я все еще получаю противоречивые результаты, например, столбец 1 = ‘Шум звука справа’ и столбец 2 = ‘Шум звука чистый’ (поэтому я бы хотел исключить эту строку).

4. «Ищите текст в одном поле, содержащемся в другом поле … затем исключите строки, где это верно». Я надеюсь, что это поможет.

Ответ №1:

Для вашего выражения, я думаю, вы хотите, and а не or :

 WHERE ((Column_2 NOT LIKE '%' || Column_1 || '%') AND
       (Column_1 NOT LIKE '%' || Column_2 || '%' OR Column_1 IS NULL)
      )
  

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

 WHERE NOT (Column_2 LIKE '%' || Column_1 || '%' OR
           Column_1 LIKE '%' || Column_2 || '%'
          )
  

Ответ №2:

Используемый вами подход заключается в выполнении полного сканирования таблицы, чтобы она не масштабировалась по мере роста таблицы. Если вы хотите реализовать более эффективное решение (без использования Oracle large text indexing), которое будет использовать индекс, используйте индекс на основе функций для предварительного вычисления общих подстрок столбцов.

Используя INSTR(), вы можете определить, является ли столбец подстрокой другого столбца, и вернуть для этого оценку. 0 означает отсутствие соответствия.

 create index ix_t_score on t (instr(nvl(column_1,' '), nvl(column_2, ' ')),
                              instr(nvl(column_2,' '), nvl(column_1, ' ')));
  

Теперь напишите запрос таким образом, чтобы он позволял Oracle использовать индексы.

 -- Find rows that don't have common strings
select * from t
  where instr(nvl(column_1, ' '), nvl(column_2, ' ')) = 0 and
        instr(nvl(column_2, ' '), nvl(column_1, ' ')) = 0;

-- Find rows that do
select * from t
  where instr(nvl(column_1, ' '), nvl(column_2, ' ')) > 0 or
        instr(nvl(column_2, ' '), nvl(column_1, ' ')) > 0;


set autotrace on


Execution Plan
----------------------------------------------------------
Plan hash value: 4100696360

---------------------------------------------------------------------------------
| Id  | Operation         | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |             |     1 |    22 |     2   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE   |             |     1 |    22 |            |          |
|*  2 |   INDEX RANGE SCAN| IX_T_SCORE  |     1 |    22 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access(INSTR(NVL("COLUMN_1",' '),NVL("COLUMN_2",' '))=0 AND
              INSTR(NVL("COLUMN_2",' '),NVL("COLUMN_1",' '))=0)
  

Вы можете упростить это, создав детерминированную хранимую процедуру / функцию для возврата оценки, и SQL станет намного проще, чем описано выше. Использование NVL() заключается в обработке столбцов с нулевыми значениями.