通过在SQL表的多列中拆分字符串进行搜索?

时间:2015-08-08 08:06:11

标签: c# sql asp.net sql-server full-text-search

我有一个Books表:

Title                     Board    Class
----------------------------------------
Interactive English       CBSE       9
Interactive  Math         ICSE      10
Hindi                     CBSE       9

我在asp.net网站上有一个搜索文本框。如果用户输入 文本框中的"9 CBSE",我的选择查询应返回

Title                      Board    Class
-----------------------------------------
Interactive English        CBSE        9
Hindi                      CBSE        9

如果用户输入"9 English",则应返回

Title                      Board    Class
------------------------------------------
Interactive English        CBSE        9

那么我的选择查询应该将文本框值与所有这三列匹配?

6 个答案:

答案 0 :(得分:1)

我无法验证这一点,因为我现在无法访问Sqlserver,但这应该可行:

select
 *
from
 books
where
  patindex('%' + left(_textbox_contents_, charindex(' ') - 1) + '%',  Title + Board + Class) > 0 
  and  patindex('%' + substring(_textbox_contents_, charindex(' ') + 1) + '%',  Title + Board + Class) > 0 

答案 1 :(得分:0)

如果你可以在发送查询之前拆分c#中的字符串并创建包含部分的变量,例如:

string1 =“9” string2 =“英语”

然后你需要向每一方添加'%'给你:

string1 =“%9%” string2 =%英文%“

然后将查询传递为:

Select *
  from books
 where (title like string1
     or title like string2)
    or (board like string1
     or board like string2)
    or (class like string1
     or class like string2);

我想在发送查询之前将搜索字符串拆分比尝试使用SQL更容易,在那里你需要做一堆instrings和substrings。

答案 2 :(得分:0)

为了解决这个问题,我们应该计划如何解决这个问题。

  1. 我们应该从搜索输入中提取标题或主板值和数字值(如果可用)。
  2. 我们应该按照与TitleBoard列中的提取值匹配的顺序构建 SQL查询
  3. 我们应该尝试在 SQL查询中找到Number匹配,前提是Number确实被提取出来(如果它被提取的话,它的值不同于{{1} }或null)。
  4. SearchInput:表示搜索输入值的实体

    Whitespace

    CreateSearchInput:将输入字符串转换为上述实体。

    搜索字符串中的第一个值是否为数字。如果第一个值是一个数字而不是将其分配给public class SearchInput { public string TitleOrBoard { get; set; } public string Number { get; set; } } 并从输入字符串中删除该数字。

    Number

    ConstructSearchQuery:根据public static SearchInput CreateSearchInput(string input) { var inputSplitted = input.Trim().Split(new [] { ' ' }, StringSplitOptions.RemoveEmptyEntries); int number; string searchText = ""; if (int.TryParse(inputSplitted.First(), out number)) { searchText = String.Join(" ", inputSplitted.Skip(1)); } var searchInput = new SearchInput() { Number = number.ToString(), TitleOrBoard = searchText }; return searchInput; } 实体值构建SQLQuery。

    SearchInput

    主要功能

    public static string ConstructSearchQuery(SearchInput searchInput)
    {
        StringBuilder sb = new StringBuilder("SELECT * FROM Books WHERE");
        sb.AppendFormat(" ([Title] LIKE '%{0}%' OR [Board] LIKE '%{0}%')", searchInput.TitleOrBoard);
        if (!String.IsNullOrWhiteSpace(searchInput.Number))
        {
            sb.AppendFormat(" OR Class = '%{0}%'", searchInput.Number);
        }
        return sb.ToString();
    }
    

    <强>输出:

    public static void Main()
    {
        string input = "9 English";
        var searchInput = CreateSearchInput(input);
        string sqlQuery = ConstructSearchQuery(searchInput);
        Console.WriteLine("Search: Number[{0}] TitleOrBoard[{1}]", searchInput.Number, searchInput.TitleOrBoard);
        Console.WriteLine("SQL Query: {0}", sqlQuery);
    }
    

    .NET Fiddle

答案 3 :(得分:0)

try this,

        declare @t table (Title  varchar(100), Board varchar(10),   Class int)
        declare @chk varchar(10)='9 English'
        insert into @t (Title, Board,   Class) values
        ('Interactive English','CBSE',9),
        ('Interactive  Math','ICSE',10),
        ('Hindi','CBSE',9)



select * from @t where  cast(Class as varchar(2)) +' '+Board  like '%' + @chk +'%' 
or Board +' '+cast(Class as varchar(2)) like '%' + @chk +'%' or

cast(Class as varchar(2)) +' '+case when charindex(' ', title)=0 then  
title else REverse(substring(reverse(title),1,charindex(' ', REVERSE(title))-1)) end 
like '%' +@chk +'%' or

