Syntax for SQL IN when using Excel database connection

1

I'm using a number of Excel files to connect to an SQL Server database, fetching sales data for a particular product number which is specified in a cell in the Excel sheet.

This was set up by defining parameters in the SQL connection with

SELECT ProductCode, Sales
    WHERE ProductCode = ?

and specifying a cell in the worksheet that contains the product number. This works fine, however I now want to extract the sales for a number of products at once. I've created a comma-separated list automatically in Excel, but trying to use this as the parameter always results in this error message:

Syntax error message screenshot

I'm entering the SQL code as WHERE ProductCode IN ? as ideally I'd like to have the parameter cell able to change dynamically within Excel, but I've also tried WHERE ProductCode IN (1,2,3) or WHERE ProductCode IN (N'1', N'2', N'3') and various other different syntax. I've also replicated this syntax in the Excel-generated list of product numbers. (1,2 and 3 in this case being example product codes).

Some alternatives I could use would be having WHERE ProductCode=? OR ProductCode=? OR ProductCode=? etc and specify each as a separate parameter, but it's likely to be at least 200 product codes so this is far from ideal, it also means I'll have to manually edit the SQL code whenever a greater number of codes need to be fetched than however many cells I've set as parameters, and most colleagues don't have the SQL knowledge to do this in my absence either.

Probably I'm just using the incorrect syntax, but hopefully someone will be able to point out where I might be going wrong. The error message is the same no matter what format I select so I can't figure out what the problem might be.

This is the full query which does work:

SELECT
PRODUCT.ProductCode
,SALES.Quantity
,SALES.Date

FROM
  SALES
INNER JOIN PRODUCT
    ON SALES.ProductCode = PRODUCT.ProductCode
