Join table using columns which contains other table's id's separated by commas - sql

I have FACULTY table which contain the column with other table's id's separated by commas. I want to join those with respective table.
faculty table:
id | name | course_id | subject_id
a | smith | 2,3 | 1,2
course table:
id | name
1 | bcom
2 | mcom
3 | bba
subject table:
id | name
1 | account
2 | state
3 | economics
I want to get result from these table like..
faculty.id, faculty.name, course.name(using faculty.course_id), subject.name(using faculty.subject_id)
I have tried a lot of queries and also finds from Google but it didn't gave me proper result.

I do not think the performance will be too nice but worths trying. This solution would work in SQL SERVER:
SELECT *
FROM faculty F
JOIN course C
ON ','+F.course_id+',' LIKE '%,'+CONVERT(VARCHAR,C.ID) +',%'
JOIN subject S
ON ','+F.subject_id_id+',' LIKE '%,'+CONVERT(VARCHAR,S.ID) +',%'
Based on Albin Sunnanbo's comment i would also sugget you add some many too many tables:
fcourses
facultyId
courseId
and
fsubjects
facultyId
subjectId
That way you could do a proper join :
SELECT *
FROM faculty F
JOIN fcourses FC
ON F.Id = FC.facultyId
JOIN course C
ON FC.courseId = C.ID
JOIN fsubjects FS
ON F.Id = FS.facultyId
JOIN subject S
ON FS.courseId = S.ID

You can do the following query
select * from faculty F
JOIN course C
on CHARINDEX((','+CAST(c.id as varchar(10))+','), (','+f.courseid+',')) > 0
JOIN subject s
on CHARINDEX((','+CAST(s.id as varchar(10))+','), (','+f.subjectid+',')) > 0

I've done something similar like this:
select f.id, f.lname, f.fname, U.useridlist
from TABLE1 F, TABLE2 U
where ',' || U.useridlist || ',' like '%,' || f.id || ',%'