case when charindex(' ', title)=0 then  
title else REverse(substring(reverse(title),1,charindex(' ', REVERSE(title))-1)) end +' '+cast(Class as varchar(2)) 
like '%' +@chk +'%' 

答案 4 :(得分:0)

如果您愿意找到所有搜索关键字至少匹配一个值的结果,那么这应该对您有用:

private string BuildQueryString(List<string> keywords)
{
    List<string> numbers = keywords.Where(keyword => keyword.All(Char.IsDigit))
                                   .ToList();

    List<string> words = keywords.Except(numbers)
                                 .Select(keyword => string.Format("('{0}')", keyword))
                                 .ToList();

    var queryBuilder = new StringBuilder();

    if (words.Count > 0)
    {
        queryBuilder.AppendFormat(@"
            CREATE TABLE #Keywords
            (
                Keyword NVARCHAR(MAX)
            )

            INSERT INTO #Keywords (Keyword)
            VALUES {0} ",

            string.Join(", ", words));
    }

    queryBuilder.AppendFormat(@"
        SELECT Title, Board, Class
        FROM Books ");

    string numbersFilter = string.Format("Class IN ({0})", string.Join(", ", numbers));
    string wordsFilter = @"EXISTS (SELECT TOP 1 1
                                   FROM #Keywords
                                   WHERE Title LIKE '%' + Keyword + '%'
                                      OR Board LIKE '%' + Keyword + '%')";

    if (numbers.Count > 0 && words.Count > 0)
    {
        queryBuilder.AppendFormat(@"
            WHERE {0} AND {1}", numbersFilter, wordsFilter);
    }
    else if (numbers.Count > 0)
    {
        queryBuilder.AppendFormat(@"
            WHERE {0}", numbersFilter);
    }
    else if (words.Count > 0)
    {
        queryBuilder.AppendFormat(@"
            WHERE {0}", wordsFilter);
    }

    return queryBuilder.ToString();
}

用例示例:

txtSearch.Text = "CBSE 9 MEH 23 Hey 90 N0 Word1";

List<string> keywords = txtSearch.Text
    .Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
        .ToList();

string queryString = BuildQueryString(keywords);

您的查询字符串将返回此搜索文本的下一个查询:

Query

对于您在问题描述中提供的表格内容,此查询的结果将产生下一个结果:

Table result

这两个记录都与Class列中的9和Board列中的CBSE相匹配。如果您想要不同的行为,可以在查询构建器中更改 ANDs ORs ,但通常,这就是您要求的。希望它有所帮助。

答案 5 :(得分:0)

使用全文查询,您可以为最终用户提供构建搜索的灵活性。此外,您不需要对搜索字符串执行尽可能多的解析,并且搜索通常比使用LIKE更快。

<强> 1。创建全文目录和索引。

CREATE FULLTEXT CATALOG [ftcat_Books] WITH ACCENT_SENSITIVITY = OFF
GO

CREATE FULLTEXT INDEX ON [Books] ([Title] LANGUAGE 'English', [Board] LANGUAGE 'English', [Class] LANGUAGE 'English')
KEY INDEX [PK_Books] ON ([ftcat_Books], FILEGROUP [PRIMARY])
WITH (CHANGE_TRACKING = AUTO, STOPLIST = OFF)

您的Books.Class列必须为varchar或nvarchar才能生效。

我建议不要使用任何名单(STOPLIST = OFF),这样就不会忽略单个数字,例如你的例子中的9。

More about accent sensitivity(此示例不使用重音敏感度)

More about change tracking(此示例使用更改跟踪)

<强> 2。将用户查询转换为布尔语法。

当用户输入9 CBSE时,必须将其转换为"9" AND "CBSE"。每个术语必须用双引号括起来并用&#34; AND&#34;分隔。 (您也可以使用OR,NOT,NEAR和通配符,但我不确定您是否需要它们。)

这里是一种使用.NET正则表达式转换为所需布尔语法的简单方法(基本上,用" AND "替换每个1+空格的系列,并用更多双引号括起结果):

// assume searchString = "9 CBSE"
string searchStringBoolean = "\"" + Regex.Replace(searchString, @"\s+", "\" AND \"") + "\"";

请记住,这是一种非常简单的方法。如果用户已在其搜索字符串中键入双引号或AND,则需要考虑该怎么做。

第3。运行全文查询。

-- @SearchStringBoolean is the boolean string created in step 2
SELECT TOP 100 Books.Title, Books.Board, Books.Class
FROM ContainsTable(Books, *, @SearchStringBoolean) as FullTextResults
join Books on FullTextResults.KEY = Books.Id
ORDER BY FullTextResults.RANK desc

这将返回前100个匹配项,其中包含最先排序的最佳匹配项。