2014-09-25 3 views
2

Я хочу, чтобы пользователь просматривал все столбцы таблицы для набора фраз, определенных в текстовом поле (разделенные термины с пробелом). Итак, первое, что пришло в голову, - найти способ в SQL, чтобы объединить все столбцы и просто использовать оператор LIKE (для каждой фразы) в этом результате. Другое решение, о котором я думал, это написать алгоритм, который выполняет поиск всех фраз и сопоставляет их со всеми столбцами. Так что я в конечном итоге со следующим:Согласование всех столбцов со всеми поисковыми фразами

String [] columns = {"col1", "col2", "col3", "col4"}; 
String [] phrases = textBox.Text.Split(' '); 

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

"(col1 LIKE '%prase1%' AND col1 LIKE '%phrase2%') OR 
(col1 LIKE '%phrase1%' AND col2 LIKE '%phrase2%') OR 
(col1 LIKE '%phrase2%' AND col2 LIKE '%phrase1%') OR 
(col2 LIKE '%phrase1%' AND col3 LIKE '%phrase2%')" 

выше всего лишь пример фрагмент кода выхода, количество условий, создаваемых в этом Алгоритм Построения измеряется

conditions=columns^(phrases+1) 

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

Какова наилучшая практика при поиске всех столбцов для одних и тех же данных?

+0

Насколько велика таблица, которую вы собираетесь искать? все поля столбцов столбцов? и вам нужно беспокоиться о чувствительности к регистру? –

+0

В таблице всего около 500 строк. Все столбцы - это текст, за исключением столбца «цена». Мы создали веб-искателя и ограничили его одним доменом для получения данных обо всех продуктах. Я не беспокоюсь о чувствительности к регистру. – Edwin

+0

