Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2005 Forums
 Transact-SQL (2005)
 Searching a Table

Author  Topic 

ronnieoverby
Starting Member

36 Posts

Posted - 2008-09-05 : 09:23:49
I want to search a table using a stored procedure that accepts one parameter.

If the parameter is 'firstname lastname' I want to search all columns for like %firstname% then like %lastname%. I would like the same functionality if there were 3,4,n words delimited by a space.

Whats the best way to do this? There are no columns with lots of text. The largest column is nvarchar(65). Should I consider full text search?

Thanks!

blindman
Master Smack Fu Yak Hacker

2365 Posts

Posted - 2008-09-05 : 10:24:54
That makes absolutely no sense at all.
Please explain your requirements more clearly, with examples, if you want assistance.

Boycotted Beijing Olympics 2008
Go to Top of Page

ronnieoverby
Starting Member

36 Posts

Posted - 2008-09-05 : 11:02:22
Sorry,
Here is my table:

ColleagueID int 4 PK
FirstName nvarchar 100
MiddleName nvarchar 100
LastName nvarchar 100
JobTitle nvarchar 130
DepartmentName nvarchar 100
DivisionName nvarchar 100
Extension varchar 4


The end user will have a single text box and search button where they can search all of these columns:

FirstName
MiddleName
LastName
JobTitle
DepartmentName
DivisionName

REQUIREMENTS:
Basically I want to search all fields for each word in the search string, allowing for inexact matches (example: 'ron' matches 'Ronnie') Also, if the search string contains multiple words, returned records must match ALL words.

EXAMPLES:

End user search query: 'ron over'
This would return the records having %ron% in ANY column AND %over% in ANY column, where % represents a wildcard.
For example, the record with FirstName = 'Ronnie' & LastName = 'Overby' would be a match.

End user search query: 'online'
This would return the records having %online% in ANY column, where % represents a wildcard.

I have never searched a table this way before and I am researching the best way to do it. Thanks in advance for any help!
Go to Top of Page

blindman
Master Smack Fu Yak Hacker

2365 Posts

Posted - 2008-09-05 : 11:51:19
There is no best way to do this.
The requirements are going to ensure that whatever you come up with is inefficient.
But your best bet would probably be full text search.

Boycotted Beijing Olympics 2008
Go to Top of Page

ronnieoverby
Starting Member

36 Posts

Posted - 2008-09-05 : 11:57:26
Well, if that's my "best bet", then it's the best way as far as I am concerned.

Here is something I was playing with:

SELECT *
FROM Directory.Employees
WHERE CONTAINS ( *, '"*ron*"' )
INTERSECT
SELECT *
FROM Directory.Employees
WHERE CONTAINS ( *, '"*over*"' )



This achieves the effect I want, but of course I can't actually do it this way. Can anyone offer any ideas for getting this to work with a single text box?
Go to Top of Page

ronnieoverby
Starting Member

36 Posts

Posted - 2008-09-05 : 16:04:41
I created a CLR stored procedure and got this to work. Below is the code. Does anyone see any major problems with this? I think I will limit the # of allowed words coming in to keep someone from overworking the database.


using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;


public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void SearchEmployees( SqlString searchText )
{
/* This sproc builds a sql statement from the searchText parameter.
* The words in the searchtext delimited by space are split into an array.
* The array is traversed and a tsql statement is constructed.
*
* Example: @searchText = 'ron over dwayne'
*
* HERE IS THE CONSTRUCTED SQL STATEMENT: *
*
SELECT *
FROM Directory.Employees
WHERE CONTAINS ( *, '"*ron*"' )
INTERSECT
SELECT *
FROM Directory.Employees
WHERE CONTAINS ( *, '"*over*"' )
INTERSECT
SELECT *
FROM Directory.Employees
WHERE CONTAINS ( *, '"*dwayne*"' )
*
* The result set would be all rows that match EVERY WORD in the array in AT LEAST ONE COLUMN.
* Wildcards are appended before and after each word.
*/

SqlCommand cmd = new SqlCommand();
cmd.Connection = new SqlConnection("context connection=true");

// template for sql statement; {0} is where each word will be inserted
string sqlTemplate = "SELECT * FROM Directory.Employees WHERE CONTAINS ( *, '\"*{0}*\"' )";
string sql = string.Empty;

// split parameter into array of words
string[] searchWords = searchText.ToString().Split(' ');

// iterate through array, building sql statement
for (int i = 0; i < searchWords.Length; i++)
{
sql += string.Format(sqlTemplate, searchWords[i]);
if (i != searchWords.Length - 1)
{
sql += " INTERSECT "; // on all but last pass, INTERSECT is inserted into statement
}
}

// set commandtext of command to sql statement we just built
cmd.CommandText = sql;

//Get a reference to the SqlPipe for this calling context
SqlPipe pipe = SqlContext.Pipe;

// do the deed
cmd.Connection.Open();
pipe.Send(cmd.ExecuteReader());
cmd.Connection.Close();

}
};
Go to Top of Page

