Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 461
  • 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
Independent Software Vendors: 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!

 
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

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!

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