Improve company productivity with a Business Account.Sign Up

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 464
  • Last Modified:

Problem with IN Statement in SQL Server

I currently have a a query where I pass in some delimited values as a varchar. When I go to test against this list in my Where clause SQL Server freaks out and tells me I need to have integers . Not sure what to do.

@states varchar(max)
in C# I pass this in as - @states='AL,CT,FL'

Then in my query it looks like this :

Select *
From dhpDrivers
Where  dhpDriver.State in(@states)


error I get is :
Conversion failed when converting the varchar value 'AL,CT,FL' to data type int

The dhpDriver.State  field is not an integer field so I'm a bit confused.Any idea what I need to do with my states list to make this work ? Any advice would be much appreciated.

Jason
0
jazzcatone
Asked:
jazzcatone
  • 6
  • 3
  • 2
  • +3
4 Solutions
 
Paul MacDonaldDirector, Information SystemsCommented:
Is this a stored procedure?  Is the passed parameter defined as an Int?
0
 
Kent OlsenData Warehouse Architect / DBACommented:
Hi Jazz,

You've got several problems here, the biggest is "You can't do that".

Select *
From dhpDrivers
Where  dhpDriver.State in(@states)

You can't pass a variable to IN.  Even though it looks like a function, IN is an operator and it requires a parameter list, not a string.

You can create a string with the entire query and execute it, but that may no help this particular issue.


Also, the error that you're seeing is a conversion to integer error.  That implies that dhpDriver.State is an integer (as in the logical state of the driver) not a string (as in a state in the U.S.A.)


So the first issue is to determine what you need to compare and the source field that contains the value.


Good Luck,
Kent
0
 
Christopher GordonSenior Developer AnalystCommented:
Try using CHARINDEX.

For Example...


declare @myFilter nvarchar(100) = 'AL,CT,FL'
declare @myTable table (id int identity(1,1), myState nvarchar(100))

insert into @myTable
values ('OH'),
 ('NY'),
 ('MI'),
 ('CT'),
  ('FL'),
 ('AL')
 
 
select      *
from      @myTable
where      CHARINDEX(myState, @myFilter) > 0
0
Improve Your Query Performance Tuning

In this FREE six-day email course, you'll learn from Janis Griffin, Database Performance Evangelist. She'll teach 12 steps that you can use to optimize your queries as much as possible and see measurable results in your work. Get started today!

 
jazzcatoneAuthor Commented:
dhpDriver.State is a char(2). This is source field I need to compare against.
0
 
Scott PletcherSenior DBACommented:
Looks like the parameter type of @states is an int.  Change the param to varchar(nnnn).

Best would likely be convert the list passed into a table, since that can be keyed.

DECLARE @statesTable TABLE (
    state char(2) PRIMARY KEY
    )

-- code to insert values from @states to @statesTable

SELECT *
FROM dbo.dhpDrivers d
INNER JOIN @statesTable st ON
    st.state = d.state
0
 
Scott PletcherSenior DBACommented:
Here is the:
-- code to insert values from @states to @statesTable


-- insert the first state into the table
INSERT INTO @statesTable
SELECT LEFT(@states, CHARINDEX(',', @states) - 1)

-- dynamically create a table of seq #s from 1 to 9999 to help parse input parameter
;WITH
cteDigits AS (
    SELECT 0 AS digit UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL
    SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
),
cteTally AS (
    SELECT [1000s].digit * 1000 + [100s].digit * 100 + [10s].digit * 10 + [1s].digit AS num
    FROM cteDigits [1s]
    CROSS JOIN cteDigits [10s]
    CROSS JOIN cteDigits [100s]
    CROSS JOIN cteDigits [1000s]    
)
INSERT INTO @statesTable
SELECT
    SUBSTRING(@states, num + 1, CHARINDEX(',', @states + ',', num + 1) - num - 1) AS state
FROM cteTally
WHERE
    num BETWEEN 2 AND LEN(@states) AND
    SUBSTRING(@states, num, 1) = ','
0
 
HainKurtSr. System AnalystCommented:
use this query and you are done

Select *
From dhpDrivers
Where ','+@states+',' like '%,'+State+',%'

simple is the best...
0
 
Scott PletcherSenior DBACommented:
Not necessarily for performance it isn't.

That could have awful performance, depending on the number of rows and number of values entered, and if a state index exists on the table.
0
 
HainKurtSr. System AnalystCommented:
ok! if we have a look-up table for states we can use this format :) and still use index and performance would not be awful :)

Select d.*
From dhpDrivers d inner join dphStates s on s.state=d.state and ','+@states+',' like '%,'+s.State+',%'
0
 
Scott PletcherSenior DBACommented:
If you could create a table that's guaranteed to hold all the state values (*), you could do this:


SELECT ...
FROM dbo.dhpDrivers d
INNER JOIN (
    SELECT state
    FROM dbo.dphStates
    WHERE
        ',' + @states + ',' LIKE '%,' + state + ',%'
) AS s ON
    s.state = d.state
...


(*) Sometimes "state" includes things like "DC", Canadian provinces, etc., so it's more than just a fixed list of (exactly) 50 values.

I still see that as a disadvantage over just dynamically creating a much more limited table from only the state values that are entered in the parameter for that run.


However, I'd probably change to a true temporary table, #states, rather than @statesTable, so that stats are available for SQL, so the optimizer will "know" it's a very small table.
0
 
HainKurtSr. System AnalystCommented:
ScottPletcher, is your last post any different then my post @ 37744667 :)
0
 
Scott PletcherSenior DBACommented:
Yes.  I reduced the number of rows as much as possible BEFORE joining to the main table.

Again, I still think that is an inferior approach to creating a temp table of the actual values passed in, since very few values are likely to be passed in for a typical run.
0
 
jazzcatoneAuthor Commented:
So I created a User Defined function called CSVStringToTable to pump out my @states into a single column table.

So when @states = 'AL,OH,PA'
and I call the function like so : CSVStringToTable(@states)

I get a single column table (column name is ItemList) with 3 records. One record per state.

so in my stored proc I create a temp table like so :
SELECT * INTO #TEMP_StateList34 FROM CSVStringToTable(@states)

this lets lets me do my in function from my where clause:
WHERE dhpDriver.State in(SELECT Itemlist from #TEMP_StateList34)

AS Kdo mentioned earlier the problem is that you really need something that sql server sees as an list and not a string. Thank you for all the help.
0
 
Scott PletcherSenior DBACommented:
Looks good.

A primary key on the temp table should help SQL perform (slightly) better.  The more states there are in the table, the more they key should help.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 6
  • 3
  • 2
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now