I have two strings:
DECLARE #str1 varchar(max) = '[First Name],[Last Name],[Middle Name]'
DECLARE #str2 varchar(max) = '[First Name],[Pin Code],[Address],[Last Name]'
Want to concatenate two strings into one without duplicates.
Expected Output:
str3
-------------------------------------------------------------
[First Name],[Last Name],[Middle Name],[Pin Code],[Address]
You can use STRING_SPLIT() function and DISTINCT as
DECLARE #str1 varchar(max) = '[First Name],[Last Name],[Middle Name]';
DECLARE #str2 varchar(max) = '[First Name],[Pin Code],[Address],[Last Name]';
SELECT DISTINCT *
FROM STRING_SPLIT(#Str1 +','+ #Str2, ',');
Or
DECLARE #str1 varchar(max) = '[First Name],[Last Name],[Middle Name]';
DECLARE #str2 varchar(max) = '[First Name],[Pin Code],[Address],[Last Name]';
SELECT DISTINCT *
FROM STRING_SPLIT(CONCAT(#Str1, ',', #Str2), ',');
to get it as one row
declare #result varchar(max) = '';
SELECT #result = #result + value
FROM STRING_SPLIT(CONCAT(#Str1, ',', #Str2), ',')
group by value;
SELECT #result;
Demo
and since you are working on SQL Server 2008 you need to create your own function such this one here.
Related
How can I store the result of exec in a variable? The output is JSON.
My SQL query is complex and dynamically generated, so I have to set a variable and execute it.
create PROCEDURE dbo.RetrievePerfCounterData #jsonOutput NVARCHAR(MAX) OUTPUT
AS
BEGIN
declare #sql NVARCHAR(MAX)
SET #sql = ' SELECT TOP (1) getdate() AS ''dateTime'' ,suser_sname()AS ''user'' FOR JSON PATH '
exec (#sql)
END
Here's my attempt at storing the data in a variable:
DECLARE #json AS NVARCHAR(MAX)
EXEC dbo.RetrievePerfCounterData #jsonOutput = #json OUTPUT
DECLARE #myVar VARCHAR(MAX)
DECLARE #SQL NVARCHAR(MAX)
IF OBJECT_ID('tempdb..#t1') IS NOT NULL DROP TABLE #t1
CREATE TABLE #t1 (col1 INT, col2 INT)
INSERT INTO #t1
SELECT 1, 1
UNION
SELECT 1, 2
SET #SQL = 'SET #myVar = (SELECT * FROM #t1 AS T FOR JSON AUTO);'
EXEC sp_executesql #SQL, N'#myVar VARCHAR(MAX) OUT', #myVar OUT
SELECT #myVar
You need to use a subquery:
SET #json = (SELECT TOP (1) getdate() AS [dateTime],suser_sname()AS [user] FOR JSON PATH);
If I have a value something like '10,10,20,30,40,20' in a field of table, then I want to make it as '10,20,30,40'
Is there any sql function to do such thing?
Thanks
Sudhakar
using Jeff's DelimitedSplit8K from http://www.sqlservercentral.com/articles/Tally+Table/72993/
declare #value varchar(100) = '10,10,20,30,40,20',
#new_value varchar(100)
select #new_value = isnull(#new_value + ',', '') + Item
from DelimitedSplit8K(#value, ',')
group by Item
order by Item
select #new_value
Did this long ago. This might need some modifications. But it generates output.
Try :
DECLARE #Data_String AS VARCHAR(1000), #Result as varchar(1000)=''
SET #Data_String = '10,10,20,30,40,20'
SET #Data_String = REPLACE(#Data_String,'|',',')
select #Data_String;
SELECT #Result=#Result+col+',' from(
SELECT DISTINCT t.c.value('.','varchar(100)') col from(
SELECT cast('<A>'+replace(#Data_String,',','</A><A>')+'</A>' as xml)col1)data
cross apply col1.nodes('/A') as t(c))Data
SELECT LEFT(#Result,LEN(#Result)-1)
believing it stores integer number you can get them with creating a function first you need to split the values then have to use a distinct function as below
1st create a function like
CREATE FUNCTION [dbo].[idpGetSplitedString]
(
#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(rtrim(ltrim(#slice)))
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
RETURN
END
then call the function like
select [dbo].idpGetSplitedString as Values
I have this query:
DECLARE #holdIds VARCHAR(MAX)
SET #holdIds = '1,2,3'
DECLARE #flagNames NVARCHAR(MAX);
SELECT
#flagNames = COALESCE(#flagNames + ',', '') + FlagName
FROM
BurnHoldStatus
WHERE
BurnHoldStatusID in (#holdIds);
SELECT #flagNames AS FlagName;
In this example the variable '#holdIds' has values '1,2,3' but could have just one value '1'.
When I run the query, an error appears:
Msg 245, Level 16, State 1, Line 6
Conversion failed when converting the varchar value '1,2,3' to data type int.
I try convert the value of '#holdIds' but not work.
Any idea?
Thanks.
[UPDATE]
I found the answer:
DECLARE #holdIds NVARCHAR(MAX);
SET #holdIds = '1,2,3';
DECLARE #holdIdList TABLE(id INT);
INSERT INTO #holdIdList
SELECT * FROM Split(#holdIds, ',');
DECLARE #flagNames NVARCHAR(MAX);
SELECT
#flagNames = COALESCE(#flagNames + ',', '') + FlagName
FROM
BurnHoldStatus, #holdIdList h
WHERE
BurnHoldStatusID = h.id;
SELECT #flagNames AS FlagName;
In this code I use an function 'Split' to split a string passing the divisor (i.e: ',').
Split function code:
ALTER FUNCTION [dbo].[Split]
(
#RowData nvarchar(MAX),
#SplitOn nvarchar(MAX)
)
RETURNS #RtnValue table
(
Data nvarchar(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
Thanks for Vercelli by show other post.
Thanks guys :)
The comment made by swe is correct. You could make the query dynamic, then insert #holdIds See below for a workaround:
DECLARE #holdIds VARCHAR(MAX)
SET #holdIds = '1,2,3'
SET #holdIds = (CHAR(39) + (REPLACE(#holdIds, ',', ''',''') + CHAR(39)))
You can do this, then set the entire query above as a varchar variable, then execute. There are certainly other workarounds as well but dynamic SQL will work.
I have the following three different strings which needs to split into three different columns.
Example:
String 1:
Declare #str1 varchar(max) = 'A1,A2,A3'
String 2:
Declare #str2 varchar(max) = 'B1,B2,B3'
String 3:
Declare #str2 varchar(max) = 'C1,C2,C3'
NoteI want to store the above three strings into three different columns.
Expected Output:
colA colB colC
------------------
A1 B1 C1
A2 B2 C2
A3 B3 C3
Attempt:
SQL Fiddle: http://sqlfiddle.com/#!3/d41d8/41345
I know its a bit heavy but it will work
Declare #str1 varchar(max) = 'A1,A2,A3'
Declare #str2 varchar(max) = 'B1,B2,B3'
Declare #str3 varchar(max) = 'C1,C2,C3'
DECLARE #RowCount TINYINT
DECLARE #i TINYINT = 0
DECLARE #Table AS TABLE
(
colA varchar(MAX)
,ColB varchar(MAX)
,ColC varchar(MAX)
)
SET #RowCount = len(#str1) - len(replace(#str1, ',', ''))
WHILE(#i<=#RowCount)
BEGIN
INSERT INTO #Table
SELECT LEFT(#str1,CHARINDEX(',',#str1+',',0)-1) AS colA
,LEFT(#str2,CHARINDEX(',',#str2+',',0)-1) AS colB
,LEFT(#str3,CHARINDEX(',',#str3+',',0)-1) AS colC
SET #str1 = STUFF(#str1,1,CHARINDEX(',',#str1,0),'')
SET #str2 = STUFF(#str2,1,CHARINDEX(',',#str2,0),'')
SET #str3 = STUFF(#str3,1,CHARINDEX(',',#str3,0),'')
SET #i = #i + 1
END
SELECT * FROM #Table
If you have atmost three values then try this.
DECLARE #str1 VARCHAR(max) = 'A1,A2,A3'
SELECT Parsename(Replace(#str1, ',', '.'), 3) 'FST_COL',
Parsename(Replace(#str1, ',', '.'), 2) 'SCD_COL',
Parsename(Replace(#str1, ',', '.'), 1) 'TRD_COL' into #temp
Or
DECLARE #str1 VARCHAR(max) = 'A1,A2,A3',
#sql NVARCHAR(max),
#loop INT,
#cnt INT=1
SELECT #loop = Len(#str1) - Len(Replace(#str1, ',', '')) + 1
SET #sql=' WITH Split_cols ( xmlcol)
AS (SELECT CONVERT(XML, ''<cols><col>''
+ Replace('''
+ #str1 + ''', '','', ''</col><col>'') + ''</col></cols>'') as xmlcol)
SELECT '
WHILE #cnt <= #loop
BEGIN
SET #sql+=' xmlcol.value(''/cols[1]/col['
+ CONVERT(VARCHAR(30), #cnt)
+ ']'', ''varchar(100)'') AS col'
+ CONVERT(VARCHAR(30), #cnt) + ','
SET #cnt=#cnt + 1
END
SET #sql=LEFT(#sql, Len(#sql) - 1)
SET #sql +=' FROM Split_cols '
--PRINT #sql
EXEC Sp_executesql #sql
THIS WILL WORK WITH ANY NUMBER OF STRINGS AND VALUES NOT HARDCODED
CREATE FUNCTION dbo.splitstring (#stringToSplit VARCHAR(MAX) )
RETURNS
#returnList TABLE ([ID] INT IDENTITY(1,1),[Name] [nvarchar] (500))
AS
BEGIN
DECLARE #name NVARCHAR(255)
DECLARE #pos INT
WHILE CHARINDEX(',', #stringToSplit) > 0
BEGIN
SELECT #pos = CHARINDEX(',', #stringToSplit)
SELECT #name = SUBSTRING(#stringToSplit, 1, #pos-1)
INSERT INTO #returnList
SELECT #name
SELECT #stringToSplit = SUBSTRING(#stringToSplit, #pos+1, LEN(#stringToSplit)-#pos)
END
INSERT INTO #returnList
SELECT #stringToSplit
RETURN
END
-- USE THIS PARAMETER TO PASS VALUE
DECLARE #STRING VARCHAR(MAX)
DECLARE #COUNT INT
DECLARE #I INT
DECLARE #COLUMNNAME VARCHAR(MAX)
DECLARE #CREATETABLE VARCHAR(MAX)
DECLARE #INSERT VARCHAR(MAX)
IF OBJECT_ID('TEMPDB..##TEMPTABLE') IS NOT NULL
DROP TABLE ##TEMPTABLE
IF OBJECT_ID('TEMPDB..##RETURNLIST') IS NOT NULL
DROP TABLE ##RETURNLIST
SELECT * INTO ##RETURNLIST FROM dbo.splitstring(#STRING)
select #COUNT = COUNT(*) from ##RETURNLIST
SET #I=0
SET #CREATETABLE = 'CREATE TABLE ##TEMPTABLE ('
WHILE (#COUNT>0)
BEGIN
SET #COLUMNNAME = 'COLUMN'+ CONVERT(varchar(10), #I) + ' VARCHAR(MAX)'
SET #CREATETABLE = #CREATETABLE + #COLUMNNAME
IF(#COUNT<>1)
SET #CREATETABLE = #CREATETABLE + ', '
SET #I = #I+1
SET #COUNT = #COUNT -1;
END
SET #CREATETABLE = #CREATETABLE + ' )'
EXECUTE(#CREATETABLE)
SET #INSERT = 'INSERT INTO ##TEMPTABLE VALUES( '
WHILE (#I>0)
BEGIN
SET #INSERT = #INSERT +''''+ (SELECT NAME FROM ##RETURNLIST WHERE ID = #COUNT+1) +''''
IF(#I<>1)
SET #INSERT = #INSERT + ', '
SET #I = #I-1
SET #COUNT = #COUNT +1;
ENDenter code here
SET #INSERT = #INSERT + ' )'
EXECUTE(#INSERT)
EXECUTE('SELECT * FROM ##TEMPTABLE')
You haven't given any criteria for joining the values together for each of the rows of columns so I've just joined them in descending order. This solution can handle any number of items in the lists but if the number gets too high you may need to use the MAX RECURSION query hint.
DECLARE #strA NVARCHAR(MAX) = 'A1,A2,A3';
DECLARE #strB NVARCHAR(MAX) = 'B1,B2,B3,B4';
DECLARE #strC NVARCHAR(MAX) = 'C1,C2,C3';
WITH stringData AS (
--each group of comma separate values with a group identifier
SELECT 'a' AS grp, #strA AS strng
UNION ALL
SELECT 'b' AS grp, #strB
UNION ALL
SELECT 'c' AS grp, #strC
),
splitStrings AS (
--a recursive CTE to split the comma separated values
SELECT grp, CAST('' AS NVARCHAR(MAX)) AS item,
strng AS cText
FROM stringData
UNION ALL
SELECT grp,
CASE
WHEN CHARINDEX(N',',cText,0)>0 THEN LEFT(cText,CHARINDEX(N',',cText,0)-1) --SUBSTRING(cText,0,CHARINDEX(N',',cText,0))
ELSE cText
END,
RIGHT(cText,LEN(cText)-CHARINDEX(N',',cText,0))
FROM splitStrings
WHERE cText!=item
)
SELECT grp,
item,
ROW_NUMBER() OVER(PARTITION BY grp ORDER BY item) AS rnum
INTO #stringValues --put the results in a temp table so we don't need to execute the recursive CTE more than once
FROM splitStrings
WHERE len(item)>0;
DECLARE #maxNum INT = (SELECT MAX(rnum) FROM #stringValues);
--join the values together
WITH allNums AS (
SELECT 1 AS num
UNION ALL
SELECT num+1
FROM allNums
WHERE num<#maxNum
)
SELECT sa.item AS colA,
sb.item AS colB,
sc.item AS colC
FROM allNums
LEFT JOIN #stringValues AS sa ON sa.rnum=allNums.num AND sa.grp='A'
LEFT JOIN #stringValues AS sb ON sb.rnum=allNums.num AND sb.grp='B'
LEFT JOIN #stringValues AS sc ON sc.rnum=allNums.num AND sc.grp='C'
DROP TABLE #stringValues;
I am trying to create a dynamic query in SQL Server.
Input: #value= abc,def,en,
Output: MAX(abc) as abc, MAX(def) as def, MAX(en) as en
My efforts so far took me no where.
With CONVERT() and REPLACE() I achieved a bit but finding it difficult. Need help!
Try this:
declare #value varchar(50) = 'abc,def,en'
declare #result varchar(100) = ''
select #result = replace(#value,'abc', 'MAX(''abc'') as abc')
select #result = replace(#result,'def', 'MAX(''def'') as def')
select #result = replace(#result,'en', 'MAX(''en'') as en')
select #result
You can also do the replacements in one line by nesting the expressions.
EDIT: If you have variable values in #value, you can take the below approach:
Use a splitter function to get the individual values in the string as a list. You can take a look at this article for implementations.
Insert this list to a temp table.
Update the temp table as shown above.
Concatenate the values into a single string using STUFF like so:
select stuff((select ',' + val from #temp for xml path('')),1,1,'')
Try this:
DECLARE #Value VARCHAR(200) = 'abc,def,en'
DECLARE #Template VARCHAR(100) = 'MAX(''##'') as ##'
DECLARE #Result VARCHAR(1000) = ''
DECLARE #Data VARCHAR(100) = ''
WHILE LEN(#Value) > 0
BEGIN
SET #Data = REPLACE(LEFT(#Value, ISNULL(NULLIF(CHARINDEX(',', #Value),0), LEN(#Value))),',','')
SET #Result = #Result + REPLACE(#Template, '##', #Data)
IF CHARINDEX(',', #Value) > 0
BEGIN
SET #Result = #Result + ','
SET #Value = REPLACE(#Value,#Data + ',','')
END
ELSE
SET #Value = REPLACE(#Value,#Data,'')
END
SELECT #Result
Have a look at SQL User Defined Function to Parse a Delimited String
So you can do like
Declare #Value varchar(200) = 'abc,def,en'
Declare #Item varchar(20) = null
declare #Str varchar(1000)=''
WHILE LEN(#Value) > 0
BEGIN
IF PATINDEX('%,%',#Value) > 0
BEGIN
SET #Item = SUBSTRING(#Value, 0, PATINDEX('%,%',#Value))
-- SELECT #Item
IF(LEN(#Str)>0)
SET #Str = #Str + ', SELECT MAX('+#Item+') as ' +#Item
ELSE
SET#Str = #Str + ' SELECT MAX('+#Item+') as ' +#Item
SET #Value = SUBSTRING(#Value, LEN(#Item + ',') + 1, LEN(#Value))
END
ELSE
BEGIN
SET #Item = #Value
SET #Value = NULL
SET #Str = #Str + 'SELECT MAX('+#Item+') as ' + #Item
END
END
select #Str
See the fiddle sample here