Solved

Problem with IN Statement in SQL Server

Posted on 2012-03-20
14
433 Views
Last Modified: 2012-03-20
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
Comment
Question by:jazzcatone
  • 6
  • 3
  • 2
  • +3
14 Comments
 
LVL 34

Expert Comment

by:Paul MacDonald
ID: 37743575
Is this a stored procedure?  Is the passed parameter defined as an Int?
0
 
LVL 45

Accepted Solution

by:
Kent Olsen earned 125 total points
ID: 37743612
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
 
LVL 14

Assisted Solution

by:Christopher Gordon
Christopher Gordon earned 125 total points
ID: 37743664
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
Migrating Your Company's PCs

To keep pace with competitors, businesses must keep employees productive, and that means providing them with the latest technology. This document provides the tips and tricks you need to help you migrate an outdated PC fleet to new desktops, laptops, and tablets.

 

Author Comment

by:jazzcatone
ID: 37744023
dhpDriver.State is a char(2). This is source field I need to compare against.
0
 
LVL 69

Assisted Solution

by:Scott Pletcher
Scott Pletcher earned 125 total points
ID: 37744057
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
 
LVL 69

Expert Comment

by:Scott Pletcher
ID: 37744106
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
 
LVL 51

Assisted Solution

by:HainKurt
HainKurt earned 125 total points
ID: 37744436
use this query and you are done

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

simple is the best...
0
 
LVL 69

Expert Comment

by:Scott Pletcher
ID: 37744459
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
 
LVL 51

Expert Comment

by:HainKurt
ID: 37744667
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
 
LVL 69

Expert Comment

by:Scott Pletcher
ID: 37744746
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
 
LVL 51

Expert Comment

by:HainKurt
ID: 37744828
ScottPletcher, is your last post any different then my post @ 37744667 :)
0
 
LVL 69

Expert Comment

by:Scott Pletcher
ID: 37744849
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
 

Author Comment

by:jazzcatone
ID: 37744865
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
 
LVL 69

Expert Comment

by:Scott Pletcher
ID: 37744879
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

Featured Post

U.S. Department of Agriculture and Acronis Access

With the new era of mobile computing, smartphones and tablets, wireless communications and cloud services, the USDA sought to take advantage of a mobilized workforce and the blurring lines between personal and corporate computing resources.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article explains how to reset the password of the sa account on a Microsoft SQL Server.  The steps in this article work in SQL 2005, 2008, 2008 R2, 2012, 2014 and 2016.
When it comes to protecting Oracle Database servers and systems, there are a ton of myths out there. Here are the most common.
Video by: Steve
Using examples as well as descriptions, step through each of the common simple join types, explaining differences in syntax, differences in expected outputs and showing how the queries run along with the actual outputs based upon a simple set of dem…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

856 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question