How to use declared table values to delete from a table? - sql

I'm passing a delimited string to a stored procedure that enters the values into the declared table when it runs into the delimiter,
Here is my Stored Procedure.
Alter PROCEDURE s_BulkDeleteTest
(
#IDString VarChar(200)
)
AS
-- Creating Variables
DECLARE #numberLength int
DECLARE #numberCount int
DECLARE #TheIDs VarChar(200)
DECLARE #sTemp VarChar(100) -- to hold single characters
-- Creating a temp table
DECLARE #T TABLE
(
TheIDs VarChar(500)
)
--Initializing Variables for counting
SET #numberLength = LEN (#IDString)
SET #numberCount = 1
SET #TheIDs = ''
--Start looping through the keyword ids
WHILE (#numberCount <= #numberLength)
BEGIN
SET #sTemp = SUBSTRING (#IDString, #numberCount, 1)
IF (#sTemp = ',')
BEGIN
INSERT #T(TheIDs) VALUES (#TheIDs)
SET #TheIDs = ''
END
IF (#sTemp <> ',')
BEGIN
SET #TheIDs = #TheIDs + #sTemp
END
SET #numberCount = #numberCount + 1
END
This all works fine for adding the values to the #T table, but then I added this..
delete from [Subjects]
where (select TheIDs from #T) = SubjectID
that threw an error about there being more than one value in the declared table #T.
So I was wondering how can I use the values in #T and delete all those ID's from my Subjects table.

If TheIDs has any null values using IN operator will delete unexpect rows. I would suggest using EXISTS operator something like this...
DELETE FROM [Subjects]
WHERE EXISTS
(SELECT 1
FROM #T
WHERE [Subjects].SubjectId = TheIDs)

You need to use in:
delete from [Subjects]
where SubjectId in (select TheIDs from #T);
A result set with multiple rows cannot be equal to a single value.
EDIT:
The expression (select TheIds from #T) returns a set of values. The = operator works on scalar values, not sets. So, it doesn't normally work with this construct. The in operator compares a scalar to a set. so it does work.
There is one exception. When the subquery returns one row and one column, then it is converted to a scalar value. So, the expression would work if there were one row returned, or if you forced one row, as in:
where SubjectId = (select top 1 TheIDs from #T);
Of course, in would work in this situation as well.

Related

Using a temp table with a stored procedure to cycle through IDs [duplicate]

How can one call a stored procedure for each row in a table, where the columns of a row are input parameters to the sp without using a Cursor?
Generally speaking I always look for a set based approach (sometimes at the expense of changing the schema).
However, this snippet does have its place..
-- Declare & init (2008 syntax)
DECLARE #CustomerID INT = 0
-- Iterate over all customers
WHILE (1 = 1)
BEGIN
-- Get next customerId
SELECT TOP 1 #CustomerID = CustomerID
FROM Sales.Customer
WHERE CustomerID > #CustomerId
ORDER BY CustomerID
-- Exit loop if no more customers
IF ##ROWCOUNT = 0 BREAK;
-- call your sproc
EXEC dbo.YOURSPROC #CustomerId
END
You could do something like this: order your table by e.g. CustomerID (using the AdventureWorks Sales.Customer sample table), and iterate over those customers using a WHILE loop:
-- define the last customer ID handled
DECLARE #LastCustomerID INT
SET #LastCustomerID = 0
-- define the customer ID to be handled now
DECLARE #CustomerIDToHandle INT
-- select the next customer to handle
SELECT TOP 1 #CustomerIDToHandle = CustomerID
FROM Sales.Customer
WHERE CustomerID > #LastCustomerID
ORDER BY CustomerID
-- as long as we have customers......
WHILE #CustomerIDToHandle IS NOT NULL
BEGIN
-- call your sproc
-- set the last customer handled to the one we just handled
SET #LastCustomerID = #CustomerIDToHandle
SET #CustomerIDToHandle = NULL
-- select the next customer to handle
SELECT TOP 1 #CustomerIDToHandle = CustomerID
FROM Sales.Customer
WHERE CustomerID > #LastCustomerID
ORDER BY CustomerID
END
That should work with any table as long as you can define some kind of an ORDER BY on some column.
DECLARE #SQL varchar(max)=''
-- MyTable has fields fld1 & fld2
Select #SQL = #SQL + 'exec myproc ' + convert(varchar(10),fld1) + ','
+ convert(varchar(10),fld2) + ';'
From MyTable
EXEC (#SQL)
Ok, so I would never put such code into production, but it does satisfy your requirements.
I'd use the accepted answer, but another possibility is to use a table variable to hold a numbered set of values (in this case just the ID field of a table) and loop through those by Row Number with a JOIN to the table to retrieve whatever you need for the action within the loop.
DECLARE #RowCnt int; SET #RowCnt = 0 -- Loop Counter
-- Use a table variable to hold numbered rows containg MyTable's ID values
DECLARE #tblLoop TABLE (RowNum int IDENTITY (1, 1) Primary key NOT NULL,
ID INT )
INSERT INTO #tblLoop (ID) SELECT ID FROM MyTable
-- Vars to use within the loop
DECLARE #Code NVarChar(10); DECLARE #Name NVarChar(100);
WHILE #RowCnt < (SELECT COUNT(RowNum) FROM #tblLoop)
BEGIN
SET #RowCnt = #RowCnt + 1
-- Do what you want here with the data stored in tblLoop for the given RowNum
SELECT #Code=Code, #Name=LongName
FROM MyTable INNER JOIN #tblLoop tL on MyTable.ID=tL.ID
WHERE tl.RowNum=#RowCnt
PRINT Convert(NVarChar(10),#RowCnt) +' '+ #Code +' '+ #Name
END
Marc's answer is good (I'd comment on it if I could work out how to!)
Just thought I'd point out that it may be better to change the loop so the SELECT only exists once (in a real case where I needed to do this, the SELECT was quite complex, and writing it twice was a risky maintenance issue).
-- define the last customer ID handled
DECLARE #LastCustomerID INT
SET #LastCustomerID = 0
-- define the customer ID to be handled now
DECLARE #CustomerIDToHandle INT
SET #CustomerIDToHandle = 1
-- as long as we have customers......
WHILE #LastCustomerID <> #CustomerIDToHandle
BEGIN
SET #LastCustomerId = #CustomerIDToHandle
-- select the next customer to handle
SELECT TOP 1 #CustomerIDToHandle = CustomerID
FROM Sales.Customer
WHERE CustomerID > #LastCustomerId
ORDER BY CustomerID
IF #CustomerIDToHandle <> #LastCustomerID
BEGIN
-- call your sproc
END
END
If you can turn the stored procedure into a function that returns a table, then you can use cross-apply.
For example, say you have a table of customers, and you want to compute the sum of their orders, you would create a function that took a CustomerID and returned the sum.
And you could do this:
SELECT CustomerID, CustomerSum.Total
FROM Customers
CROSS APPLY ufn_ComputeCustomerTotal(Customers.CustomerID) AS CustomerSum
Where the function would look like:
CREATE FUNCTION ComputeCustomerTotal
(
#CustomerID INT
)
RETURNS TABLE
AS
RETURN
(
SELECT SUM(CustomerOrder.Amount) AS Total FROM CustomerOrder WHERE CustomerID = #CustomerID
)
Obviously, the example above could be done without a user defined function in a single query.
The drawback is that functions are very limited - many of the features of a stored procedure are not available in a user-defined function, and converting a stored procedure to a function does not always work.
For SQL Server 2005 onwards, you can do this with CROSS APPLY and a table-valued function.
Using CROSS APPLY in SQL Server 2005
Just for clarity, I'm referring to those cases where the stored procedure can be converted into a table valued function.
This is a variation on the answers already provided, but should be better performing because it doesn't require ORDER BY, COUNT or MIN/MAX. The only disadvantage with this approach is that you have to create a temp table to hold all the Ids (the assumption is that you have gaps in your list of CustomerIDs).
That said, I agree with #Mark Powell though that, generally speaking, a set based approach should still be better.
DECLARE #tmp table (Id INT IDENTITY(1,1) PRIMARY KEY NOT NULL, CustomerID INT NOT NULL)
DECLARE #CustomerId INT
DECLARE #Id INT = 0
INSERT INTO #tmp SELECT CustomerId FROM Sales.Customer
WHILE (1=1)
BEGIN
SELECT #CustomerId = CustomerId, #Id = Id
FROM #tmp
WHERE Id = #Id + 1
IF ##rowcount = 0 BREAK;
-- call your sproc
EXEC dbo.YOURSPROC #CustomerId;
END
This is a variation of n3rds solution above. No sorting by using ORDER BY is needed, as MIN() is used.
Remember that CustomerID (or whatever other numerical column you use for progress) must have a unique constraint. Furthermore, to make it as fast as possible CustomerID must be indexed on.
-- Declare & init
DECLARE #CustomerID INT = (SELECT MIN(CustomerID) FROM Sales.Customer); -- First ID
DECLARE #Data1 VARCHAR(200);
DECLARE #Data2 VARCHAR(200);
-- Iterate over all customers
WHILE #CustomerID IS NOT NULL
BEGIN
-- Get data based on ID
SELECT #Data1 = Data1, #Data2 = Data2
FROM Sales.Customer
WHERE [ID] = #CustomerID ;
-- call your sproc
EXEC dbo.YOURSPROC #Data1, #Data2
-- Get next customerId
SELECT #CustomerID = MIN(CustomerID)
FROM Sales.Customer
WHERE CustomerID > #CustomerId
END
I use this approach on some varchars I need to look over, by putting them in a temporary table first, to give them an ID.
If you don't what to use a cursor I think you'll have to do it externally (get the table, and then run for each statement and each time call the sp)
it Is the same as using a cursor, but only outside SQL.
Why won't you use a cursor ?
I usually do it this way when it's a quite a few rows:
Select all sproc parameters in a dataset with SQL Management Studio
Right-click -> Copy
Paste in to excel
Create single-row sql statements with a formula like '="EXEC schema.mysproc #param=" & A2' in a new excel column. (Where A2 is your excel column containing the parameter)
Copy the list of excel statements into a new query in SQL Management Studio and execute.
Done.
(On larger datasets i'd use one of the solutions mentioned above though).
DELIMITER //
CREATE PROCEDURE setFakeUsers (OUT output VARCHAR(100))
BEGIN
-- define the last customer ID handled
DECLARE LastGameID INT;
DECLARE CurrentGameID INT;
DECLARE userID INT;
SET #LastGameID = 0;
-- define the customer ID to be handled now
SET #userID = 0;
-- select the next game to handle
SELECT #CurrentGameID = id
FROM online_games
WHERE id > LastGameID
ORDER BY id LIMIT 0,1;
-- as long as we have customers......
WHILE (#CurrentGameID IS NOT NULL)
DO
-- call your sproc
-- set the last customer handled to the one we just handled
SET #LastGameID = #CurrentGameID;
SET #CurrentGameID = NULL;
-- select the random bot
SELECT #userID = userID
FROM users
WHERE FIND_IN_SET('bot',baseInfo)
ORDER BY RAND() LIMIT 0,1;
-- update the game
UPDATE online_games SET userID = #userID WHERE id = #CurrentGameID;
-- select the next game to handle
SELECT #CurrentGameID = id
FROM online_games
WHERE id > LastGameID
ORDER BY id LIMIT 0,1;
END WHILE;
SET output = "done";
END;//
CALL setFakeUsers(#status);
SELECT #status;
A better solution for this is to
Copy/past code of Stored Procedure
Join that code with the table for which you want to run it again (for each row)
This was you get a clean table-formatted output. While if you run SP for every row, you get a separate query result for each iteration which is ugly.
In case the order is important
--declare counter
DECLARE #CurrentRowNum BIGINT = 0;
--Iterate over all rows in [DataTable]
WHILE (1 = 1)
BEGIN
--Get next row by number of row
SELECT TOP 1 #CurrentRowNum = extendedData.RowNum
--here also you can store another values
--for following usage
--#MyVariable = extendedData.Value
FROM (
SELECT
data.*
,ROW_NUMBER() OVER(ORDER BY (SELECT 0)) RowNum
FROM [DataTable] data
) extendedData
WHERE extendedData.RowNum > #CurrentRowNum
ORDER BY extendedData.RowNum
--Exit loop if no more rows
IF ##ROWCOUNT = 0 BREAK;
--call your sproc
--EXEC dbo.YOURSPROC #MyVariable
END
I had some production code that could only handle 20 employees at a time, below is the framework for the code. I just copied the production code and removed stuff below.
ALTER procedure GetEmployees
#ClientId varchar(50)
as
begin
declare #EEList table (employeeId varchar(50));
declare #EE20 table (employeeId varchar(50));
insert into #EEList select employeeId from Employee where (ClientId = #ClientId);
-- Do 20 at a time
while (select count(*) from #EEList) > 0
BEGIN
insert into #EE20 select top 20 employeeId from #EEList;
-- Call sp here
delete #EEList where employeeId in (select employeeId from #EE20)
delete #EE20;
END;
RETURN
end
I had a situation where I needed to perform a series of operations on a result set (table). The operations are all set operations, so its not an issue, but...
I needed to do this in multiple places. So putting the relevant pieces in a table type, then populating a table variable w/ each result set allows me to call the sp and repeat the operations each time i need to .
While this does not address the exact question he asks, it does address how to perform an operation on all rows of a table without using a cursor.
#Johannes offers no insight into his motivation , so this may or may not help him.
my research led me to this well written article which served as a basis for my solution
https://codingsight.com/passing-data-table-as-parameter-to-stored-procedures/
Here is the setup
drop type if exists cpRootMapType
go
create type cpRootMapType as Table(
RootId1 int
, RootId2 int
)
go
drop procedure if exists spMapRoot2toRoot1
go
create procedure spMapRoot2toRoot1
(
#map cpRootMapType Readonly
)
as
update linkTable set root = root1
from linktable lt
join #map m on lt.root = root2
update comments set root = root1
from comments c
join #map m on c.root = root2
-- ever growing list of places this map would need to be applied....
-- now consolidated into one place
here is the implementation
... populate #matches
declare #map cpRootMapType
insert #map select rootid1, rootid2 from #matches
exec spMapRoot2toRoot1 #map
I like to do something similar to this (though it is still very similar to using a cursor)
[code]
-- Table variable to hold list of things that need looping
DECLARE #holdStuff TABLE (
id INT IDENTITY(1,1) ,
isIterated BIT DEFAULT 0 ,
someInt INT ,
someBool BIT ,
otherStuff VARCHAR(200)
)
-- Populate your #holdStuff with... stuff
INSERT INTO #holdStuff (
someInt ,
someBool ,
otherStuff
)
SELECT
1 , -- someInt - int
1 , -- someBool - bit
'I like turtles' -- otherStuff - varchar(200)
UNION ALL
SELECT
42 , -- someInt - int
0 , -- someBool - bit
'something profound' -- otherStuff - varchar(200)
-- Loop tracking variables
DECLARE #tableCount INT
SET #tableCount = (SELECT COUNT(1) FROM [#holdStuff])
DECLARE #loopCount INT
SET #loopCount = 1
-- While loop variables
DECLARE #id INT
DECLARE #someInt INT
DECLARE #someBool BIT
DECLARE #otherStuff VARCHAR(200)
-- Loop through item in #holdStuff
WHILE (#loopCount <= #tableCount)
BEGIN
-- Increment the loopCount variable
SET #loopCount = #loopCount + 1
-- Grab the top unprocessed record
SELECT TOP 1
#id = id ,
#someInt = someInt ,
#someBool = someBool ,
#otherStuff = otherStuff
FROM #holdStuff
WHERE isIterated = 0
-- Update the grabbed record to be iterated
UPDATE #holdAccounts
SET isIterated = 1
WHERE id = #id
-- Execute your stored procedure
EXEC someRandomSp #someInt, #someBool, #otherStuff
END
[/code]
Note that you don't need the identity or the isIterated column on your temp/variable table, i just prefer to do it this way so i don't have to delete the top record from the collection as i iterate through the loop.

Cannot insert the value NULL into column with procedure

This is not a duplicate.
I do understand what the issue means but I don't understand why because the variable contains data. I'm basically trying to make a char(4) column increase alone (just like identity with integers). If the table doesn't contain anything, the first value would be 'C001' otherwise, It simply increase based on the last record.
CREATE PROCEDURE ADD_CL(#nom VARCHAR(20),
#dn DATE)
AS
BEGIN
DECLARE #B CHAR(4)
DECLARE #B_to_int INT
DECLARE #B_new_value CHAR(4)
IF EXISTS(SELECT TOP 1 *
FROM CLIENT)
SET #B_new_value = 'C001'
ELSE
BEGIN
SELECT TOP 1 #B = code_client
FROM client
ORDER BY code_client DESC
SET #B_to_int = CAST(SUBSTRING(#B, 2, 3) AS INTEGER)
SET #B_to_int = #B_to_int + 1;
SET #B_new_value = LEFT(#B, 1) + RIGHT('00' + CAST(#B_to_int AS INT), 3)
END
INSERT INTO CLIENT
VALUES (#B_new_value,
#nom,
#dn)
END
Cannot insert the value NULL into column 'code_client', table 'dbo.CLIENT'; column does not allow nulls. INSERT fails.
#B_new_value represent code_client
Your If Exists should be If Not Exists.
So change
if exists(select TOP 1 * from CLIENT)
to
if not exists(select TOP 1 * from CLIENT)
Also you are adding 00 to your final #B_to_int which is cast as int. so it will show C2,C3 and so on.
If you want to retain the same format, cast it to varchar
SET #B_new_value = LEFT(#B,1) + '00' + CAST(#B_to_int as varchar)
Above line will work only till the count is 9. and then it will continue replicating itself with 1 because 10 will be 0010 and final output will be C0010. To eliminate this issue, use replicate and replicate 0 until 3 characters.
SET #B_new_value = LEFT(#B,1) + REPLICATE('0',3-LEN(#B_to_int)) + #B_to_int
Good Luck.
The other answers already tell you that you should be using NOT EXISTS.
This numbering scheme is quite possibly something you'll regret but you could simplify this a lot as well as making it safer in conditions of concurrency and when you run out of numbers by just doing
CREATE PROCEDURE ADD_CL(#nom VARCHAR(20),
#dn DATE)
AS
BEGIN
DECLARE #B VARCHAR(5);
SET XACT_ABORT ON;
BEGIN TRAN
SELECT #B = FORMAT(1 + RIGHT(ISNULL(MAX(code_client), 'C000'), 3), '\C000')
FROM CLIENT WITH(ROWLOCK, UPDLOCK, HOLDLOCK);
IF ( LEN(#B) > 4 )
THROW 50000, 'Exceeded range',1;
INSERT INTO CLIENT
VALUES (#B,
#nom,
#dn);
COMMIT
END
I believe the following should be 'NOT EXISTS'
if EXISTS(select TOP 1 * from CLIENT)

Removing ' ' from sql query and stored proc

I have a table in which a column named data is of type varbinary . If I do a simple query
select * from tab where data = 1 then it works but if I do select * from tab where data = '1' then it does not return any row. The issue comes when I create a stored proc to retrieve data from this table and it converts the query and adds ' ' in the parameter when querying and so I am not able to retrieve any data. Can some one please tell me how to get around this issue.
Parameters
#ID INT = NULL
,#Data varchar(100) = NULL
CREATE TABLE #Results (
ID INT
,Data varchar(100)
)
BEGIN
INSERT #Results (
ID
,Data
)
SELECT
SK.ID
,SK.Data
FROM dbo.tab SK
where SK.ID = #ID And SK.data = #data
END
SELECT #TotalRows = COUNT(*)
FROM #Results
SELECT #TotalRows TotalRows
Now from the code when I execute this statement
oReader = ExecuteReader(oConn, CommandType.StoredProcedure, "Proc", New SqlParameter("#ID", Request.ID), _
New SqlParameter("#Data", Request.Data))
I see in SQL Profiler that it runs the query as 'data'
which does not return any rows
Thanks
Since you have said that you have written an SP, I think the inpput parameter is specified as NVARCHAR or VARCHAR
Below is one way of doing but i'm guessing that the column called data will only have integer values in the first solution.
DECLARE #X VARCHAR(5)
SET #X = '1 '
SELECT CAST(#X AS INT)
The above is only if the Data column specified above is Integer.
If the same is string (VARCHAR) you can write a User defined function to do the same.
CREATE FUNCTION dbo.TRIM(#string VARCHAR(8000))
RETURNS VARCHAR(8000)
BEGIN
RETURN LTRIM(RTRIM(#string))
END
SELECT dbo.TRIM('1 ')
I hope the above was useful, I did get the idea rather copied the function from here
http://blog.sqlauthority.com/2007/04/24/sql-server-trim-function-udf-trim/

SQL server - Split and sum of a single cell

I have a table cell of type nvarchar(max) that typically looks like this:
A03 B32 Y660 P02
e.g. a letter followed by a number, separated by spaces. What I want to do is get a sum of all those numbers in a SQL procedure. Something rather simple in other languages, but I am fairly new to SQL and besides it seems to me like a rather clumsy language to play around with strings.
Aaanyway, I imagine it would go like this:
1) Create a temporary table and fill it using a split function
2) Strip the first character of every cell
3) Convert the data to int
4) Update target table.column set to sum of said temporary table.
So I got as far as this:
CREATE PROCEDURE [dbo].[SumCell] #delimited nvarchar(max), #row int
AS
BEGIN
declare #t table(data nvarchar(max))
declare #xml xml
set #xml = N'<root><r>' + replace(#delimited,' ','</r><r>') + '</r></root>'
insert into #t(data)
select
r.value('.','varchar(5)') as item
from #xml.nodes('//root/r') as records(r)
UPDATE TargetTable
SET TargetCell = SUM(#t.data) WHERE id = #row
END
Obviously, the first char stripping and conversion to int part is missing and on top of that, I get a "must declare the scalar variable #t" error...
Question is not very clear so assuming your text is in a single cell like A3 B32 Y660 P20 following snippet can be used to get the sum.
DECLARE #Cell NVARCHAR(400), #Sum INT, #CharIndex INT
SELECT #Cell = 'A3 B32 Y660 P20',#Sum=0
WHILE (LEN(LTRIM(#Cell))>0)
BEGIN
SELECT #CharIndex = CHARINDEX(' ',#Cell,0)
SELECT #Sum = #Sum +
SUBSTRING(#Cell,2,CASE WHEN #CharIndex>2 THEN #CharIndex-2 ELSE LEN(#Cell)-1 END )
SELECT #Cell = SUBSTRING(#Cell,#CharIndex+1,LEN(#Cell))
IF NOT (#CharIndex >0) BREAK;
END
--#Sum has the total of cell numbers
SELECT #Sum
I'm making the assumption that you really want to be able to find the sum of values in your delimited list for a full selection of a table. Therefore, I believe the most complicated part of your question is to split the values. The method I tend to use requires a numbers table, So I'll start with that:
--If you really want to use a temporary numbers table don't use this method!
create table #numbers(
Number int identity(1,1) primary key
)
declare #counter int
set #counter = 1
while #counter<=10000
begin
insert into #numbers default values
set #counter = #counter + 1
end
I'll also create some test data
create table #data(
id int identity(1,1),
cell nvarchar(max)
)
insert into #data(cell) values('A03 B32 Y660 P02')
insert into #data(cell) values('Y72 A12 P220 B42')
Then, I'd put the split functionality into a CTE to keep things clean:
;with split as (
select d.id,
[valOrder] = row_number() over(partition by d.cell order by n.Number),
[fullVal] = substring(d.cell, n.Number, charindex(' ',d.cell+' ',n.Number) - n.Number),
[char] = substring(d.cell, n.Number, 1),
[numStr] = substring(d.cell, n.Number+1, charindex(' ',d.cell+' ',n.Number) - n.Number)
from #data d
join #numbers n on substring(' '+d.cell, n.Number, 1) = ' '
where n.Number <= len(d.cell)+1
)
select id, sum(cast(numStr as int))
from split
group by id

SQL: Retrieving Unique ID with Multiple Attributes

Ok, I had trouble describing this. I have:
material table (materialID, material, etc...)
ThicknessRange table (ThicknessRangeID, ThicknessRange)
MaterialThicknessRange table (MaterialID, ThicknessRangeID)
I am trying to retrieve all MaterialID's from the MaterialThicknessRange table that fit all required ThicknessRangeID's.
For example, any MaterialID with ThicknessRangeID 1 AND ThicknessRangeID 2, etc with a variable number of ThicknessRangeID's (selected from checkboxes by the user).
Thanks in advance.
Are you guaranteed to have only one entry in the MaterialThicknessRange table for a given Material/ThicknessRange combination?
SELECT MaterialID, COUNT(MaterialID) As NumMaterialThicknesses
FROM MaterialThicknessRange
WHERE ThicknessRangeID IN (1, 2)
GROUP BY MaterialID
HAVING COUNT(MaterialID) > 1
I'm using something like this
select MaterialID from MaterialThicknessRange MTR inner join
dbo.TransformCSVToTable('1,2,15') IDs on MTR.ThiknessRangeID = IDs.ID
where dbo.TransformCSVToTable is a user defined function to transform a csv string to a one column table. Bellow is one sample of such function
ALTER FUNCTION [dbo].[fn_IntegerParameterListFromString]
(
#IntegerParameterList varchar(max)
)
RETURNS #result TABLE (IntegerID int)
AS
begin
declare #temp table (IntegerID int)
declare #s varchar(max), #s1 varchar(10)
declare #len int
set #len =len(#IntegerParameterList)
set #s = #IntegerParameterList
if (right(#s,1)<>',') set #s = #s +','
while #s<>''
begin
set #s1 = substring(#s,1,charindex(',',#s)-1)
if (isnumeric(#s1)= 1)
insert #result (IntegerID) Values ( Cast(#s1 as int))
if (CHARINDEX(',',#s)>0)
begin
set #s = substring (#s, charindex(',',#s)+1, #Len)
end
else
begin
if isnumeric(#s) = 1
insert #result (IntegerID) Values ( Cast(#s as int))
set #s = ''
end
end
return
end