If you can create a 'string to int table' function, I would look at the following:
Create the function
CREATE FUNCTION [dbo].[udf_ConvertIntListToTable] (#list varchar(MAX))
RETURNS #tbl TABLE (val int) AS
BEGIN
DECLARE #ix int,
#pos int,
#str varchar(MAX),
#num int
SET #pos = 1
SET #ix = 1
WHILE #ix > 0
BEGIN
SET #ix = charindex(',', #list, #pos)
IF #ix > 0
SET #str = substring(#list, #pos, #ix - #pos)
ELSE
SET #str = substring(#list, #pos, len(#list))
SET #str = ltrim(rtrim(#str))
IF #str LIKE '%[0-9]%' AND
(#str NOT LIKE '%[^0-9]%' OR
#str LIKE '[-+]%' AND
substring(#str, 2, len(#str)) NOT LIKE '[-+]%[^0-9]%')
BEGIN
SET #num = convert(int, #str)
INSERT #tbl (val) VALUES(#num)
END
SET #pos = #ix + 1
END
RETURN
END
Then query using CROSS APPLY
declare #FacultyTable table(id int PRIMARY KEY, name nvarchar(50), course_id varchar(50))
declare #CourseTable table(id int PRIMARY KEY, name nvarchar(50))
insert into #FacultyTable values(1, 'Peter Sagal', '11,22')
insert into #FacultyTable values(2, 'Carl Kasell', '22,33')
insert into #CourseTable values(11,'News')
insert into #CourseTable values(22,'News')
insert into #CourseTable values(33,'News')
insert into #CourseTable values(44,'News')
select *
from #FacultyTable f
CROSS APPLY(
SELECT *
FROM #CourseTable c
WHERE
c.id IN (SELECT * FROM dbo.udf_ConvertIntListToTable(f.course_id))
) tCourses

Related

Script to get all numbers between Characters

I need to find a way to get the numbers between the dashes. This is the only way I know to do it, but I know that not all of our accounts are the same length. So I am just looking for a way to get everything between before, after and between the dashes. This is an example of the types of accounts we have. '2-0-200-325-0' and '1-0-1105-1500-1520' The non-digit characters are only dashes and nothing else.
declare #Department Int
declare #Account Int
declare #Company Int
declare #Location Int
declare #SubAccount Int
declare #AccountNo varchar(24) = '2-0-200-325-0'
declare #CommaPos Int
select #CommaPos = charindex('-',#accountno)
set #Company = substring(#accountno,1,#CommaPos-1)
select #Company as Company
set #Location = Substring(#AccountNo, #CommaPos+1, 1)
select #Location as Location
set #Department = Substring(#AccountNo, #CommaPos+3, 4)
select #Department as Department
set #Account = Substring(#AccountNo, #CommaPos+8, 4)
select #Account as Account
set #SubAccount = Substring(#AccountNo, #CommaPos+13, 4)
select #SubAccount as SubAccount
One option uses a recursive query for parsing. This properly handles the variable lenght of each part - and can easily be extended to handle more parts if needed.
-- declare the variables
declare #AccountNo varchar(24) = '2-0-200-325-0';
declare #Department Int;
declare #Account Int;
declare #Company Int;
declare #Location Int;
declare #SubAccount Int;
-- parse and assign values to variables
with cte as (
select
substring(#AccountNo + '-', 1, charindex('-', #AccountNo + '-') - 1) val,
substring(#AccountNo + '-', charindex('-', #AccountNo + '-') + 1, len(#AccountNo)) rest,
1 lvl
union all
select
substring(rest, 1, charindex('-', rest) - 1),
substring(rest, charindex('-', rest) + 1, len(rest)),
lvl + 1
from cte
where charindex('-', rest) > 0
)
select
#Company = max(case when lvl = 1 then val end),
#Location = max(case when lvl = 2 then val end),
#Department = max(case when lvl = 3 then val end),
#Account = max(case when lvl = 4 then val end),
#SubAccount = max(case when lvl = 5 then val end)
from cte;
-- check the results
select
#AccountNo AccountNo,
#Company Company,
#Location Location,
#Department Department,
#Account Account,
#SubAccount SubAccount
;
Demo on DB Fiddle:
AccountNo | Company | Location | Department | Account | SubAccount
:------------ | ------: | -------: | ---------: | ------: | ---------:
2-0-200-325-0 | 2 | 0 | 200 | 325 | 0
This was my approach:
--first I use a declared table variable to simulate your issue:
DECLARE #tbl TABLE(ID INT IDENTITY,ACCOUNT_NO VARCHAR(24))
INSERT INTO #tbl VALUES('2-0-200-325-0');
--The query
SELECT t.ID
,t.ACCOUNT_NO
,casted.value('x[1]','int') AS Company
,casted.value('x[2]','int') AS Location
,casted.value('x[3]','int') AS Department
,casted.value('x[4]','int') AS Account
,casted.value('x[5]','int') AS SubAccount
FROM #tbl t
CROSS APPLY(VALUES(CAST('<x>' + REPLACE(t.ACCOUNT_NO,'-','</x><x>') + '</x>' AS XML))) A(casted);
The idea in short:
We use simple string operations to transform your dash-separated list of numbers into XML.
Now we can use XQuery to retrieve each element by its position (typesafe!).
Find details here. In this link there is also a faster approach using JSON support (needs v2016+):
SELECT t.ID
,t.ACCOUNT_NO
,A.*
FROM #tbl t
CROSS APPLY OPENJSON(CONCAT('[[',REPLACE(t.ACCOUNT_NO,'-',','),']]'))
WITH(Company INT '$[0]'
,Location INT '$[1]'
,Department INT '$[2]'
,Account INT '$[3]'
,SubAccount INT '$[4]') A;
The idea of this JSON approach:
Agains we use some simple string operations to transform your string into a JSON array.
Using two array brackets ([[) allows to use OPENJSON() with a WITH clause.
The WITH clause allows to grab each fragment by its (zero-based) position (typesafe).
The WITH clause is some kind of implicit pivoting.
/*
-- First Create this function. This is what you need.
-- It will split a sentence into words, given a defined separator
CREATE FUNCTION [dbo].[udf_SplitString] (#Sentence varchar(max), #Separator char(1))
RETURNS #WordList TABLE (Word varchar(50))
AS
BEGIN
SET #Separator = ISNULL(#Separator, ' ')
DECLARE #Word varchar(50)
SET #Sentence = LTRIM(#Sentence) + #Separator
WHILE (CHARINDEX(#Separator, #Sentence) > 0)
BEGIN
SET #Word = SUBSTRING(#Sentence, 1, CHARINDEX(#Separator, #Sentence) - 1)
INSERT INTO #WordList SELECT LTRIM(#Word)
-- Remove word added to the List from the sentence.
SET #Sentence = SUBSTRING(#Sentence, CHARINDEX(#Separator, #Sentence) + 1, LEN(#Sentence))
SET #Sentence = LTRIM(#Sentence)
END
RETURN
END
GO
*/
DECLARE #AccountList TABLE (AccountNo varchar(20), Variable varchar(20))
INSERT INTO #AccountList VALUES
('1-0-1105-1200-1290','')
, ('1-0-1105-1500-1520','')
, ('1-0-1105-1500-1620','')
, ('1-0-1106-1200-1250','')
, ('1-0-1106-1200-1290','')
, ('1-0-1106-1500-1520','')
;
DECLARE #VariableList TABLE (OrderNo int, VariableName varchar(20))
INSERT INTO #VariableList VALUES
(1, 'Company ')
, (2, 'Location ')
, (3, 'Department ')
, (4, 'Account ')
, (5, 'SubAccount ')
;
SELECT
AccountNo
, Variable = (SELECT VariableName FROM #VariableList WHERE RowNo = OrderNo)
, Value = Word
FROM (
SELECT
RowNo = ROW_NUMBER() OVER(PARTITION BY AccountNo ORDER BY AccountNo)
, AccountNo = L.AccountNo
, Variable = ''
, Word = W.Word
FROM #AccountList L
CROSS APPLY dbo.udf_SplitString(L.AccountNo, '-') W -- Here how to use the function
) R

Can't get table function to work with if statement

trying to create a table function that returns a two column table that must be conditioned with an if statement.
I have two other functions that do this separate but cant get it to work when combined.
create function dbo.PDM_GetCategorytable (#Mystring varchar(200) ,#appid int)
returns table
as -- begin
--return
begin
-- declare #MyString varchar(200);
--set #MyString= 'Fred mtf is dead'--'RE: [Encrypt]]FW: MTF Military ---
--UPDATE URGENT'
--declare #AppId int =5
declare #Dubb Table (Col varchar(200));
insert into #dubb
(Col )
values ( #Mystring);
if ((select top 1 categoryid from #dubb a
left join
(SELECT (pass.Recordid) as categoryid , pass.appid,
pass.Priority_Identifier, pass.PrioritySortorder, pass.Category,
ps.Search_String AS SrchVar
FROM dbo.PDM_PriorityAssignments AS pass INNER JOIN
dbo.PDM_Priority_Search AS ps ON pass.Recordid =
ps.PriorityAssignmentid where pass.appid=#AppId ) b on a.col like '%' +
b.SrchVar + '%'
order by PrioritySortorder) is not null)--'where
appid=#AppId
begin
select top 1 categoryid,Category from #dubb a
left join
(SELECT (pass.Recordid) as categoryid , pass.appid,
pass.Priority_Identifier, pass.PrioritySortorder, pass.Category,
ps.Search_String AS SrchVar
FROM dbo.PDM_PriorityAssignments AS pass INNER JOIN
dbo.PDM_Priority_Search AS ps ON pass.Recordid =
ps.PriorityAssignmentid where pass.appid=#AppId ) b on a.col like '%' +
b.SrchVar + '%'
order by PrioritySortorder;
end
else
begin
select recordid as categoryid,Category FROM dbo.PDM_PriorityAssignments
AS pass where appid=#AppId and Priority_Identifier like 'Routine'
end
return
end;
expected results will be the returning of two columns , category id, and category.
seems like a duplicate for Multi statement table valued function
Multi-statement Table Valued Function vs Inline Table Valued Function
here is an example how to achieve this.
CREATE FUNCTION foo
(#param int)
RETURNS
#T TABLE (id int, val varchar)
As
BEGIN
IF (#param = 1)
insert into #t Select 1, 'a';
else
insert into #t Select 0, 'a';
return ;
END
GO
The problem is exactly because of the algorithm you need to use.
That requirement prevents you from returning just a table. On this scenarios you need to do something a bit different.
First define the resulting table and then, insert the values as you need.
I canĀ“t run it without your data but it should work.
CREATE FUNCTION dbo.PDM_GetCategorytable (
#Mystring VARCHAR(200)
,#appid INT
)
RETURNS #GetCategorytable TABLE
(
[CategoryId] INT,
[Category] VARCHAR(200))
AS -- begin
--return
BEGIN
-- declare #MyString varchar(200);
--set #MyString= 'Fred mtf is dead'--'RE: [Encrypt]]FW: MTF Military ---
--UPDATE URGENT'
--declare #AppId int =5
DECLARE #Dubb TABLE (Col VARCHAR(200));
INSERT INTO #dubb (Col)
VALUES (#Mystring);
IF (
(
SELECT TOP 1 categoryid
FROM #dubb a
LEFT JOIN (
SELECT (pass.Recordid) AS categoryid
,pass.appid
,pass.Priority_Identifier
,pass.PrioritySortorder
,pass.Category
,ps.Search_String AS SrchVar
FROM dbo.PDM_PriorityAssignments AS pass
INNER JOIN dbo.PDM_Priority_Search AS ps ON pass.Recordid = ps.PriorityAssignmentid
WHERE pass.appid = #AppId
) b ON a.col LIKE '%' + b.SrchVar + '%'
ORDER BY PrioritySortorder
) IS NOT NULL
) --'where
-- NOT SURE WHAT YOU ARE TRYING TO DO WITH THIS -- appid = #AppId
BEGIN
insert into #GetCategorytable(Categoryid, Category)
SELECT TOP 1 categoryid
,Category
FROM #dubb a
LEFT JOIN (
SELECT (pass.Recordid) AS categoryid
,pass.appid
,pass.Priority_Identifier
,pass.PrioritySortorder
,pass.Category
,ps.Search_String AS SrchVar
FROM dbo.PDM_PriorityAssignments AS pass
INNER JOIN dbo.PDM_Priority_Search AS ps ON pass.Recordid = ps.PriorityAssignmentid
WHERE pass.appid = #AppId
) b ON a.col LIKE '%' + b.SrchVar + '%'
ORDER BY PrioritySortorder;
END
ELSE
BEGIN
insert into #GetCategorytable(Categoryid, Category)
SELECT recordid AS categoryid ,Category FROM dbo.PDM_PriorityAssignments AS pass
WHERE appid = #AppId
AND Priority_Identifier LIKE 'Routine'
END
RETURN
END;

Parse text field and join tables

I have 2 tables.
Table Heroes - 2 records
Name NVARCHAR(50)
PowerIds NVARCHAR(50)
Name PowerIds
'Hulk' '1,3'
'Reed Richards' '2'
Table Powers - 3 records
PowerId INT
PowerDescr NVARCHAR(50)
PowerId PowerDescr
1 'Strength'
2 'Intelligence'
3 'Durability'
What would be the smartest way to achieve this in a SELECT:
Name Powers
'Hulk' 'Strength, Durability'
'Reed Richards' 'Intelligence'
I cannot change the table structure, since this is a third party product.
The smartest way would be to normalize your table. Change the Heroes table to
Name PowerId
'Hulk' 1
'Hulk' 3
'Reed Richards' 2
or remove the power from the Heroes table and add another table that holds only the reference to a hero and the powers like this
HeroID PowerID
1 1
1 3
2 2
Never store multiple data in one column!
Try This:
SELECT Name,
STUFF(
(SELECT ',' + CAST(P.PowerDescr as VARCHAR(MAX))
FROM fn_ParseCsvString(H1.PowerIds, ',') H2
INNER JOIN Powers P ON P.PowerId = H2.ParsedString
FOR XML path('')),1,1,''
) AS Strength
FROM Heroes H1
Function:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[fn_ParseCsvString]
(
#csvString VARCHAR(MAX),
#delimiter VARCHAR(MAX)
)
RETURNS #parsedStringTable TABLE (ParsedString VARCHAR(MAX))
AS
BEGIN
DECLARE #startIndex INT, #targetedIndex INT
SELECT
#startIndex = 1
WHILE #startIndex <= LEN(#CSVString)
BEGIN
SELECT
#targetedIndex = charindex(#Delimiter, #CSVString, #startIndex)
IF #targetedIndex = 0
BEGIN
SELECT
#targetedIndex = len(#CSVString) + 1
END
INSERT #parsedStringTable
SELECT
SUBSTRING(#CSVString, #startIndex, #targetedIndex - #startIndex)
SELECT #startIndex = #targetedIndex + LEN(#Delimiter)
END
RETURN
END
GO
Here you can find a SQL Fiddle example.

Convert Comma Delimited String to bigint in SQL Server

I have a varchar string of delimited numbers separated by commas that I want to use in my SQL script but I need to compare with a bigint field in the database. Need to know to convert it:
DECLARE #RegionID varchar(200) = null
SET #RegionID = '853,834,16,467,841,460,495,44,859,457,437,836,864,434,86,838,458,472,832,433,142,154,159,839,831,469,442,275,840,299,446,220,300,225,227,447,301,450,230,837,441,835,302,477,855,411,395,279,303'
SELECT a.ClassAdID, -- 1
a.AdURL, -- 2
a.AdTitle, -- 3
a.ClassAdCatID, -- 4
b.ClassAdCat, -- 5
a.Img1, -- 6
a.AdText, -- 7
a.MemberID, -- 9
a.Viewed, -- 10
c.Domain, -- 11
a.CreateDate -- 12
FROM ClassAd a
INNER JOIN ClassAdCat b ON b.ClassAdCAtID = a.ClassAdCAtID
INNER JOIN Region c ON c.RegionID = a.RegionID
AND a.PostType = 'CPN'
AND DATEDIFF(d, GETDATE(), ExpirationDate) >= 0
AND a.RegionID IN (#RegionID)
AND Viewable = 'Y'
This fails with the following error:
Error converting data type varchar to bigint.
RegionID In the database is a bigint field.. need to convert the varchar to bigint.. any ideas..?
Many thanks in advance,
neojakey
create this function:
CREATE function [dbo].[f_split]
(
#param nvarchar(max),
#delimiter char(1)
)
returns #t table (val nvarchar(max), seq int)
as
begin
set #param += #delimiter
;with a as
(
select cast(1 as bigint) f, charindex(#delimiter, #param) t, 1 seq
union all
select t + 1, charindex(#delimiter, #param, t + 1), seq + 1
from a
where charindex(#delimiter, #param, t + 1) > 0
)
insert #t
select substring(#param, f, t - f), seq from a
option (maxrecursion 0)
return
end
change this part:
AND a.RegionID IN (select val from dbo.f_split(#regionID, ','))
Change this for better overall performance:
AND DATEDIFF(d, 0, GETDATE()) <= ExpirationDate
Your query does not know that those are separate values, you can use dynamic sql for this:
DECLARE #RegionID varchar(200) = null
SET #RegionID = '853,834,16,467,841,460,495,44,859,457,437,836,864,434,86,838,458,472,832,433,142,154,159,839,831,469,442,275,840,299,446,220,300,225,227,447,301,450,230,837,441,835,302,477,855,411,395,279,303'
declare #sql nvarchar(Max)
set #sql = 'SELECT a.ClassAdID, -- 1
a.AdURL, -- 2
a.AdTitle, -- 3
a.ClassAdCatID, -- 4
b.ClassAdCat, -- 5
a.Img1, -- 6
a.AdText, -- 7
a.MemberID, -- 9
a.Viewed, -- 10
c.Domain, -- 11
a.CreateDate -- 12
FROM ClassAd a
INNER JOIN ClassAdCat b ON b.ClassAdCAtID = a.ClassAdCAtID
INNER JOIN Region c ON c.RegionID = a.RegionID
AND a.PostType = ''CPN''
AND DATEDIFF(d, GETDATE(), ExpirationDate) >= 0
AND a.RegionID IN ('+#RegionID+')
AND Viewable = ''Y'''
exec sp_executesql #sql
I use this apporach sometimes and find it very good.
It transfors your comma-separated string into an AUX table (called #ARRAY) and then query the main table based on the AUX table:
declare #RegionID varchar(50)
SET #RegionID = '853,834,16,467,841,460,495,44,859,457,437,836,864,434,86,838,458,472,832,433,142,154,159,839,831,469,442,275,840,299,446,220,300,225,227,447,301,450,230,837,441,835,302,477,855,411,395,279,303'
declare #S varchar(20)
if LEN(#RegionID) > 0 SET #RegionID = #RegionID + ','
CREATE TABLE #ARRAY(region_ID VARCHAR(20))
WHILE LEN(#RegionID) > 0 BEGIN
SELECT #S = LTRIM(SUBSTRING(#RegionID, 1, CHARINDEX(',', #RegionID) - 1))
INSERT INTO #ARRAY (region_ID) VALUES (#S)
SELECT #RegionID = SUBSTRING(#RegionID, CHARINDEX(',', #RegionID) + 1, LEN(#RegionID))
END
select * from your_table
where regionID IN (select region_ID from #ARRAY)
It avoids you from ahving to concatenate the query string and then use EXEC to execute it, which I dont think it is a very good approach.
if you need to run the code twice you will need to drop the temp table
I think the answer should be kept simple.
Try using CHARINDEX like this:
DECLARE #RegionID VARCHAR(200) = NULL
SET #RegionID =
'853,834,16,467,841,460,495,44,859,457,437,836,864,434,86,838,458,472,832,433,142,154,159,839,831,469,442,275,840,299,446,220,300,225,227,447,301,450,230,837,441,835,302,477,855,411,395,279,303'
SELECT 1
WHERE Charindex('834', #RegionID) > 0
SELECT 1
WHERE Charindex('999', #RegionID) > 0
When CHARINDEX finds the value in the large string variable, it will return it's position, otherwise it return 0.
Use this as a search tool.
The easiest way to change this query is to replace the IN function with a string function. Here is what I consider the safest approach using LIKE (which is portable among databases):
AND ','+#RegionID+',' like '%,'+cast(a.RegionID as varchar(255))+',%'
Or CHARINDEX:
AND charindex(','+cast(a.RegionID as varchar(255))+',', ','+#RegionID+',') > 0
However, if you are explicitly putting the list in your code, why not use a temporary table?
declare #RegionIds table (RegionId int);
insert into #RegionIds
select 853 union all
select 834 union all
. . .
select 303
Then you can use the table in the IN clause:
AND a.RegionId in (select RegionId from #RegionIds)
or in a JOIN clause.
I like Diego's answer some, but I think my modification is a little better because you are declaring a table variable and not creating an actual table. I know the "in" statement can be a little slow, so I did an inner join since I needed some info from the Company table anyway.
declare #companyIdList varchar(1000)
set #companyIdList = '1,2,3'
if LEN(#companyIdList) > 0 SET #companyIdList = #companyIdList + ','
declare #CompanyIds TABLE (CompanyId bigint)
declare #S varchar(20)
WHILE LEN(#companyIdList) > 0 BEGIN
SELECT #S = LTRIM(SUBSTRING(#companyIdList, 1, CHARINDEX(',', #companyIdList) - 1))
INSERT INTO #CompanyIds (CompanyId) VALUES (#S)
SELECT #companyIdList = SUBSTRING(#companyIdList, CHARINDEX(',', #companyIdList) + 1, LEN(#companyIdList))
END
select d.Id, d.Name, c.Id, c.Name
from [Division] d
inner join [Company] c on d.CompanyId = c.Id
inner join #CompanyIds cids on c.Id = cids.CompanyId

SQL Server - Compare Varchar values using IN

In my table, I have a varchar column whereby multi-values are stored. An example of my table:
RecNum | Title | Category
-----------------------------------------
wja-2012-000001 | abcdef | 4,6
wja-2012-000002 | qwerty | 1,3,7
wja-2012-000003 | asdffg |
wja-2012-000004 | zxcvbb | 2,7
wja-2012-000005 | ploiuh | 3,4,12
The values in the Category column points to another table.
How can I return the relevant rows if I want to retrieve the rows with value 1,3,5,6,8 in the Category column?
When I tried using IN, I get the 'Conversion failed when converting the varchar value '1,3,5,6,8' to data type int' error.
Breaking the Categories out into a separate table would be a better design if that's a change you can make... otherwise, you could create a function to split the values into a table of integers like this:
CREATE FUNCTION dbo.Split(#String varchar(8000), #Delimiter char(1))
returns #temptable TABLE (id int)
as
begin
declare #idx int
declare #slice varchar(8000)
select #idx = 1
if len(#String)<1 or #String is null return
while #idx!= 0
begin
set #idx = charindex(#Delimiter,#String)
if #idx!=0
set #slice = left(#String,#idx - 1)
else
set #slice = #String
if(len(#slice)>0)
insert into #temptable(id) values(convert(int, #slice))
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
return
end
Then call it from your query:
SELECT ...
FROM ...
WHERE #SomeID IN (SELECT id FROM dbo.Split(Category, ','))
Or if you're looking to provide a list of categories as an input parameter (such as '1,3,5,6,8'), and return all records in your table that contain at least one of these values, you could use a query like this:
SELECT ...
FROM ...
WHERE
EXISTS (
select 1
from dbo.Split(Category, ',') s1
join dbo.Split(#SearchValues, ',') s2 ON s1.id = s2.id
)
you can do like this
declare #var varchar(30); set #var='2,3';
exec('select * from category where Category_Id in ('+#var+')')
Try this solution:
CREATE TABLE test4(RecNum varchar(20),Title varchar(10),Category varchar(15))
INSERT INTO test4
VALUES('wja-2012-000001','abcdef','4,6'),
('wja-2012-000002','qwerty','1,3,7'),
('wja-2012-000003','asdffg',null),
('wja-2012-000004','zxcvbb','2,7'),
('wja-2012-000005','ploiuh','3,4,12')
select * from test4
Declare #str varchar(25) = '1,3,5,6,8'
;WITH CTE as (select RecNum,Title,Category from test4)
,CTE1 as (
select RecNum,Title,RIGHT(#str,LEN(#str)-CHARINDEX(',',#str,1)) as rem from CTE where category like '%'+LEFT(#str,1)+'%'
union all
select c.RecNum,c.Title,RIGHT(c1.rem,LEN(c1.rem)-CHARINDEX(',',c1.rem,1)) as rem from CTE1 c1 inner join CTE c
on c.category like '%'+LEFT(c1.rem,1)+'%' and CHARINDEX(',',c1.rem,1)>0
)
select RecNum,Title from CTE1
As mentioned by others, your table design violates basic database design principles and if there is no way around it, you could normalize the table with little code (example below) and then join away with the other table. Here you go:
Data:
CREATE TABLE data(RecNum varchar(20),Title varchar(10),Category varchar(15))
INSERT INTO data
VALUES('wja-2012-000001','abcdef','4,6'),
('wja-2012-000002','qwerty','1,3,7'),
('wja-2012-000003','asdffg',null),
('wja-2012-000004','zxcvbb','2,7'),
('wja-2012-000005','ploiuh','3,4,12')
This function takes a comma separated string and returns a table:
CREATE FUNCTION listToTable (#list nvarchar(MAX))
RETURNS #tbl TABLE (number int NOT NULL) AS
BEGIN
DECLARE #pos int,
#nextpos int,
#valuelen int
SELECT #pos = 0, #nextpos = 1
WHILE #nextpos > 0
BEGIN
SELECT #nextpos = charindex(',', #list, #pos + 1)
SELECT #valuelen = CASE WHEN #nextpos > 0
THEN #nextpos
ELSE len(#list) + 1
END - #pos - 1
INSERT #tbl (number)
VALUES (convert(int, substring(#list, #pos + 1, #valuelen)))
SELECT #pos = #nextpos
END
RETURN
END
Then, you can do something like this to "normalize" the table:
SELECT *
FROM data m
CROSS APPLY listToTable(m.Category) AS t
where Category is not null
And then use the result of the above query to join with the "other" table. For example (i did not test this query):
select * from otherTable a
join listToTable('1,3,5,6,8') b
on a.Category = b.number
join(
SELECT *
FROM data m
CROSS APPLY listToTable(m.Category) AS t
where Category is not null
) c
on a.category = c.number