From: SetonSoftware on
I have a SQL Server 2005 stored procedure that will receive a series
of valeus to be passed to an IN clause. Since IN clauses do not take
parameters, I need to use a UDF like fnc_Parse2TableString() to parse
the comma-delimited values into a table object as shown below:

DECLARE @DeptNames varchar(max)

SET @DeptNames = 'Accounting, Finance'

SELECT *
FROM Personnel
WHERE Department IN
CASE
WHEN @DeptNames <> '' THEN (SELECT data FROM
dbo.fnc_Parse2TableString(@DeptNames, ','))
END


What I'm trying to accomplish is to have @DeptNames as an optional
parameter. Since this SQL does not work as shown, what must I do in
order to accomplish this?

I really want to avoid dynamic SQL and since I may have many such
optional IN clause parameters, managing multiple versions of the same
SQL would become cumbersome.

Thanks

Carl
From: --CELKO-- on
>> I have a SQL Server 2005 stored procedure that will receive a series of valeus to be passed to an IN clause. Since IN clauses do not take parameters, ..<<

Wrong, you just need to learn how to do it. It means thinking in sets
and not in procedural code

>> I need to use a UDF like fnc_Parse2TableString() to parse the comma-delimited values into a table object as shown below: <<

Yep, just like you were in a 1960's C programming class and having to
do low-level I/O. And you are using proprietary "features" that will
foil the optimizer, too.

SQL Server can handle up to 2K parameters, which is actually a short
list compared to DB2's 32K. Since they are parameters, the compiler
handles ALL the error checking (I'll bet your parser doesn't and I
will bet that you will not update your code to make your parser work
like the next release of T-SQL), can do optimizer tricks with them,
detect missing parameters, etc.

Here is a skeleton for 5 values. Yo use the table constructor to
create a derived table where you need it.

CREATE PROCEDURE Foobar
(@p1 INTEGER = NULL,
@p2 INTEGER = NULL,
@p3 INTEGER = NULL,
@p4 INTEGER = NULL,
@p5 INTEGER = NULL,
etc.)

BEGIN
...
SELECT ..
FROM ..
WHERE x
IN (SELECT parm
FROM (VALUES (@p1), (@p2), (@p3), @p4), (@p5)) AS
X(parm)
WHERE parm IS NOT NULL;
...
END;

You can generalize this, do calculations and add CASE expression to
the code. YOu can cast the first line to desired data types and force
the columns. After that use cut & paste.

VALUES (CAST (sku_1 AS CHAR(9)), CAST (price_1 AS DECIMAL(8,2), CAST
(order_qty_1 AS INTEGER),
(sku_2, price_2, order_qty_2),
etc. ) AS X(..)

All declarative code, no need for procedural thinking at all.
From: Plamen Ratchev on
You can simply use IF statement to execute two queries with different
WHERE predicate:

IF @DeptNames <> ''
<query with IN>;
ELSE
<query without IN>;

Also, see Erland's article on different technique for splitting
arrays:
http://www.sommarskog.se/arrays-in-sql-2005.html

--
Plamen Ratchev
http://www.SQLStudio.com
From: BGL on

We used this suggested approach for a "Google Friend Connect" custom feature
against a MySQL backend.

We needed to SELECT data for the current user, as well as the current user's
Friends (up to 100). MySQL doesn't support the row constructor, so we had to
UNION ALL-up the input params in the derived table, but the SP call from the
web app was a cinch and the SP was lightning fast.

"--CELKO--" wrote:

> >> I have a SQL Server 2005 stored procedure that will receive a series of valeus to be passed to an IN clause. Since IN clauses do not take parameters, ..<<
>
> Wrong, you just need to learn how to do it. It means thinking in sets
> and not in procedural code
>
> >> I need to use a UDF like fnc_Parse2TableString() to parse the comma-delimited values into a table object as shown below: <<
>
> Yep, just like you were in a 1960's C programming class and having to
> do low-level I/O. And you are using proprietary "features" that will
> foil the optimizer, too.
>
> SQL Server can handle up to 2K parameters, which is actually a short
> list compared to DB2's 32K. Since they are parameters, the compiler
> handles ALL the error checking (I'll bet your parser doesn't and I
> will bet that you will not update your code to make your parser work
> like the next release of T-SQL), can do optimizer tricks with them,
> detect missing parameters, etc.
>
> Here is a skeleton for 5 values. Yo use the table constructor to
> create a derived table where you need it.
>
> CREATE PROCEDURE Foobar
> (@p1 INTEGER = NULL,
> @p2 INTEGER = NULL,
> @p3 INTEGER = NULL,
> @p4 INTEGER = NULL,
> @p5 INTEGER = NULL,
> etc.)
>
> BEGIN
> ...
> SELECT ..
> FROM ..
> WHERE x
> IN (SELECT parm
> FROM (VALUES (@p1), (@p2), (@p3), @p4), (@p5)) AS
> X(parm)
> WHERE parm IS NOT NULL;
> ...
> END;
>
> You can generalize this, do calculations and add CASE expression to
> the code. YOu can cast the first line to desired data types and force
> the columns. After that use cut & paste.
>
> VALUES (CAST (sku_1 AS CHAR(9)), CAST (price_1 AS DECIMAL(8,2), CAST
> (order_qty_1 AS INTEGER),
> (sku_2, price_2, order_qty_2),
> etc. ) AS X(..)
>
> All declarative code, no need for procedural thinking at all.
> .
>
From: --CELKO-- on
This is an old DB2 trick; I had not seen it done with MySQL. Since the
data is getting pushed on a parameter stack, it should fast in most
SQLs. SQL Server can take 2k parameters, but DB2 takes 32k and Oracle
takes 64K.

I have an article on it I have to send off this week; I will let you
know when it comes out.