views:

119

answers:

4

I'm trying to search several tables at once for a search term. My query is:

SELECT item.ItemID 
    FROM Inventory.Item item 
        JOIN Inventory.Category catR // each item can be in several categories
            ON catR.ItemID = item.ItemID 
        JOIN Category.Category cat 
            ON cat.CategoryID = catR.CategoryID 
        JOIN Inventory.Brand bran 
            ON bran.BrandID = item.BrandID
    WHERE
         item.Description LIKE '%' + @term + '%'
       OR
         item.Description LIKE '%' + @term
       OR
         item.Description LIKE @term + '%'
       OR
         item.Description = @term
       OR
         cat.CategoryName LIKE '%' + @term + '%'
             //same pattern as item.Description used to search CategoryName
             //...
       OR
         bran.BrandName LIKE '%' + @term + '%'
             //same pattern as item.Description used to search BrandName
             //...

But the results are not as expected. I have about 50 items in the category "Casement" but when term == "Casement" only items that have "Casement" in their item.Description will be returned.

Am I doing something wrong? Should I do this a better way?

+1  A: 

Its enough to write

item.Description LIKE '%' + @term + '%'

instead of

item.Description LIKE '%' + @term + '%'
OR
   item.Description LIKE '%' + @term
OR
   item.Description LIKE @term + '%'
OR
   item.Description = @term
Jan
A: 

Try this:

Select i.ItemID    
From Inventory.Item i
  Join Inventory.Category ic
    On ic.ItemID = i.ItemID         
  Join Category.Category cc            
    On cat.CategoryID = ic.CategoryID         
  Join Inventory.Brand ib
    On ib.BrandID = i.BrandID
Where CharIndex(@Term,
      i.Description + '|' + 
     ic.Description + '|' +
     cc.Description + '|' +
     ib.Description) > 0

Realize that this will cause a full table scan of all four tables, so it will be slow if these tables are large. But given what you are trying to do, the only alternative would be to implement full text indices on the database...

Also, if it is possiblke that one of these tables does not contain a matching row for yr join condition, you should make all the joins outer joins, and use IsNull() on all the column references...

Select i.ItemID    
From Inventory.Item i
  Left Join Inventory.Category ic
    On ic.ItemID = i.ItemID         
  Left Join Category.Category cc            
    On cat.CategoryID = ic.CategoryID         
  Left Join Inventory.Brand ib
    On ib.BrandID = i.BrandID
Where CharIndex(@Term,
      i.Description + '|' + 
     IsNull(ic.Description, '') + '|' +
     IsNull(cc.Description, '') + '|' +
     IsNull(ib.Description, '')) > 0
Charles Bretana
For some reason this selected every record in the database.
David Murdoch
What value for @Term did you pass in ? If you pass in a value that is 'In' every record's Description field, then it will return every record, otherwise you are doing something else in your query that is 'including all the records... and Oh, I had an extra comma in there, that should have caused the SQL to throw a syntax error, it's removed now...
Charles Bretana
+2  A: 

Conceptually I would keep it simple and then change it from there if needed for performance. First I would create a view and then do the select off of that.

CREATE VIEW vSearchTables
AS

SELECT item.ItemID, 'Item' AS TableName, item.Descripton AS Txt
FROM Inventory.Item item

UNION ALL

SELECT catR.ItemID, 'Category' AS TableName, cat.CategoryName AS Txt
FROM Inventory.Category catR 
JOIN Category.Category cat  
ON cat.CategoryID = catR.CategoryID 

UNION ALL

SELECT item.ItemID, 'Brand' AS TableName, bran.BrandName AS Txt
FROM Inventory.Item  item
JOIN Inventory.Brand bran
ON bran.BrandID = item.BrandID 

GO



SELECT ItemID
FROM vSearchTables
WHERE Txt LIKE '%'+@term +'%'


GO

If you have sql2005 and want to test this concept you can run the following:

CREATE VIEW vSearchTables 
AS 

select object_name(o.object_id) Object, o.type, m.definition as Txt
from sys.sql_modules m    
join sys.objects o on m.object_id = o.object_id    

GO


SELECT *
FROM vSearchTables 
WHERE Txt LIKE '%TRIGGER%'
JBrooks
Thanks, I'll give it a try in the morning and let you know.
David Murdoch
I'm still going to try this...just haven't had the time.
David Murdoch
I got an error: "Incorrect syntax near 'VIEW'"
David Murdoch
CREATE VIEW has to be the first line you submit. I updated my post to show an example that will work on any sql2005.
JBrooks
+1  A: 

This is a good CTE example:

WITH items AS (
     SELECT i.itemid,
            i.description,
            cat.category_name,
            b.brandname 
       FROM INVENTORY.ITEM i 
  LEFT JOIN INVENTORY.CATEGORY c ON c.itemid = i.itemid
  LEFT JOIN CATEGORY.CATEGORY cat ON cat.CategoryID = c.categoryid
  LEFT JOIN INVENTORY.BRAND b ON b.brandid = i.brandid)
SELECT a.itemid
  FROM items a
 WHERE a.description LIKE '%' + @term + '%'
UNION ALL
SELECT b.itemid
  FROM items b
 WHERE b.categoryname LIKE '%' + @term + '%'
UNION ALL
SELECT c.itemid
  FROM items c
 WHERE c.brandname LIKE '%' + @term + '%'

CTEs are supported in SQL Server 2005+.

OMG Ponies
This worked great. Thanks!
David Murdoch