Solved

Problem with IN Statement in SQL Server

Posted on 2012-03-20
14
441 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Ransomware-A Revenue Bonanza for Service Providers

Ransomware – malware that gets on your customers’ computers, encrypts their data, and extorts a hefty ransom for the decryption keys – is a surging new threat.  The purpose of this eBook is to educate the reader about ransomware attacks.

 

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 52

Assisted Solution

by:Huseyin KAHRAMAN
Huseyin KAHRAMAN 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 52

Expert Comment

by:Huseyin KAHRAMAN
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 52

Expert Comment

by:Huseyin KAHRAMAN
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

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Use this article to create a batch file to backup a Microsoft SQL Server database to a Windows folder.  The folder can be on the local hard drive or on a network share.  This batch file will query the SQL server to get the current date & time and wi…
A company’s centralized system that manages user data, security, and distributed resources is often a focus of criminal attention. Active Directory (AD) is no exception. In truth, it’s even more likely to be targeted due to the number of companies …
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…

726 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