one way is by using the famous [de limited 8K splitter] function by Jeff Moden
please click arrow to the left for the 8K Function Code
CREATE FUNCTION [dbo].[DelimitedSplit8K]
--===== Define I/O parameters
(@pString VARCHAR(8000), @pDelimiter CHAR(1))
--WARNING!!! DO NOT USE MAX DATA-TYPES HERE! IT WILL KILL PERFORMANCE!
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
--===== "Inline" CTE Driven "Tally Table" produces values from 1 up to 10,000...
-- enough to cover VARCHAR(8000)
WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), --10E+1 or 10 rows
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
-- for both a performance gain and prevention of accidental "overruns"
SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
SELECT 1 UNION ALL
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
),
cteLen(N1,L1) AS(--==== Return start and length (for use in substring)
SELECT s.N1,
ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000)
FROM cteStart s
)
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
Item = SUBSTRING(@pString, l.N1, l.L1)
FROM cteLen l
;
go
select * from [DelimitedSplit8K]( 'AXOO1;AX005;AK013', ';')
USE sqlteam
GO
declare @codes nvarchar(100) = 'AXOO1;AX005;AK013;'
create table #product(productcode nvarchar(10), ProductName nvarchar(50))
insert into #product
select top 100000 case
when column_id % 2 = 0 then 'AX' + cast(column_id as nvarchar(50))
else 'AK' + cast(column_id as nvarchar(50))
end as productcode,
name
from sys.all_columns
union
select 'AXOO1', 'Chicken' union
select 'AX005', 'Beef' union
select 'AK013', 'Goat'
select *
From #product p
join DelimitedSplit8K(@codes,';') c on p.productcode = c.Item;
--table type approach
IF TYPE_ID(N'ProductCodeType') IS NOT NULL
DROP TYPE [dbo].[ProductCodeType]
CREATE TYPE [dbo].[ProductCodeType] AS TABLE(
ProductCode nvarchar(10) NOT NULL
)
go
DECLARE @ProductCode AS ProductCodeType;
insert into @ProductCode
select 'AXOO1' union
select 'AX005' union
select 'AK013'
select *
From #product p
join @ProductCode c on p.productcode = c.productcode;
drop table #product
Thanks. The big reason is because of the test code and the long history located in the header not to mention the usage examples. It helps build trust in the code when a DBA sees it. A lot of DBAs are "function phobics". A Developer stands a better chance getting the code in play when such a DBA is present because of the proper documentation and, perhaps, a little when they they see who wrote it.