SELECT with variable number of search requirements

  • Given tables-

    Client

    ClientId (IDENTITY)

    LastName

    FirstName

    MiddleName

    ClientAccount

    AccountId (IDENTITY)

    ClientId (FK)

    AccountNumber

    I need to write a query that returns a list of Client Ids that match ALL search terms entered by a user. Search terms are entered into one text box, and for simplicity's sake we'll say can include Name or AccountNumber. An example might look like 'John A78389S87 Smith'. Although it is visually obvious that 'A78389S87' is probably an Account Number, programmatically I have no good way of knowing this.

    Given that

    searchTerm1 = 'John'

    searchTerm2 = 'A78389S87'

    searchTerm3 = 'Smith'

    and given that the number of search terms is variable, how do I gracefully accomplish something like the following?

    SELECT c.ClientId

    FROM Client c

    JOIN ClientAccount ca ON c.ClientId = ca.ClientId

    WHERE(searchTerm1 = c.LastName

    OR searchTerm1 = c.FirstName

    OR searchTerm1 = c.MiddleName

    OR searchTerm1 = ca.AccountNumber)

    AND(searchTerm2 = c.LastName

    OR searchTerm2 = c.FirstName

    OR searchTerm2 = c.MiddleName

    OR searchTerm2 = ca.AccountNumber)

    AND(searchTerm3 = c.LastName

    OR searchTerm3 = c.FirstName

    OR searchTerm3 = c.MiddleName

    OR searchTerm3 = ca.AccountNumber)

  • would it not be possible to enter you various search items into a temp table/table variable with 1 col and do various left joins onto your main table and take results that are not null as matches?

    How does that sound?

    ----------------------------------------------
    Try to learn something about everything and everything about something. - Thomas Henry Huxley

    :w00t:
    Posting Best Practices[/url]
    Numbers / Tally Tables[/url]

    SQL-4-Life
  • something like this:

    CREATE TABLE Client

    (ClientId INT IDENTITY(1,1),

    LastName VARCHAR(100),

    FirstName VARCHAR(100),

    MiddleName VARCHAR(100))

    CREATE TABLE ClientAccount

    (AccountId INT IDENTITY(1,1),

    ClientId INT,

    AccountNumber VARCHAR(100))

    --TEST DATA

    INSERT INTO Client

    SELECT 'Stobbs', 'Chris' , 'Terence' UNION ALL

    SELECT 'Joe', 'Blogs' , 'Middle' UNION ALL

    SELECT 'Jane', 'Doe' , 'Middle'

    INSERT INTO ClientAccount

    SELECT 1, 'A12313121' UNION ALL

    SELECT 2, 'B12313321' UNION ALL

    SELECT 3, 'C12313991'

    --CODE TO SEARCH

    DECLARE @SearchString VARCHAR(MAX)

    DECLARE @Delimiter VARCHAR(10)

    SET @Delimiter = ' '

    SET @SearchString = 'Middle A12313121'

    DECLARE @Search TABLE

    (Val VARCHAR(100))

    INSERT INTO @Search

    SELECT SUBSTRING(@SearchString+@Delimiter, n,

    CHARINDEX(@Delimiter, @SearchString+@Delimiter, n) - n)

    FROM tally

    WHERE n <= LEN(@SearchString)

    AND SUBSTRING(@Delimiter + @SearchString,

    n, 1) = @Delimiter

    ORDER BY n

    SELECT * FROM @Search

    SELECT *

    FROM Client cl

    INNER JOIN ClientAccount ca ON cl.ClientId = ca.ClientId

    LEFT JOIN @Search a ON a.val = cl.LastName

    LEFT JOIN @Search b ON b.val = cl.FirstName

    LEFT JOIN @Search c ON c.val = cl.MiddleName

    LEFT JOIN @Search d ON d.val = ca.AccountNumber

    WHERE COALESCE(a.val,b.val,c.val,d.val) IS NOT NULL

    ----------------------------------------------
    Try to learn something about everything and everything about something. - Thomas Henry Huxley

    :w00t:
    Posting Best Practices[/url]
    Numbers / Tally Tables[/url]

    SQL-4-Life
  • Thanks for your reply Chris. It feels close but seems to give results where ANY of the search terms match instead of ALL. I'll keep working on it....

  • ah sorry I must have miss read the spec...

    if you need more help just shout

    ----------------------------------------------
    Try to learn something about everything and everything about something. - Thomas Henry Huxley

    :w00t:
    Posting Best Practices[/url]
    Numbers / Tally Tables[/url]

    SQL-4-Life
  • suggestion:

    alter function dbo.fParameterMatrix(

    @parm1 varchar(64), @parm2 varchar(64), @parm3 varchar(64), @parm4 varchar(64)

    )

    returns @matrix table

    (

    firstName varchar(64),

    lastName varchar(64),

    accountNumber varchar(64),

    otherField varchar(64),

    numFields as isnull(sign(len(lastName)),0)+

    isnull(sign(len(firstName)),0)+

    isnull(sign(len(accountNumber)),0)+

    isnull(sign(len(otherField)),0),

    duplicateFields as case when lastName in (firstName,accountNumber,otherField)

    or firstName in (accountNumber,otherField)

    or accountNumber in (otherField) then 'Y' end

    )

    as

    begin

    declare @parms table (parm varchar(64) null)

    insert @parms

    select @parm1

    union

    select @parm2

    union

    select @parm3

    union

    select @parm4

    insert into @matrix (firstName, lastName, accountNumber, otherField)

    select T1.parm as firstName,

    T2.parm as lastName,

    T3.parm as accountNumber,

    T4.parm as otherField

    from

    @parms T1

    cross join @parms T2

    cross join @parms T3

    cross join @parms T4

    delete @matrix

    where duplicateFields = 'Y'

    or numFields !=

    (select count(*) from @parms where parm is not null)

    return

    end

    this function creates a matrix of all parameters in all 'fields'. this example:

    select firstName, lastName, accountNumber, otherField

    from dbo.fParameterMatrix( 'Sally', 'Smith', 'b-24005', null)

    returns this matrix:

    firstName lastName accountNumber otherField

    b-24005NULLSmithSally

    b-24005NULLSallySmith

    SallyNULLSmithb-24005

    ...

    b-24005SmithNULLSally

    SallySmithb-24005NULL

    SallySmithNULLb-24005

    now, just join the matrix to your tables like so (I forgot you were using [middleName]... I just used [otherField]):

    SELECT c.ClientId

    FROM Client c

    JOIN ClientAccount ca ON c.ClientId = ca.ClientId

    JOIN dbo.fParameterMatrix('Sally', 'Smith', 'b-24005', null) P

    ON c.firstName = isnull(P.firstName,c.firstName)

    and c.lastName = isnull(P.lastName,c.lastName)

    and c.accountNumber = isnull(P.accountNumber,c.accountNumber)

    and c.middleName = isnull(P.otherField,c.middleName)

    P.S.: if the columns you're using for the search aren't indexed, such as join could be very resource intensive.

    P.P.S.: you could also join character columns using LIKE and wildcards

  • According to example given by Christopher Stobbs, can you do something like this?

    CREATE TABLE Client

    (ClientId INT IDENTITY(1,1),

    LastName VARCHAR(100),

    FirstName VARCHAR(100),

    MiddleName VARCHAR(100))

    CREATE TABLE ClientAccount

    (AccountId INT IDENTITY(1,1),

    ClientId INT,

    AccountNumber VARCHAR(100))

    --TEST DATA

    INSERT INTO Client

    SELECT 'Stobbs', 'Chris' , 'Terence' UNION ALL

    SELECT 'Joe', 'Blogs' , 'Middle' UNION ALL

    SELECT 'Jane', 'Doe' , 'Middle'

    INSERT INTO ClientAccount

    SELECT 1, 'A12313121' UNION ALL

    SELECT 2, 'B12313321' UNION ALL

    SELECT 3, 'C12313991'

    SELECT * FROM Client

    SELECT * FROM ClientAccount

    declare @tbl table(searchData varchar(100))

    insert into @tbl

    select 'Stobbs' union all

    select 'A12313121' union all

    select 'Blogs'

    select * from Client c1 join ClientAccount c2 on c1.ClientID=c2.ClientID and

    (c1.LastName in (select searchData from @tbl) or

    c1.FirstName in (select searchData from @tbl) or

    c2.AccountNumber in (select searchData from @tbl))

    "Don't limit your challenges, challenge your limits"

Viewing 7 posts - 1 through 6 (of 6 total)

You must be logged in to reply to this topic. Login to reply