3

I am using SQL Server 2000 and having a wierd issue with a SQL code block (below):
A user can enter "GM" as a possible parameter or "F". If the user enters "GM" as a parameter in the stored proc query string, I need the AutoDivision to include GMC, CAD, CHE,SAT

declare @AutoDivision as varchar(15) 
set @AutoDivision = 'GM' 

if @AutoDivision = 'GM' 
            Begin 
                Select @AutoDivision = '''Cad'', ''GMC'', ''Sat'', ''Che'''
            End 

            SELECT 
                 oh.OrderNumber, lg.[lgh_number]
            FROM 
                [dbo].[OrderHeader] oh (NOLOCK)
            INNER JOIN 
                [dbo].[DistrctHeader] lg (NOLOCK) ON oh.[inv_number] = lg.[inv_number]
            INNER JOIN
                [dbo].[DealerCompany] c (NOLOCK) ON c.cmp_id = LEFT(oh.[ordernumber],3)
            INNER JOIN
                [dbo].[divisionXREF] x (NOLOCK) ON x.Division = c.comp_revtype
            WHERE
                oh.ord_number = '113-889257'
                AND x.AutoDivision IN (@AutoDivision)
                --AND x.AutoDivision IN ('Cad', 'Sat', 'GMC', 'Che')
                AND lg.[lgh_outstatus] IN ('AVAIL', 'PLAN', 'DISP', 'STRTD', 'PEND','COMP')  

However, when I run the code below, I don't get back any records. When I uncomment the code line
--AND x.AutoDivision IN ('Cad', 'Sat', 'GMC', 'Che')

it works (I get a record returned).

When I do a print 'AND x.AutoDivision IN (' + cast(@AutoDivision as varchar) + ')'
I get back AND x.AutoDivision IN ('Cad', 'GMC', 'Sat', 'Che')

What am I missing here?

5 Answers 5

10

You can't use a single variable to represent a comma separated list of IN parameters in SQL - Oracle, MySQL, SQL Server... doesn't matter.

To get this variable method to work, you need to use dynamic SQL so you are able to create the query as a string first (using concatenation to get the IN parameters from your variable), and the query statement is executed afterwards:

DECLARE @cmd VARCHAR(1000)

SET @cmd = 'SELECT oh.OrderNumber, 
                   lg.[lgh_number]
              FROM [dbo].[OrderHeader] oh (NOLOCK)
              JOIN [dbo].[DistrctHeader] lg (NOLOCK) ON oh.[inv_number] = lg.[inv_number]
              JOIN [dbo].[DealerCompany] c (NOLOCK) ON c.cmp_id = LEFT(oh.[ordernumber],3)
              JOIN [dbo].[divisionXREF] x (NOLOCK) ON x.Division = c.comp_revtype
             WHERE oh.ord_number = '113-889257'
               AND x.AutoDivision IN ('+ @AutoDivision +')
               AND lg.[lgh_outstatus] IN (''AVL'', ''PLN'', ''DSP'', ''STD'', ''PND'',''CMP'')  '

EXEC(@cmd)

I recommend reading The Curse and Blessings of Dynamic SQL before implementing a dynamic SQL solution.

Table Valued Function

A table valued function would allow you do what you want without using dynamic SQL -- there's more info in this article.

Sign up to request clarification or add additional context in comments.

Comments

5

To avoid this, you can create a temp table, fill it in, then use

IN (SELECT myField from #myTable)

2 Comments

your solution was simple and easy to maintain. Thanks!!
You're welcome, that's what I aim for. :0) By the way, I have a handy proc that converts a string of choices like that into a table automatically. If you find yourself doing this often, you could look it up.
3

Even though you concatenate what looks like a few different arguments your IN clause is actually testing it as a single string (you did declare it as a varchar) and it's no surprise that no records match that predicate.

Looks like you're trying to mix dynamic sql and a standard query. That won't work. Your query either has to be all dynamically created and then specially executed or your IN clause has to be inputed with individual arguments which can be done by subqery.

You could do something like:

... AND x.AutoDivision IN 
(SELECT Division WHERE Corp = 'GM') ...

OR

... AND x.AutoDivision IN 
(SELECT 'Cad' UNION SELECT 'GMC' UNION SELECT 'Sat' UNION SELECT 'Che') ...

Try this:

        SELECT 
             oh.OrderNumber, lg.[lgh_number]
        FROM 
            [dbo].[OrderHeader] oh (NOLOCK)
        INNER JOIN 
            [dbo].[DistrctHeader] lg (NOLOCK) ON oh.[inv_number] = lg.[inv_number]
        INNER JOIN
            [dbo].[DealerCompany] c (NOLOCK) ON c.cmp_id = LEFT(oh.[ordernumber],3)
        INNER JOIN
            [dbo].[divisionXREF] x (NOLOCK) ON x.Division = c.comp_revtype
        WHERE
            oh.ord_number = '113-889257'
            AND x.AutoDivision IN 
           (SELECT 'Cad' UNION SELECT 'GMC' UNION SELECT 'Sat' UNION SELECT 'Che')
            AND lg.[lgh_outstatus] IN ('AVL', 'PLN', 'DSP', 'STD', 'PND','CMP') 

That is an inline subquery that UNIONs arbitrary strings into a result set. (Take with a grain of salt. I am a long way from a Sql Server interface.)

3 Comments

Paul, just so you know, a user can enter "GM" or "F" (updated my original post). If they enter "F", everything is fine. If they enter "GM", thats where the complexity begins.
Because GM has divisions and Ford doesn't? OK. Try that. (Replaced the string with a UNION set of subqueries)
Well, technically, because GM needs to show a detailed report... but thats business logic
1
   AND x.AutoDivision IN (@AutoDivision)
        --AND x.AutoDivision IN ('Cad', 'Sat', 'GMC', 'Che')

Can you clarify these two lines of code, are they not doing the same thing?

2 Comments

The former is not supported by SQL; the latter (commented out) is supported.
They are supposed to be the same, but the top line does not return a record, the bottom line returns a record.
0
CREATE FUNCTION [dbo].[Split]
(
    @String NVARCHAR(4000),
    @Delimiter NCHAR(1)
)
RETURNS TABLE 
AS
RETURN 
(
    WITH Split(stpos,endpos) 
    AS(
        SELECT 0 AS stpos, CHARINDEX(@Delimiter,@String) AS endpos
        UNION ALL
        SELECT endpos+1, CHARINDEX(@Delimiter,@String,endpos+1)
            FROM Split
            WHERE endpos > 0
    )
    SELECT 'Id' = ROW_NUMBER() OVER (ORDER BY (SELECT 1)),
        'Data' = SUBSTRING(@String,stpos,COALESCE(NULLIF(endpos,0),LEN(@String)+1)-stpos)
    FROM Split
)
GO

DECLARE @AutoDivision varchar(50) = NULL
SET @AutoDivision ='Cad, Sat, GMC, Che'

SELECT * FROM divisionXREF P INNER JOIN dbo.SPLIT(ISNULL(@AutoDivision,''),',') as T ON P.lgh_outstatus = CASE T.strval WHEN '' THEN P.PG_CODE ELSE T.strval END

1 Comment

You need to format this and explain what you're doing to provide a good answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.