匹配所有列与所有搜索短语

时间:2014-09-25 20:51:45

标签: c# sql plsql

我想让用户搜索表格中的所有列,查找文本框中定义的一组短语(使用空格分割术语)。 首先想到的是在SQL中找到一种方法来连接所有列,并在此结果中使用LIKE运算符(对于每个短语)。 我想到的另一个解决方案是编写一个算法,该算法将搜索所有短语,并将它们与所有列匹配。 所以我最终得到了以下内容:

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

然后我接受了所有可能的列和短语组合,并将其放入sql的where子句格式,然后结果是

"(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个搜索短语仍然可以提供良好的性能,但不止于此肯定会大大降低性能。

搜索所有相同数据的列时,最佳做法是什么?

2 个答案:

答案 0 :(得分:0)

埃德,

我不知道你在使用ORACLE。我的解决方案是使用SQL Server。希望您能获得解决方案的要点并转换为PL / SQL。

希望这对你有用。

我手动填充#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
        )

答案 1 :(得分: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;