Using "IN" operator in a dynamic query - sql

i've been searching SO for a while and found nothing related to this.
We use heavily the dynamic approach for most of our queries like this:
Declare #ContactId VarChar(8000)
Select #ContactId = '1'
Select *
From Person.Contact
Where 1 = 1 And
Case When Len(Ltrim(Rtrim(#ContactId))) = 0 Then 1 Else ContactID End =
Case When Len(Ltrim(Rtrim(#ContactId))) = 0 Then 1 Else #ContactId End
This way the query gets filtered dynamically if there's a value on the parameter
But the problem comes when trying the same stuff with several IDs like so:
Declare #ContactId VarChar(8000)
Select #ContactId = '1,2,3'
Select *
From Person.Contact
Where 1 = 1 And
Case When Len(Ltrim(Rtrim(#ContactId))) = 0 Then 1 Else ContactID End In (
Select Case When Len(Ltrim(Rtrim(#ContactId))) = 0 Then 1 Else ( Select id From dbo.SplitString(#ContactId,',') ) End )
Sql throws an error "Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression."
that's totally normal and expected, my question is:
Is there a way to dynamically do this kind of filtering ?
The solution we use is this:
Declare #Table Table(
Col1 Int,
Col2 Int,
Col3 Int
)
Insert #Table
Select Col1, Col2, Col3
From Person.Contact
Where [many filters except the in clause filters]
If Len(Ltrim(RTrim(#ContactId))) > 0
Select *
From #Table
Where ContactId In ( Select Id From dbo.SplitString(#ContactId, ',') )
Else
Select *
From #Table
But it's not an option when the query is massive and feeding a table variable is overkill for this. Hope i made my point and someone is kind enough to help me find a solution to this.
PS: Using sp_ExecuteSql is not an option in this scenario either, sorry.

How you should do this is with a table parameter.
But if you want to persist in this approach.
Declare #ContactId VarChar(8000)
Select #ContactId = '1,2,3'
Select *
From Person.Contact
where ',' + #contactID + ',' like '%,'+convert(varchar(50),contactid)+',%'

Try this
Select *
From Person.Contact
Where (
len(#contactid) > 0 AND
ContactID IN (Select id From dbo.SplitString(#ContactId,',')))
or 1 = 1

Related

Finding row until condition is met

This is my table:
PackingNr
SerienNr
PN185971
PN185972
PN185972
PN185974
PN185974
PN185978
PN185978
R005478
PN185968
R000547
PN185725
R004987
As an input I get PackingNr and I need to select SerienNr which is like Rxxxxx not PNxxxxx.
So for example, if I have input PN175971, I need to get SerienNr = R005478.
How can I do this inside of select query? I tried CASE but this won't work as I don't know how many times I have to go again.
My select query is selecting also other columns from different tables.
SELECT
... ,
CASE
WHEN PSPD.SerienNr LIKE '%PN%'
THEN
(SELECT SerienNr FROM PSAPacking_Det
WHERE PSAPacking_Det.PackingNr = PSPD.SerienNr)
ELSE PSPD.SerienNr
END AS SerienNr
...
FROM
PSAPacking PSPD
JOIN
...
WHERE
PSPD.PackingNr = 'PN185971'
You need a recursive CTE. Something like this:
WITH cte AS (
SELECT t.PackingNr, t.SerienNr
FROM YourTable t
WHERE t..PackingNr = 'YourValueHere'
UNION ALL
SELECT t.PackingNr, t.SerienNr
FROM YourTable t
JOIN cte ON cte.SerienNr = t.PackingNr
)
SELECT TOP (1)
*
FROM cte
WHERE cte.SerienNr LIKE 'R%';
try this
declare #var2 varchar(max) = 'PN185971' --PUT YOUR INPUT HERE
declare #var1 varchar(max);
while(#var2 not like 'R%')
begin
set #var1 = #var2
set #var2 = (select max(SerienNr) from PSAPacking where PackingNr = #var1)
end
select #var2
if it doesn't find the value starting with R it returns null

Conditionally modify query based on parameter

I have this query (something like a case statement which I can use and fix it)
select *
from mytable
where 1=1
and (isNull(ID, 0) = 0 OR UtilityID IN (9,40))
I also want to add another statement
select *
from mytable
where 1=1
and UtilityID NOT IN (9,40)
Everything is happening in a procedure, so want to use a variable like declare #something so if that is passed as 1, use the first statement and the if 0 is passed, use the latter one.
While I appreciate the genius in Dale's answer I find this more readable:
IF #something = 0
BEGIN
select *
from mytable
where ID IS NULL OR ID = 0 OR UtilityID IN (9,40);
END
IF #something = 1
BEGIN
select *
from mytable
where UtilityID NOT IN (9,40);
END
It's procedure code, so use IF to direct the control flow. Also expanded and simplified your where clauses
I think I understand your logic, ignoring the 1=1 (which does nothing) you want to only allow id = 0 when #something = 1. This should do it:
declare #something bit = 0;
declare #mytable table (ID int, UtilityID int);
insert into #mytable (ID, UtilityID)
select 0, 1 union all
select 1, 2 union all
select 2, 9 union all
select 3, 40;
select *
from #mytable
where (
(#something = 1 and (isnull(ID, 0) = 0 or UtilityID in (9,40)))
or (#something = 0 and (UtilityID not in (9,40)))
);
A more performant approach for a larger query could be:
select *
from #mytable
where (#something = 1 and (isnull(ID, 0) = 0 or UtilityID in (9,40)))
union all
select *
from #mytable
where (#something = 0 and (UtilityID not in (9,40)));
PS: Hopefully your ID cannot ever by null - it should have a constraint on it.

T-SQL IN Clause Combined With Case Statement

i have query where i have a in clause combined with a case statement.
the error i get is this:
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression.
i receive in stored procedure a concatenate varchar value like this '2,3,4,5' and i want in my query to filter the ids using the in clause
but something i missing
someone can give me a hand with this pls?
#ids varchar(50) = '2,3,4'
DECLARE #mylist TABLE (Id int)
INSERT INTO #mylist
select CONVERT(INT,v) from [dbo].[SplitString](#cardtypes)
//result of #mylist
//-------------------
//2
//3
//4
and then in the query
select * from mytable
where
ctable.Id IN (CASE
WHEN ISNULL(#ids,'') <> '' THEN (select id from #mylist)
ELSE ctable.Id
END)
Note:
ctable.Id (INT)
If i have only passing one value it works but if there are more it breaks
thanks in advance
You're trying to mix scalar value ctable.Id and some resultset select id from #mylist here in one case statement.
This can't be done, but you can rewrite your query like this:
select * from mytable
where
(isnull(#ids,'') <> '' and ctable.Id in (select id from #mylist))
or isnull(#ids,'') = ''
Out of curiosity, why are you using a temporary table? You can express this as a CTE:
with values as (
select CONVERT(INT, v)
from [dbo].[SplitString](#cardtypes)
)
select t.*
from <table> t
where t.id in (select v from values) or
not exists (select 1 from values);

Sql server exception: the statement did not return a result set

I have a SQL query that runs fine in SQL Server Management Studio, but when I copy and paste it into jasperreports's iReport to make a report, it gives me a SQL Server exception and says the statement did not return a result set. This has left me confused.
The query is:
declare #index int = 1
declare #t Table(ID INT, DI INT, INDBOOK1 INT, INDBOOK2 INT, delta INT)
while(#index < 18)
begin
INSERT INTO #t
select distinct top 18
col1.ID,
col1.DI,
col1.INDBOOK as INDBOOK1,
col2.INDBOOK as INDBOOK2,
col2.INDBOOK - col1.INDBOOK
FROM
table as col1
inner join
table as col2 on col2.ID = #index
and col2.DI = col1.DI+1
where
col1.ID = #index
set #index = #index + 1
end
select ID, DI, INDBOOK1, INDBOOK2, delta FROM #t
Does anybody know why this is giving me the no result set returned exception?
Any help appreciated.
Tough to tell without sample data etc. but I think this should be close to what you need, in a single statement with no explicit loops:
;WITH x([index]) AS
(
SELECT TOP (18) ROW_NUMBER() OVER (ORDER BY number)
FROM master..spt_values ORDER BY number
),
y AS
(
SELECT [index] = ROW_NUMBER() OVER (PARTITION BY col1.ID ORDER BY col1.ID),
col1.ID, col1.DI, col1.INDBOOK as INDBOOK1, col2.INDBOOK as INDBOOK2,
col2.INDBOOK - col1.INDBOOK as delta
FROM dbo.table as col1
INNER JOIN dbo.table as col2
ON col2.ID = col1.ID
AND col2.DI = col1.DI+1
)
SELECT y.ID, y.DI, y.INDBOOK1, y.INDBOOK2, y.delta
FROM x INNER JOIN y
ON x.[index] = y.[index]
WHERE y.[index] <= 18;

sql server conditional where clause big trouble

2Im in a big trouble, im refactoring a very big procedure to full text search, and I found a very important outer apply:
select top 1 *
from tablea
where
column1 like
case
when #value = 1 or #value = 2 then '%' + #something + '%'
else '%'
end
The logic here is: if #value is 1 or 2, get the first register with #something inside. Else, get any register.
What I need now is:
select top 1 *
from tablea
where
case
when #value = 1 or #value = 2 then contains(column1, #something)
else 1 = 1
end
The code above dont work, its mal formed, and I have no clue how solve that.
select top 1 *
from tablea
where
(#value IN (1,2) AND (#something = '""' OR contains(column1, #something)))
OR #value NOT IN (1,2)