show one column in multiple rows - sql

I’ve been looking for a way to show one column in multiple rows, one cell. The content of it separated by comma’s.
For example, in stead of:
ProjectID Label
———— ——–
1200 label1
1200 label2
1200 label3
I would like the result of my query to look like this:
ProjectID Label
———— ——–
1200 label1, label2, label3
thanks in advance

There are different ways to do this. One option is to create a table valued function that 'splits' your multiple valued cell on different records. Here is an example of an split function:
ALTER FUNCTION [dbo].[Split](#RowData VARCHAR(MAX), #SplitOn VARCHAR(5))
RETURNS #RtnValue TABLE
(
Id int identity(1,1),
Data VARCHAR(MAX)
)
AS
BEGIN
Declare #Cnt int
Set #Cnt = 1
While (Charindex(#SplitOn,#RowData)>0)
Begin
Insert Into #RtnValue (data)
Select
Data = ltrim(rtrim(Substring(#RowData,1,Charindex(#SplitOn,#RowData)-1)))
Set #RowData = Substring(#RowData,Charindex(#SplitOn,#RowData)+1,len(#RowData))
Set #Cnt = #Cnt + 1
End
Insert Into #RtnValue (data)
Select Data = ltrim(rtrim(#RowData))
Return
END
Once created, you can do the following to obtain your results:
SELECT *
FROM YourTable A
CROSS APPLY dbo.Split(Label,', ') B

Here, I have made Table Valued Function which splits the string and return the result as your desired
--Create the function
CREATE FUNCTION dbo.Split(#ProjectId nvarchar(50),#String varchar(8000), #Delimiter char(1)) --Pass projectID,label and delimiter and returns table
returns #temptable TABLE (id nvarchar(50),items varchar(8000))
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,Items) values(#ProjectId,#slice)
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
return
end
--Calling the function
select * from dbo.split('1200',' label1, label2, label3',',') --calling teh function

create table #comma_seprate
(ProductID int,
Lable varchar(max))
declare #index int, #id int;
declare #lable varchar(max);
declare cur_comma cursor
for select ProductID, Lable from comma_seprate
open cur_comma
fetch next from cur_comma into #id, #lable
while (##fetch_status=0)
begin
set #index=charindex(',',#lable);
while(#index>0)
begin
insert into #comma_seprate values (#id,rtrim(ltrim(left(#lable,#index-1))));
set #lable=substring(#lable,#index+1,len(#lable));
set #index=charindex(',',#lable);
end
insert into #comma_seprate values (#id, rtrim(ltrim(#lable)));
fetch next from cur_comma into #id,#lable;
end
close cur_comma;
deallocate cur_comma;
select * from #comma_seprate;
truncate table #comma_seprate;

Use SQL Server table function with split function which returns a table

Related

I need help for a specific sql task

I have been given the following task: I have to write a stored procedure with two parameters: #Court int, #ReportId NVARCHAR(400) and i have to split the #ReportId parameter by space, convert each piece (of #ReportId) into int and use both this piece and the #Court parameter to perform an insert operation like this:
insert into RPT_Report2court (Reportid, courtnumber)
values (#ReportId, #Court)
for each piece (converted to int) of #ReportId parameter.
So far i have done the following:
SELECT CAST(value AS int)
FROM STRING_SPLIT(#ReportId, ' ')
but i really don't know how to iterate over these int values and take them to use them for the insert statements. (If the language is C# and not SQL i would put these int values in a list of ints and simply iterate over that list with foreach, but i don't know how to do that using sql).
I think this is what you want:
insert into RPT_Report2court (Reportid, courtnumber)
select cast(value AS int) , #Court
from string_split(#ReportId, ' ');
Create UserDefined function Split.
CREATE FUNCTION [dbo].[Split](#String varchar(8000), #Delimiter char(1))
returns #temptable TABLE (SplitValue varchar(8000))
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(SplitValue) values(#slice)
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
return
end
insert into RPT_Report2court (Reportid, courtnumber)
select * ,#Court FROM dbo.Split(ReportId,' ')
Let me know if you have any query .
Thanks .

SSRS Report: get parameter data value and store it into variable in dataset

I have multi-valued parameter in my Report named #Animal which has ('Cat', 'Dog', 'Mouse').
inside dataset i need to get 'Cat', Dog', 'Mouse' and store it into #AnimalName table variable.
"Hard-Coded" way would be:
DECLARE #AnimalName TABLE (Name nvarchar (10))
INSERT INTO #AnimalName SELECT ('Cat');
INSERT INTO #AnimalName SELECT ('Dog');
INSERT INTO #AnimalName SELECT ('Mouse');
I know that I can use #Animal directly inside my dataset, the reason I'm doing this is because I'm trying to improve my report's performance. Many multi-valued parameters will make the report runs forever.
Does any one know how(the syntax) to get #Animal data values and stored it into a table variables #AnimalName inside dataset?
Thanks heaps!
Pass the comma delimited string into your stored procedure and in your stored proc use a table valued function to convert you multi-valued parameter into a table.
CREATE PROC GetAllAnimals
#AnimalList nvarchar(max)
AS
DECLARE #Animals TABLE (Animal nvarchar(10))
INSERT INTO #Animals SELECT * FROM dbo.fnGetValueListFromMultiSelect(#AnimalList)
and then use the #Animals table to inner join in your query
Functions declared below.
For Integer (or ID) values
CREATE FUNCTION [dbo].[fnGetIdListFromMultiSelect](#String nvarchar(MAX))
RETURNS #Results TABLE ([Id] int)
AS
BEGIN
DECLARE #Delimiter CHAR(1)
DECLARE #INDEX INT
DECLARE #SLICE nvarchar(4000)
IF #String IS NULL RETURN
SET #Delimiter = ','
SET #INDEX = 1
WHILE #INDEX !=0
BEGIN
-- GET THE INDEX OF THE FIRST OCCURENCE OF THE SPLIT CHARACTER
SELECT #INDEX = CHARINDEX(#Delimiter,#STRING)
-- NOW PUSH EVERYTHING TO THE LEFT OF IT INTO THE SLICE VARIABLE
IF #INDEX !=0
BEGIN
SELECT #SLICE = LEFT(#STRING,#INDEX - 1)
-- CHOP THE ITEM REMOVED OFF THE MAIN STRING
SELECT #STRING = RIGHT(#STRING,LEN(#STRING) - #INDEX)
END
ELSE
SELECT #SLICE = #STRING
-- PUT THE ITEM INTO THE RESULTS SET
INSERT INTO #Results([Id]) VALUES(CAST(#SLICE AS INT))
-- BREAK OUT IF WE ARE DONE
IF LEN(#STRING) = 0 BREAK
END
RETURN
END
For string values
CREATE FUNCTION [dbo].[fnGetValueListFromMultiSelect](#String nvarchar(MAX))
RETURNS #Results TABLE ([Item] nvarchar(128) Primary Key)
AS
BEGIN
DECLARE #Delimiter CHAR(1)
DECLARE #INDEX INT
DECLARE #SLICE nvarchar(4000)
SET #Delimiter = ','
SET #INDEX = 1
WHILE #INDEX !=0
BEGIN
-- GET THE INDEX OF THE FIRST OCCURENCE OF THE SPLIT CHARACTER
SELECT #INDEX = CHARINDEX(#Delimiter,#STRING)
-- NOW PUSH EVERYTHING TO THE LEFT OF IT INTO THE SLICE VARIABLE
IF #INDEX !=0
BEGIN
SELECT #SLICE = LEFT(#STRING,#INDEX - 1)
-- CHOP THE ITEM REMOVED OFF THE MAIN STRING
SELECT #STRING = RIGHT(#STRING,LEN(#STRING) - #INDEX)
END
ELSE
SELECT #SLICE = #STRING
-- PUT THE ITEM INTO THE RESULTS SET
INSERT INTO #Results([Item]) VALUES(#SLICE)
-- BREAK OUT IF WE ARE DONE
IF LEN(#STRING) = 0 BREAK
END
RETURN
END

Getting id values from a column and then get value from another table

I have a column value separated by comma as
GoalTag:All Tags,TaskTag:All Tags,GoalId:All,TaskId:All,MaxGoal:5,MaxTask:5
As you can see I have 6 values separated by comma, so when I do split the first value will be
GoalTag:All Tags
How I do this (get the values seperated by comma is) by calling a table valued function
Select * from dbo.CustomSplit((SELECT FilterNames FROM TblUserFilterView where UserId = 325 AND Entity = 'Dashboard'),',')
The definition for dbo.CustomSplit looks like
ALTER FUNCTION [dbo].[CustomSplit](#String varchar(8000), #Delimiter char(1))
returns #temptable TABLE (Items varchar(8000))
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(Items) values(#slice)
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
return
end
Now what I need to do is, I need to get the value after the ":" i.e. "All Tags" it may be some id for some other records let's say it may be "142". I need to get this Id and then get the corresponding value from the table.
How can I do this?
Try this:
SELECT Substring(s.items, 1 + Charindex ( ':', s.items),
Len(s.items) - Charindex (':',
s.items))
FROM (SELECT *
FROM dbo.Customsplit((SELECT filternames
FROM tbluserfilterview
WHERE userid = 325
AND entity = 'Dashboard'), ',')) AS s
You may create another function:
CREATE FUNCTION [dbo].[Customsplit2](#string VARCHAR(8000),
#Delimiter CHAR(1))
returns VARCHAR(4000)
AS
BEGIN
DECLARE #result NVARCHAR(4000)
SELECT #result = Substring(#string, 1 + Charindex ( #Delimiter, #string),
Len(#string) - Charindex (#Delimiter,
#string)
)
RETURN #result
END
And use it like:
SELECT [dbo].Customsplit2(s.items, ':') AS Tag
FROM (SELECT *
FROM dbo.Customsplit((SELECT filternames
FROM tbluserfilterview
WHERE userid = 325
AND entity = 'Dashboard'), ',')) AS s

Insert values into table after splitting the string

I want to insert values into employee table.
And those values are in string format ~ separated
E.g: AA~B~123
I am splitting it using following function
CREATE FUNCTION [db_owner].[FN_Split] (#String varchar(8000), #Delimiter char(1))
returns #temptable TABLE (items varchar(8000))
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(Items) values(#slice)
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
return
end
Now I get Output as
SELECT * FROM db_owner.FN_Split('AA~B~123','~')
Output
items
______
AA
B
123
Now I am stuck here
How can I insert above values in employee table???
like
insert into employee (name,add,phone)
values('AA','B','123');
Please guide.
Tried this but not working
insert into employee
SELECT * FROM db_owner.FN_Split('AA~BB~CC','~')
ERROR
Msg 213, Level 16, State 1, Line 1
Column name or number of supplied values does not match table definition.
You are using a string split function that returns your items as rows. You need a function that return them as columns instead.
Or you can do it directly in the query. Perhaps something like this.
declare #S varchar(10) = 'AA~B~123'
select left(#S, T1.Pos - 1) as Col1,
substring(#S, T1.Pos+1, T2.Pos-T1.Pos-1) as Col2,
substring(#S, T2.Pos+1, len(#S)-T2.Pos) as Col3
from (select charindex('~', #S)) as T1(Pos)
cross apply (select charindex('~', #S, T1.Pos+1)) as T2(Pos)
Result:
Col1 Col2 Col3
---------- ---------- ----------
AA B 123
Here is a version that works in SQL Server 2000
declare #S varchar(10)
set #S = 'AA~B~123'
select left(#S, T.Pos1 - 1) as Col1,
substring(#S, T.Pos1+1, T.Pos2-T.Pos1-1) as Col2,
substring(#S, T.Pos2+1, len(#S)-T.Pos2) as Col3
from (select T.Pos1,
charindex('~', #S, T.Pos1+1) as Pos2
from (select charindex('~', #S) as Pos1) as T
) as T
if you could add a small counter into the stored procedure like this then life would be easier:
CREATE FUNCTION [db_owner].[FN_Split] (#String varchar(8000), #Delimiter char(1))
returns #temptable TABLE (orderId int,items varchar(8000))
as
begin
declare #idx int
declare #slice varchar(8000)
declare #orderId int = 0 --<added a counter
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(orderId, Items) values(#orderId, #slice)
set #orderId = #orderId+1 --<increment the counter
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
return
end
Your subsequent query could be something like the following:
DECLARE #name varchar(50) = (SELECT items FROM db_owner.FN_Split('AA~BB~CC','~') where orderId = 0)
DECLARE #add varchar(50) = (SELECT items FROM db_owner.FN_Split('AA~BB~CC','~') where orderId = 1)
DECLARE #phone varchar(50) = (SELECT items FROM db_owner.FN_Split('AA~BB~CC','~') where orderId = 2)
insert into employee
(
name,
add,
phone
)
values
(
#name,
#add,
#phone
)
But have you tried changing the procedure so that it outputs the data in a horizontal format rather than the vertical output that you currently have?
Please try this query:
Insert into employee(col1,col2,col3)
select substring_index('AA~B~123','~',1) as col1,substring_index(substring_index('AA~B~123','~',-2),'~',1) as col2,
substring_index(substring_index('AA~B~123','~',-1),'~',1) as col3

How to use IN Operator in SQL Server

How to use IN Operator in SQL Server
Here Is the table Structure
Create Table Sample(Id INT,Name Varchar(50))
While I am the Query like this I can get the Value
Select * FROM Sample WHERE Id IN ('74','77','79','80')
While I am executing the above Query I can't able to get the Records Related to that table getting error executing this error.
DECLARE #s VARCHAR(MAX)
SET #s='74','77','79','80'
Select * FROM Sample WHERE Id IN (#s)
You are using wrong way
use the following way
DECLARE #s VARCHAR(MAX)
DECLARE #d VARCHAR(MAX)
SET #s='74 , 77 , 79 , 80'
set #d = 'select * from arinvoice where arinvoiceid in('+#s+')'
exec (#d)
here IN operator use integers collection not string collection..
you should use a function which gives back a result set ( takes a csv format and returns a table)
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[Splitt] (#String NVARCHAR(4000),
#Delimiter CHAR(1))
RETURNS #Results TABLE (
Items NVARCHAR(4000))
AS
BEGIN
DECLARE #Index INT
DECLARE #Slice NVARCHAR(4000)
SELECT #Index = 1
IF #String IS NULL
RETURN
WHILE #Index != 0
BEGIN
SELECT #Index = Charindex(#Delimiter, #String)
IF #Index <> 0
SELECT #Slice = LEFT(#String, #Index - 1)
ELSE
SELECT #Slice = #String
IF ( NOT EXISTS (SELECT *
FROM #Results
WHERE items = #Slice) )
INSERT INTO #Results
(Items)
VALUES (#Slice)
SELECT #String = RIGHT(#String, Len(#String) - #Index)
IF Len(#String) = 0
BREAK
END
RETURN
END
and now you can write :
DECLARE #s VARCHAR(MAX)
SET #s='74,77,79,80'
Select * FROM Sample WHERE Id IN (select items from dbo.Splitt(#s,','))
If you are using ADO.NET, you can avoid the magic string, just use SqlDataRecord.
Or if you are using SQL Server 2008, you can also avoid the magic string by using Table-Valued Parameter
Source: http://www.sommarskog.se/arrays-in-sql-2008.html