WHERE
  ((SALES.Date >=? AND SALES.Date<=?)
AND PRODUCT.ProductCode=?

David H

Posted 2019-09-04T12:50:04.570

Reputation: 23

Just added, it's not much more complex than what was already in the question tbh, but hope it helps. – David H – 2019-09-04T13:22:43.583

Does the query with the only table SELECT ProductCode FROM product WHERE ProductCode IN (?,?,?,...) works with IDs list? Does you transfer the list into your query as a lot of separate parameters, not as one CSV parameter? – Akina – 2019-09-04T13:26:03.273

It actually seems to work now if I type in a few item numbers directly into the query 'WHERE SALES.ProductCode IN (1,2,3)'. But using the parameter with the exact same values in the target cell still gives the error message. – David H – 2019-09-04T14:17:05.930

It must be parameterS, not single parameter. – Akina – 2019-09-04T14:37:42.977

But if I change the statement to WHERE ProductCode IN (?,?,?) that will require 3 separate parameters, in 3 different cells, correct? I did try something similar already but that requires me to set new parameters if the number of product codes requires increases, which I'd ideally like to avoid as I have to make the file "foolproof" for other users who have no knowledge of how to alter the SQL code. The final file will need to have several hundred product codes, so I would then need to maintain those several hundred parameters in the dialog window. – David H – 2019-09-04T14:42:08.557

if I change the statement to WHERE ProductCode IN (?,?,?) that will require 3 separate parameters, in 3 different cells, correct? Of course. If you want to send ONE parameter which contains ALL values then you must use any function which will "unpivot" this parameter into one more source table (and use proper parameter format). For example, it can be OPENXML()... or VALUES()... – Akina – 2019-09-04T18:33:06.310

How would that work exactly? In order to put all the codes into one comma-separated list, I've had to concatenate them, which presumably is what is stopping them being recognised as values. I've tried a few permutations of VALUE() (there doesn't seem to be a VALUES() function), is there another way of combining all the values into a single parameter? – David H – 2019-09-05T07:05:54.077

Sorry, VALUES() cannot achieve the goal... If your SQL server is 2017+ (compatibility level >=130) you may use STRING_SPLIT() function for to parse single parameter with CSV values into a rowset (using it in FROM clause as a source table). If your server is more ancient you may use OPENXML() or, for example, one of solutions from https://stackoverflow.com/questions/697519/split-function-equivalent-in-t-sql

– Akina – 2019-09-05T07:21:28.787

Am I right in thinking that would require me to create new tables within the database? I don't have write access to the database unfortunately, I can only read data from the existing tables. – David H – 2019-09-05T07:57:26.087

Am I right in thinking that would require me to create new tables within the database? No. I'll show draft sample code for SQLserver 2017+ as an answer to explain. – Akina – 2019-09-05T08:16:39.497

Answers

0

Draft code for 2017+

-- output list
SELECT PRODUCT.ProductCode
      ,SALES.Quantity
      ,SALES.Date

-- data sources
FROM       SALES
INNER JOIN PRODUCT
        ON SALES.ProductCode = PRODUCT.ProductCode
-- including CSV codes list transferred as single parameter and parsed to rowset
INNER JOIN (SELECT value
            FROM STRING_SPLIT(?,',')) AS parameters(productCode)
        ON PRODUCT.ProductCode = parameters.productCode

-- filtering by date range transferred as a pair of parameters
WHERE (SALES.Date >=? AND SALES.Date<=?)

Simplified fiddle (filtering by SALES.Date removed)

it seems to be SQL Server 2014, compatibility level 120.

The solution applicable for SQL Server 2014:

-- output list
SELECT PRODUCT.ProductCode
      ,SALES.Quantity
      ,SALES.Date

-- data sources
FROM       SALES
INNER JOIN PRODUCT
        ON SALES.ProductCode = PRODUCT.ProductCode
-- including CSV codes list transferred as single parameter and parsed to rowset
INNER JOIN (SELECT b.n.value('@n', 'int')
            FROM (SELECT CAST('<item n = "' + REPLACE(?, ',', '"/><item n="') + '"/>' AS XML)) a(x) 
            CROSS APPLY a.x.nodes('item') b(n)) AS parameters(productCode)
        ON PRODUCT.ProductCode = parameters.productCode

-- filtering by date range transferred as a pair of parameters
WHERE (SALES.Date >=? AND SALES.Date<=?)

Simplified fiddle (filtering by SALES.Date removed)

Akina

Posted 2019-09-04T12:50:04.570

Reputation: 2 991

Using this gives me two error messages one after the other, "Invalid parameter number" and "Invalid Descriptor Index". Would that indicate that the server version is not compatible? – David H – 2019-09-05T09:08:21.283

@DavidH These messages are NOT messages from SQL server. The problem occures on the stage of parameters attach (do you consider that the parameters order was altered?). Fiddle added. Would that indicate that the server version is not compatible? Check your server compatibility level, it must be 130 or higher. Or simply try to execute my fiddle on it. – Akina – 2019-09-05T09:24:10.080

I tried to execute that but it just seems to refresh the screen but not load any data from the database. How would I go about checking server compatibility? Apologies if this is a basic question... – David H – 2019-09-05T10:52:32.860

@DavidH To get database compatibility level execute SELECT compatibility_level FROM sys.databases WHERE name = 'your database name'; or SELECT name, compatibility_level FROM sys.databases; for all databases. To get server version execute select @@version;. – Akina – 2019-09-05T10:56:05.677

Thanks - it seems to be SQL Server 2014, compatibility level 120. Would that be why this approach is not working? – David H – 2019-09-05T11:01:11.353

My approach is not applicable in your case. STRING_SPLIT() is not available for you. – Akina – 2019-09-05T11:03:33.823

@DavidH Query applicable to your server version added. – Akina – 2019-09-05T11:19:17.230

Still getting the same two error messages on the 2014 query I'm afraid. – David H – 2019-09-05T12:09:11.213

@DavidH As fiddle shows the query itself is correct. If you obtain error message it is not relative to the query. And I don't know how to help you... – Akina – 2019-09-05T12:14:28.710

Ok, no worries. Possibly something wrong within Excel itself or my access permissions. Thanks very much for your help, it's been very informative. – David H – 2019-09-05T12:19:20.120