blindman
Master Smack Fu Yak Hacker

2365 Posts

Posted - 2008-09-05 : 16:27:37
Whoever thought up CLRs at Microsoft deserves to be shot.

Boycotted Beijing Olympics 2008
Go to Top of Page

ronnieoverby
Starting Member

36 Posts

Posted - 2008-09-06 : 11:33:16
Blindman, will you just stop looking at this thread?

When I get a topic reply notification, there is a tinge of excitement because I think maybe someone has something useful to say in response to my problem. And then I come on here and see more of your useless comments. You haven't helped me in the slightest.

I am a relatively new developer; I don't know the best way to do many things. I search the net trying to find some guidance before I ever think about creating a thread about a given problem. If I feel like I am wasting too much time searching, when I could just ask someone more knowledgeable, I come here. So, please, if you don't have anything that will contribute to my solving a problem, why waste your time and mine?

That's a rhetorical question, by the way. Don't even bother with one of your famous replies.
Go to Top of Page

preethi
Starting Member

11 Posts

Posted - 2008-09-06 : 13:46:09
Hi Ronnie,
I Understand your worries. I have a couple of concerns over the functionality as it may scan the entire table each time a person uses this functionality. it may cripple the other procedures from using this table.

However, given your scenario I have a solution:

1. Create a fucntion whcih splits the string into a table. For this purpose you can write a CLR User defined function code also. It could be faster (I haven't checked it.
2. Write a procedure which joins with your table for a search. The join condition is complex I suggest that you should use multiple IF conditions (if not multiple procedures) so that deifferent execution plans could be used if each statement and each will be optimized for each condition.


Here is the sample code:

CREATE FUNCTION dbo.GetList(@NameList nvarchar(MAX))
RETURNS @RetTable Table (name nvarchar(20))
AS
BEGIN
DECLARE @FirstPos int, @EndPos int, @Len int
SELECT @Len = Len(@NameList), @FirstPos = 0

WHILE @FirstPos < @Len
BEGIN
SELECT @EndPos = charindex(' ', @NameList, @FirstPos + 1)

IF @EndPos = 0 SELECT @EndPos = @Len + 1

INSERT INTO @RetTable VALUES (LTrim(SUBSTRING(@IDList, @FirstPos + 1, @EndPos - @FirstPos - 1)))

SELECT @FirstPos = @EndPos
END

RETURN
END

GO

CREATE PROCEDURE dbo.Search (@NameList nvarchar(MAX),@Column varchar(100))
AS
BEGIN
IF @Column = ''
BEGIN
SELECT <COLUMNList>
FROM Directory.Employee e,
dbo.GetList(@NameList) l
WHERE (e.FirstName like '%'+l.name+'%' OR
e.LastName like '%'+l.name+'%' OR
-- the rest of the columns come here
)
END

IF @Column = 'FirstName'
BEGIN
SELECT <COLUMNList>
FROM Directory.Employee e,
dbo.GetList(@NameList) l
WHERE (e.FirstName like '%'+l.name+'%')
END
-- The rest of the code comes here.



END
GO



Hope this helps!

Cheers,
Preethiviraj Kulasingham
MCITP: DBA
Go to Top of Page

ronnieoverby
Starting Member

36 Posts

Posted - 2008-09-06 : 18:50:44
Thanks, preethi! I appreciate the code for the function to disect the string; it helps a lot. I also like the option to pass a column name to the search procedure. That will add some nice flexability.

One question I have is about the CLR code. You said that I could write my UDF in CLR code, but the examples you provided were in TSQL. I'd just like to know what your thought on writing code to run in the CLR? I have just scratched the surface on writing code in the CLR and I am curious about the pros and cons.

Thanks, again!
Go to Top of Page

blindman
Master Smack Fu Yak Hacker

2365 Posts

Posted - 2008-09-07 : 12:22:21
quote:
Originally posted by ronnieoverby

Blindman, will you just stop looking at this thread?

I can't help myself. It's like watching a train wreck in slow motion. Ghastly and fascinating at the same time.

Boycotted Beijing Olympics 2008
Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2008-09-08 : 15:13:38
Hi -- Here's another way to do what you need, with a little more flexibility but you can always adapt as you like:

http://weblogs.sqlteam.com/jeffs/archive/2004/11/02/2460.aspx

- Jeff
http://weblogs.sqlteam.com/JeffS
Go to Top of Page

ronnieoverby
Starting Member

36 Posts

Posted - 2008-09-08 : 15:20:15
Thanks! I may try that.

I have actually moved my thoughts to a different architechture for this application, altogther. Instead of having every search hit a procedure at the database, I am going to cache my table on the web server, and filter the cached data (a strongly typed collection of employee record objects) using LINQ to Objects. Sound ok?
Go to Top of Page
   

- Advertisement -