Вы должны искать [Полнотекстовый поиск] (http://msdn.microsoft.com/en-us/library/ms142571.aspx) – VahidNaderi

ответ

0

Эдвин,

я не знаю, что ты использовал ORACLE. Мое решение использует SQL Server. Надеюсь, вы получите суть решения и перейдете на PL/SQL.

Надеюсь, это полезно для вас.

Я вручную заполняю таблицу temp #search. Вам нужно как-то это сделать. Или найдите некоторую функцию разделения, которая примет строку с разделителями и вернет таблицу.

IF OBJECT_ID('tempdb..#keywords') IS NOT NULL 
    DROP TABLE #keywords; 

IF OBJECT_ID('tempdb..#search') IS NOT NULL 
    DROP TABLE #search; 

DECLARE @search_count INT 

-- Populate # search with all my search strings 
SELECT * 
INTO #search 
FROM (
    SELECT '%ST%' AS Search 

    UNION ALL 

    SELECT '%CL%' 
    ) T1 

SELECT @search_count = COUNT(*) 
FROM #search; 

PRINT @search_count 

-- Populate my #keywords table with all column values from my table with table id and values 
-- I just did a select id, value union with all fields 
SELECT * 
INTO #keywords 
FROM (
    SELECT client_id AS id 
     ,First_name AS keyword 
    FROM [CLIENT] 

    UNION 

    SELECT client_id 
     ,last_name 
    FROM [CLIENT] 
    ) AS T1 

-- see what is in there 
SELECT * 
FROM #search 

SELECT * 
FROM #keywords 

-- I am doing a count(distinct #search.Search). This will get me a count, 
--so if I put in 3 search values my count should equal 3 and that tells me all search strings have been found 
SELECT #keywords.id 
    ,COUNT(DISTINCT #search.Search) 
FROM #keywords 
INNER JOIN #search ON #keywords.keyword LIKE #search.Search 
GROUP BY #keywords.id 
HAVING COUNT(DISTINCT #search.Search) = @search_count 

SELECT * 
FROM [CLIENT] 
WHERE [CLIENT].client_id IN (
     SELECT #keywords.id 
     FROM #keywords 
     INNER JOIN #search ON #keywords.keyword LIKE #search.Search 
     GROUP BY #keywords.id 
     HAVING COUNT(DISTINCT #search.Search) = @search_count 
     ) 
+0

Если я правильно понимаю, вы в основном создаете временную таблицу со словами, которые ищете, а затем используйте UNION между этой временной таблицей и обычаемой таблицей. Таким образом, в зависимости от того, какая строка была добавлена, количество раз количества ключевых слов должно соответствовать.Но что, если определенная строка имеет реплицированные данные, например: col1 (url): «http: // domain/phones/samsung/s5» col2 (product_title): «samsung s5» Будут ли присоединены определенные ключевые слова к один столбец дважды? Каждое ключевое слово может встречаться только один раз подряд. – Edwin

+0

@ Edwin, поэтому, если у меня есть 2 столбца выше, как вы говорите, и мои строки поиска - это «samsung» и «galaxy», должна ли эта строка быть возвращена в результатах? а также, если у меня есть 2 столбца, как вы сказали выше, и моя строка поиска была «samsung», если эта строка будет возвращена? –

+0

Если мы возьмем 2 столбца выше с данными «domain/phones/samsung/s5» и «samsung s5», а затем ищем «samsung» и «galaxy», строка не должна возвращаться, потому что «галактика» не была в любой колонке. Но если вы только искали «samsung», строка должна быть возвращена. @Ed Mendez – Edwin

0

Вы можете создать хранимую процедуру или функцию в PL/SQL для динамического поиска в таблице для условий поиска, а затем вернуть первичный ключ и столбец любых матчей. Пример кода, приведенный ниже, должен быть достаточным для соответствия вашим требованиям.

create table text_table(
    col1 varchar2(32), 
    col2 varchar2(32), 
    col3 varchar2(32), 
    col4 varchar2(32), 
    col5 varchar2(32), 
    pk varchar2(32) 
); 

insert into text_table(col1, col2, col3, col4, col5, pk) 
values ('the','quick','brown','fox','jumped', '1'); 
insert into text_table(col1, col2, col3, col4, col5, pk) 
values ('over','the','lazy','dog','!', '2'); 

commit; 

declare 

    rc     sys_refcursor; 
    cursor_num   number; 
    col_count   number; 
    desc_tab   dbms_sql.desc_tab; 
    vs_column_value  varchar2(4000); 
    search_terms  dbms_sql.varchar2a; 
    matching_cols  dbms_sql.varchar2a; 
    empty    dbms_sql.varchar2a; 
    key_value   varchar2(32); 

begin 

    --words to search for (i.e. from the text box) 
    search_terms(1) := 'fox'; 
    search_terms(2) := 'box'; 

    open rc for select * from text_table; 

    --Get the cursor number 
    cursor_num := dbms_sql.to_cursor_number(rc); 

    --Get the column definitions 
    dbms_sql.describe_columns(cursor_num, col_count, desc_tab); 

    --You must define the columns first 
    for i in 1..col_count loop 
    dbms_sql.define_column(cursor_num, i, vs_column_value, 4000);  
    end loop; 

    --loop through the rows  
    while (dbms_sql.fetch_rows(cursor_num) > 0) loop 

    matching_cols := empty; 

    for i in 1 .. col_count loop --loop across the cols 

     --Get the column value 
     dbms_sql.column_value(cursor_num, i, vs_column_value); 

     --Get the value of the primary key based on the column name 
     if (desc_tab(i).col_name = 'PK') then 
      key_value := vs_column_value; 
     end if; 

     --Scan the search terms array for a match 
     for j in 1..search_terms.count loop 
      if (search_terms(j) like '%'||vs_column_value||'%') then 
       matching_cols(nvl(matching_cols.last,0) + 1) := desc_tab(i).col_name; 
      end if; 
     end loop;  
    end loop; 

    --Print the result matches 
    if matching_cols.last is not null then 
     for i in 1..matching_cols.last loop 
      dbms_output.put_line('Primary Key: '|| key_value||'. Matching Column: '||matching_cols(i)); 
     end loop; 
    end if; 

    end loop; 

end; 
+0

Это хороший подход, но проблема в том, где вы просматриваете столбцы, чтобы увидеть, совпадает ли он с одним из условий поиска. Он сразу же добавит его в соответствующий результат столбцов, даже если есть только одно совпадение. ** Я требую, чтобы каждый из поисковых терминов происходил по крайней мере один раз ** в указанной строке. И даже добавление переменной счетчика, чтобы сказать, что количество совпадений найдено в строке, может быть ошибочным из-за возможности избыточности (как в моем комментарии к ответу Эд Мендеса) – Edwin

Смежные вопросы