views:

52

answers:

2

I currently have a query that returns results based on a dynamic set of conditions

DataTable Items:
    ID   Title
    1    Some title
    2    Some other title
..etc..

.

DataTable Tags:
    ID   Tag
    1    'a1c'
    1    'a1d'
    2    'a2c'
..etc..

My current search Query:

select * from dbo.Items i
LEFT JOIN dbo.tags t
on i.ID = t.ID
INNER JOIN @input in
on (in.[input] = t.Tag or in.[input] is null)

An input would be something like:

DECLARE @input as inputTable_type
INSERT INTO @input VALUES ('a1c')

What I would like to do is use a value like 'a1%' as an input, but when I try that, I get no results (although I do know that a query such as the following does work):

select * from dbo.Items i
INNER JOIN dbo.tags t
on i.ID = t.ID
and t.Tag like ('a1%')

Unfortunately, I want to keep it a static query, and as far as I know, I need the LEFT JOIN - INNER JOIN combination that I have in order to be able to pass VALUES (NULL) into the stored procedure.

Thanks for any thoughts and help, and let me know if I can clarify anything!

+1  A: 

Rather than trying to store 'a1%' in your @input table, store just 'a1', then I think the (untested) code below will give you what you want.

select * 
    from dbo.Items i
        LEFT JOIN dbo.tags t
            INNER JOIN @input in
                on in.[input] = left(t.Tag, len(in.[input]))
            on i.ID = t.ID
    where (t.ID is not null or not exists(select 1 from @input))
Joe Stefanelli
@Joe - Thanks for the response, this looks great, as it is giving me the results I need, but if I were to not have a `tag` for a given item, I'm still receiving NULL values in my result set even though I've specified a Tag to search by...
Brett
@Brett: I added a `where` clause that should help with that.
Joe Stefanelli
@Joe - Thanks, yeah, I had done something similar, I hadn't thought about it too much before I commented. This solution worked great for me, but I was wondering if you would be able to explain the difference between putting the `ON i.ID = t.ID` condition for the left join BEFORE the INNER JOIN versus AFTER the INNER JOIN? I noticed the results will include NULL values from `Tags` in your code, but NOT include NULL values from `Tags` if the ON condition is moved.
Brett
@Brett: You can think of the version I wrote as a `LEFT JOIN` to a derived table that consists of the `INNER JOIN` of the other two `(dbo.tags t INNER JOIN @input in...)` Since it sounds like you don't want the NULLs in your case, your version would be the appropriate one in this case.
Joe Stefanelli
+1  A: 

Since you're already playing funny games with the outer joined table, why not extend the games? The simplest version is to replace the equality with LIKE; the next simplest version is to add an OR term:

SELECT *
  FROM dbo.Items i
  LEFT JOIN dbo.tags t ON i.ID = t.ID
 INNER JOIN @input  in ON (t.Tag = in.[input] OR
                           t.Tag LIKE in.[input] OR
                           in.[input] IS NULL)

The next grade up in sophistication (or do I mean 'complication'?) is to add a second column to the @input table which indicates the comparison to perform:

SELECT *
  FROM dbo.Items i
  LEFT JOIN dbo.tags t ON i.ID = t.ID
 INNER JOIN @input  in ON ((in.[type] = '=' AND t.Tag = in.[input]) OR
                           (in.[type] = '%' AND t.Tag LIKE in.[input]) OR
                           in.[input] IS NULL)

I've chosen to call the extra column 'type' and the value in it is a single character, using '=' to indicate an equality join and '%' to indicate a LIKE join.

Jonathan Leffler