Not sure of best way to select different status values

  • On many of my tables I store a status value. The values are Active, On Hold, Cancelled, In Legal and Closed. There are times when I need to return all rows that are Active or on Hold. Other times when I need to return all rows that are Active or Closed. I am trying to come up with a method that I can use to return any combination of status values. I am not sure which of the following options is a better option:

    1. Create/Call a stored procedure that returns all the rows for one specific status multiple times (once for each status value) and then combine the result sets into one result set.

    2. Create/Call a stored procedure that returns the specific combination of status values that I looking for.

    3. Create/Call a dynamic stored procedure that passes in status values that I am looking for

    I would appreciate it if I could get some opinions as to which solution is the best solution or if there is a better solution that I have not thought of.

    Thanks

  • I dont know how your tables are indexed or anything but you could use some simple xml to parse a string and retreive values from the table based on the string. I would prefer this method over returning unwanted results or dynamic sql.

    CREATE PROCEDURE TEST

    @filter VARCHAR(100)

    AS

    BEGIN

    DECLARE @x XML

    SET @x = '?i?' + REPLACE( @filter, '|', '?/i??i?') + '?/i?'

    SELECT *

    FROM MyTable

    WHERE [Status]

    IN (SELECT x.i.value('.', 'VARCHAR(7)')

    FROM @x.nodes('//i') x(i))

    END

    You can then execute the code like

    EXEC Test 'ACTIVE|ONHOLD'

  • Man, I hate how this site strips the XML. You have to change the question marks to open and close xml tags ( )

    DECLARE @x XML

    SET @x = '?i?' + REPLACE( @filter, '|', '?/i??i?') + '?/i?'

  • Adam - if you do a find and replace prior to posting that, and replace the brackets with their HTML equivalents - it won't get stripped.

    Meaning - replace

    > with >

    < with &lt;

    you'd still have to post it in a code block if you want to maintain some semblance of alignment.

    ----------------------------------------------------------------------------------
    Your lack of planning does not constitute an emergency on my part...unless you're my manager...or a director and above...or a really loud-spoken end-user..All right - what was my emergency again?

  • Post with Matt's tip.

    CREATE PROCEDURE TEST

    @filter VARCHAR(100)

    AS

    BEGIN

    DECLARE @x XML

    SET @x = '<i>' + REPLACE( @filter, '|', '</i><i>') + '</i>'

    SELECT *

    FROM MyTable

    WHERE [Status]

    IN (SELECT x.i.value('.', 'VARCHAR(7)')

    FROM @x.nodes('//i') x(i))

    END

  • Ah, much better. Thanks for the tip, I knew the equivilant but didnt even think to use it.

    Thanks.

  • I came up with a different solution that I am close to fixing, but am having a problem with. I decided to use an IN clause so that my selection would include a line like:

    where STATUS in (@statuses)

    Exec SomeProc 'HOLD, ACTIVE'

    Unfortunately I was not told by my manager that the status values are actually Ints. For instance Active = 1, On Hold = 2... Etc.

    So I tried

    Exec SomeProc '1,2'

    This generated a conversion error. So now I am stuck. Can I use an "IN" clause to solve this problem or do I need to make use of the solutions that have been provided?

    Thanks

  • Like I said I would not use dynamic sql, if I did not have to. Dynamic SQL does not reuse execution plans and can hinder performance, if there are lots of records. The solution I gave you will take any number of statuses, in any delmited format, and check them against the table. Basically it is doing what you are but without dynamic sql.

  • You run into more problems with dynamic sql like indexing, caching, recompiles etc. But if you must go with a dynamic sql solution I would recommend that you use sp_executesql as this does allow for query plan reuse and has built in functionality for parameters.

    http://technet.microsoft.com/en-us/library/ms188001.aspx

  • At this point I am not sure if I am better off using dynamic sql or using optional parameters in my t-sql script. Any thoughts?

    Thanks

  • meichner (2/19/2008)


    At this point I am not sure if I am better off using dynamic sql or using optional parameters in my t-sql script. Any thoughts?

    Thanks

    You should not use dynamic sql unless you have to...and this is not such a case. Instead you should do like Adam suggests...or do something like this

    --Adam's code wrapped in a function

    CREATE FUNCTION SplitStringToInt

    (

    @filter VARCHAR(8000)

    )

    RETURNS @numbers TABLE

    (

    idno int

    )

    AS

    BEGIN

    DECLARE @x XML

    SET @x = '<i>' + REPLACE( @filter, '|', '</i><i>') + '</i>'

    INSERT INTO @numbers(idno)

    SELECT x.i.value('.', 'int') FROM @x.nodes('//i') x(i)

    RETURN

    END

    Then you can use this function in your sprocs...

    Select * from Order where Status in (Select idno from SplitStringToInt(@StatusCodes)) --@StatusCodes = '1|2|3|4'

  • Thanks, I will give that a shot.

  • Ok... I'm a bit new to 2k5... just installed it a couple of months ago and still coming up to speed on how some of the new features work.

    Can someone explain to me how the XML was used to this bit of computational heaven? Thanks...

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.
    "Change is inevitable... change for the better is not".

    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)
    Intro to Tally Tables and Functions

  • The first thing we are doing is adding tags to all the values in the delimited string. E.g.

    declare @filter varchar(25)

    set @filter = 'test|test2'

    DECLARE @x XML

    SET @x = '<i>' + REPLACE( @filter, '|', '</i><i>') + '</i>'

    The string @x looks like this at this point: <i>test</i><i>test2</i>

    SELECT x.i.value('.', 'VARCHAR(7)') as [test]

    FROM @x.nodes('//i') x(i)

    Next, we use the new xquery nodes to return all values from delimited string in table format. We place this piece of code in the from clause, so we can reference the values in the select, with the column reference x(i). The column aliase has to be referenced in the select. Below I changed the column alias to demonstrate how the column alias and the select must match. I will also point out that the '.' is supplied to tell the value method where to look for the data, in this case the root of x.nodes.

    SELECT x.abc.value('.', 'VARCHAR(7)') as [test]

    FROM @x.nodes('//i') x(abc)

    We then tell the query to retrieve each value from the nodes return and cast it as a varchar(7) by using the xquery value method.

  • I am new to this XML query stuff so please forgive the question. I have tried to get your function to complile, but I keep getting errors about an alias of x(i). Is the syntax in your post correct?

    Thanks

Viewing 15 posts - 1 through 15 (of 41 total)

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