What i currently have is:
COUNT DETAILS:
CNT DTLID COUNT TOTAL QTY UNITPRICE AMOUNT
1 234 2222 1.20 32
1 12 123 2 21
What i want it to be like
CNT DTLID COUNT TOTAL QTY UNITPRICE AMOUNT
1 234,12 2222 , 123 1.20,2 32 + 21 = 53
I want to have comma Separated values and also want to use group by clause for amount column.
Currently What I`m upto is:
ALTER PROCEDURE [dbo].[sp_Tbl_CountDetail_SelectAll]
-- Add the parameters for the stored procedure here
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
select * from Tbl_CountDetail
inner join tbl_Contract
on
tbl_CountDetail.ContractID = tbl_Contract.ContractID
inner join tbl_Count
on
tbl_CountDetail.CountID = tbl_Count.CountID
where tbl_CountDetail.isDeleted = 0
and tbl_Contract.isdeleted = 0
END
Some friendly sample data
create table #CountDetails
(
DTLID int,
CNT int,
Qty int,
UnitPrice money,
Amount int
)
insert into #CountDetails
SELECT
1, 234, 2222, 1.20, 32
UNION ALL SELECT
1, 12, 123, 2, 21
Here's some code
SELECT
DTLIDs.DTLID,
CNTs =
ISNULL(
STUFF(
(
select ',' +
cast(CD.cnt as varchar(50))
from #CountDetails CD
where CD.DTLID = DTLIDs.DTLID
order by CD.CNT
FOR XML PATH('')
),
1, 1, '' --removes the leading ','
),
''
),
QTYs =
ISNULL(
STUFF(
(
select ',' +
cast(CD.qty as varchar(50))
from #CountDetails CD
where CD.DTLID = DTLIDs.DTLID
order by CD.Qty
FOR XML PATH('')
),
1, 1, '' --removes the leading ','
),
''
),
UnitPrices =
ISNULL(
STUFF(
(
select ',' +
cast(CD.UnitPrice as varchar(50))
from #CountDetails CD
where CD.DTLID = DTLIDs.DTLID
order by CD.UnitPrice
FOR XML PATH('')
),
1, 1, '' --removes the leading ','
),
''
),
AmountSum =
(
select SUM(Amount) from #CountDetails CD
where CD.DTLID = DTLIDs.DTLID
)
from (
select distinct DTLID from #CountDetails
) DTLIDs
There are various ways to tweak this. For example, the "AmountSum =" nested query code be done on a group by - I just like the more consistent look given the way the rest of the query is structured.
For the CSV lists, you didn't specify how you wanted it sorted. I've ordered by the values (eg ORDER BY CD.CNT) but you can change that to order by whatever you want. Similarly there are no spaces between the CSV values. You can tweak this by changing the select ',' to have a space in there and parameters to the STUFF command (change the second 1 to a 2).
Basically the FOR XML PATH('') bit takes the mini resultset its given and returns some text with no XML literals (due to the ''). This is tidied up using STUFF to remove the leading , at the start of the XML PATH result.
Hope this helps! :)
Can be done something like this....
DECLARE #VALUES NVARCHAR(1000),#UnitPrice nvarchar(100)
SELECT #VALUES = COALESCE(#VALUES + ',','') + CAST(COUNTQty AS NVARCHAR(50)),
#UnitPrice = COALESCE(#UnitPrice + ',','') + CAST(UnitPrice AS NVARCHAR(50)) FROM tableName
SELECT #VALUES as [CountQty],#Ids as [UnitPrice]
Have not checked group by price issue..!!
Related
I need to separate values and store them in different variables in SQL,
for example
a='3100,3101,3102,....'
And the output should be
x=3100
y=3101
z=3102
.
.
.
create function [dbo].[udf_splitstring] (#tokens varchar(max),
#delimiter varchar(5))
returns #split table (
token varchar(200) not null )
as
begin
declare #list xml
select #list = cast('<a>'
+ replace(#tokens, #delimiter, '</a><a>')
+ '</a>' as xml)
insert into #split
(token)
select ltrim(t.value('.', 'varchar(200)')) as data
from #list.nodes('/a') as x(t)
return
end
GO
declare #cad varchar(100)='3100,3101,3102'
select *,ROW_NUMBER() over (order by token ) as rn from udf_splitstring(#cad,',')
token rn
3100 1
3101 2
3102 3
The results of the Parse TVF can easily be incorporated into a JOIN, or an IN
Declare #a varchar(max)='3100,3101,3102'
Select * from [dbo].[udf-Str-Parse](#a,',')
Returns
RetSeq RetVal
1 3100
2 3101
3 3102
The UDF if needed (much faster than recursive, loops, and xml)
CREATE FUNCTION [dbo].[udf-Str-Parse] (#String varchar(max),#Delimiter varchar(25))
Returns Table
As
Return (
with cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (IsNull(DataLength(#String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 a,cte1 b,cte1 c,cte1 d) A ),
cte3(N) As (Select 1 Union All Select t.N+DataLength(#Delimiter) From cte2 t Where Substring(#String,t.N,DataLength(#Delimiter)) = #Delimiter),
cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(#Delimiter,#String,s.N),0)-S.N,8000) From cte3 S)
Select RetSeq = Row_Number() over (Order By A.N)
,RetVal = LTrim(RTrim(Substring(#String, A.N, A.L)))
From cte4 A
);
--Orginal Source http://www.sqlservercentral.com/articles/Tally+Table/72993/
--Much faster than str-Parse, but limited to 8K
--Select * from [dbo].[udf-Str-Parse-8K]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse-8K]('John||Cappelletti||was||here','||')
I suggest you to use following query, it's much faster than other functions like cross apply and udf.
SELECT
Variables
,S_DATA
FROM (
SELECT
Variables
,CASE WHEN LEN(LIST2)>0 THEN LTRIM(RTRIM(SUBSTRING(LIST2, NUMBER+1, CHARINDEX(',', LIST2, NUMBER+1)-NUMBER - 1)))
ELSE NULL
END AS S_DATA
,NUMBER
FROM(
SELECT Variables
,','+COMMA_SEPARETED_COLUMN+',' LIST2
FROM Tb1
)DT
LEFT OUTER JOIN TB N ON (N.NUMBER < LEN(DT.LIST2)) OR (N.NUMBER=1 AND DT.LIST2 IS NULL)
WHERE SUBSTRING(LIST2, NUMBER, 1) = ',' OR LIST2 IS NULL
) DT2
WHERE S_DATA<>''
and also you should create a table 'NUMBER' before running the above query.
CREATE TABLE TB (Number INT)
DECLARE #I INT=0
WHILE #I<1000
BEGIN
INSERT INTO TB VALUES (#I)
SET #I=#I+1
END
How do I get the average from multiple columns?
for example:
Columns: ID 125Hz 250Hz 500Hz 750Hz 1000Hz 1500Hz 2000Hz 3000Hz 4000Hz 6000Hz 8000Hz
Values: 1 92 82 63 83 32 43 54 56 54 34 54
I want to get the average of all the columns except the ID. How do I do that?
You have to manually add the columns since there's no available built-in functions for horizontal aggregation.
select (125Hz+250Hz+500Hz+750Hz+1000Hz+1500Hz+2000Hz+3000Hz+4000Hz+6000Hz+8000Hz)/11 as aveHz from table_name
In SQL-SERVER you can use this
DECLARE #total int
DECLARE #query varchar(550)
DECLARE #ALLColumns VARCHAR(500)
SET #ALLColumns = ''
----Build the string columns
SELECT #ALLColumns = #ALLColumns + '+' + '['+sc.NAME+']'
FROM sys.tables st
INNER JOIN sys.columns sc ON st.object_id = sc.object_id
WHERE st.name LIKE '%YOUR_TABLE_NAME%'
AND sc.NAME LIKE '[0-9]%';--[0-9]% just get the column that start with number
----Get the total number of column,
SELECT #total = count(*) FROM sys.tables st
INNER JOIN sys.columns sc ON st.object_id = sc.object_id
WHERE st.name LIKE '%YOUR_TABLE_NAME%'
AND sc.NAME LIKE '[0-9]%';--[0-9]% just get the column that start with number
SET #query = 'SELECT SUM('+ SUBSTRING(#ALLColumns,2,LEN(#ALLColumns))+')/'
+CAST(#total as varchar(4))+ ' AS [AVG]
FROM [YOUR_TABLE_NAME]
GROUP BY [ID]'
--SELECT #query
EXECUTE(#query)
This will execute a query like this one:
SELECT SUM([125Hz]+[250Hz]+[500Hz]+[750Hz]+[1000Hz]+[1500Hz]+[2000Hz]
+[3000Hz]+[4000Hz]+[6000Hz]+[8000Hz])/11 AS [AVG]
FROM [YOUR_TABLE_NAME] GROUP BY [ID]
UPDATE
Add a column to store the avg, I called it [AVG] and chage the value of #query to
SET #query = '
CREATE TABLE #Medition (ID int,[AVG] decimal(18,4))
INSERT INTO #Medition (ID,[AVG])
SELECT ID,SUM ('+ SUBSTRING(#ALLColumns,2,LEN(#ALLColumns))+')/'
+CAST(#total as varchar(10))
+ ' AS [AVG] FROM Medition GROUP BY ID
UPDATE YOUR_TABLE_NAME SET YOUR_TABLE_NAME.[AVG] = #Medition.[AVG]
FROM YOUR_TABLE_NAME INNER JOIN #Medition ON YOUR_TABLE_NAME.ID =#Medition.ID
DROP TABLE #Medition
'
Note: Build queries string is a little ugly
Another way to do it, without actually using the magic number 11, be it a little more verbose.
WITH t1 AS
(
SELECT * FROM myTable
WHERE (...) -- Should limit result to 1 row
),
t2 AS
(
SELECT col1 FROM t1
UNION ALL
SELECT col2 FROM t1
UNION ALL
(...)
)
SELECT AVG(col1) FROM t2;
this will display Average value of all that fields of each ID you have.
SELECT AVG(125Hz+250Hz+500Hz+750Hz+1000Hz+1500Hz+2000Hz+3000Hz+4000Hz+6000Hz+8000Hz)
AS Average FROM table
GROUP BY ID
SELECT sum(125Hz + 250Hz + 500Hz + 750Hz + 1000Hz + 1500Hz + 2000Hz + 3000Hz +
4000Hz + 6000Hz + 8000Hz)/11 as averageHz from TABLE
I have two tables
test
and test1
test
id formula
1 A12+C32+D+X
2 K/Y
test1
id Code
6 A12
7 C32
100 A1
10 D
12 X
13 K
14 Y
How can I update formula(text formlas) filed in the table test to get
id formula
1 [6]+[7]+[10]+[12]
2 [13]/[14]
Itry the following script sqlfield but it doesn't rerun the correct result . It returns
RFORMULA
[6]+C32+D+X//need to remove it
[13]/Y//need to remove it
[13]/[14]//the best result
[100]2+[7]+[10]+[12]
[13]/Y//need to remove it
K/[14]//need to remove it
[6]+[7]+[10]+[12]//the best result
I am working on it for hours , any idea ?
Try by using the following:
SQL Fiddle
WITH a AS
( SELECT DISTINCT A.id group_id,
Split.A.value('.', 'VARCHAR(100)') AS Data
FROM
(SELECT id,
CAST ('<M>' + REPLACE(REPLACE(REPLACE(REPLACE(formula, '/', '/</M><M>'), '+','+</M><M>'), '-','+</M><M>'),'*','+</M><M>') + '</M>' AS XML) AS Data
FROM test
) AS A CROSS APPLY Data.nodes ('/M') AS Split(a)
),
b AS
(SELECT group_id,
REPLACE(LEFT(Data, LEN(Data)-1), t.[Code], concat(t.[id],RIGHT(Data,1))) yy,
REPLACE(Data, t.[Code], t.[id])uu
FROM a
LEFT JOIN test1 t
ON t.Code =LEFT(Data, LEN(Data)-1)
OR (t.Code=Data)
)
SELECT group_id,
REPLACE(REPLACE(REPLACE(REPLACE(stuff(
(SELECT uu FROM b WHERE newtable.group_id=group_id FOR XML PATH('')
), 1,1,''), 'uu', ''), '</>', ''),'<', ''), '>', '')
FROM b newtable
GROUP BY group_id
Here, I have also specified multiplication and subtraction, in case they appear in your expression column. You can edit it accordingly if there exist some other ones:
CAST ('<M>' + REPLACE(REPLACE(REPLACE(REPLACE(formula, '/', '/</M><M>'), '+','+</M><M>'), '-','+</M><M>'),'*','+</M><M>') + '</M>' AS XML) AS Data
I have a SQL table like this:
CC Descr C_NO Vol Wt
2050 Des1 123 20 40
2060 Des2 123 30 50
2050 Des1 125 20 40
2060 Des2 125 30 50
2050 Des1 126 20 40
and I want output like this:
2050
Des1
123
20
40
125
20
40
126
20
40
2060
Des2
123
30
50
125
30
50
How can I do that using TSQL code?
For every similar CC value which always have similar Descr value, it shows all the C_No, Vol and Wt values related to that particular CC value in the sequence written in the output section.
Try this
DECLARE #t TABLE
(
CC BIGINT,
Descr NVARCHAR(10),
C_NO INT,
Vol SMALLINT,
WT SMALLINT
)
INSERT INTO #t(CC,Descr,C_NO,Vol,WT)
VALUES (2050,'Des1',123,20,40)
,(2060,'Des2',123,30,50)
,(2050,'Des1',125,20,40)
,(2060,'Des2',125,30,50)
,(2050,'Des1',126,20,40)
;WITH CTE1 AS(
SELECT
t1.CC
,t1.Descr
,MergedColumn = STUFF(
(SELECT
','
+ CAST(C_NO AS VARCHAR(10)) + '/' + CAST(Vol AS VARCHAR(10)) + '/' + CAST(Wt AS VARCHAR(10))
FROM #t AS t2
WHERE t2.CC=t1.CC AND t2.Descr=t2.Descr
FOR XML PATH('')),1,1,'')
FROM #t t1
GROUP BY t1.CC,t1.Descr)
,CTE2 AS
(
SELECT
X.CC
,X.Descr
,Y.SplitDataByComma
FROM
(
SELECT
*,
CAST('<X>'+REPLACE(F.MergedColumn,',','</X><X>')+'</X>' AS XML) AS xmlfilter
FROM CTE1 F
)X
CROSS APPLY
(
SELECT fdata.D.value('.','varchar(50)') AS SplitDataByComma
FROM X.xmlfilter.nodes('X') AS fdata(D)
)Y
)
,CTE3 AS
(
SELECT
X.CC
,X.Descr
,Y.SplitDataBySlash
, X.SplitDataByComma AS GrpID
,ROW_NUMBER() OVER( PARTITION BY X.SplitDataByComma ORDER BY X.CC,X.Descr ) AS Rn
,X.SplitDataByComma + CAST(CC AS Varchar(200)) + CAST(Descr AS Varchar(200)) CC_Descr
FROM
(
SELECT
*,
CAST('<X>'+REPLACE(F.SplitDataByComma,'/','</X><X>')+'</X>' AS XML) AS xmlfilter
FROM CTE2 F
)X
CROSS APPLY
(
SELECT fdata.D.value('.','varchar(50)') AS SplitDataBySlash
FROM X.xmlfilter.nodes('X') AS fdata(D)
)Y
)
,CTE4 AS
(
SELECT
Rn = ROW_NUMBER() OVER(PARTITION BY CC ORDER BY CC)
,CC
,Descr
,CASE WHEN Rn = 1 THEN CAST (SplitDataBySlash AS VARCHAR(10)) ELSE ' ' END C_NO
,CASE WHEN Rn = 1 THEN ' ' ELSE CAST (SplitDataBySlash AS VARCHAR(10)) END Vol_Wt
,GrpID
FROM Cte3
)
,CTE5 AS(
SELECT
CC = CASE WHEN Rn > 1 THEN ' ' ELSE CAST(CC AS Varchar(200)) END
,Descr = CASE WHEN Rn > 1 THEN ' ' ELSE CAST(Descr AS Varchar(200)) END
,C_NO
,Vol_Wt
,GrpID
FROM Cte4)
SELECT
CHAR(10)
+ REPLICATE(SPACE(1),10)
+ CAST(CC as VARCHAR(100))
+ CHAR(10)
+ REPLICATE(SPACE(1),15)
+ Descr
+ CHAR(10)
+ REPLICATE(SPACE(1),10)
+ C_NO
+ CHAR(10)
+ REPLICATE(SPACE(1),15)
+ Vol_Wt
FROM CTE5
In Text Mode(CTRL + T), the result is
2050
Des1
123
20
40
125
20
40
126
20
40
2060
Des2
123
30
50
125
30
50
And in Grid Mode(CTRL + D) , the result is
(No column name)
2050
Des1
123
20
40
125
20
40
126
20
40
2060
Des2
123
30
50
125
30
50
However, SQL Server (or any database) is not the place to do formatting as others spoke about.Please look into the matter.
I wouldn't do this. TSQL is used to get the data, then you format that data with application code.
But if you're working in Query analyzer and just want the output there, you can try the following:
DECLARE mytable_cursor CURSOR FOR
SELECT CC, Descr, C_NO, Vol, Wt
FROM myTable
ORDER BY CC, Descr, C_NO
OPEN mytable_cursor;
FETCH NEXT FROM mytable_cursor
INTO #CC, #Descr, #C_NO, #Vol, #Wt
SET #oCC = #CC
SET #oDescr = #Descr
SET #oC_NO = #C_NO
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #CC;
WHILE ##FETCH_STATUS = 0 AND #oCC = #CC
BEGIN
PRINT ' ' + #Descr;
WHILE ##FETCH_STATUS = 0 AND #oDescr = #Descr
BEGIN
PRINT ' ' + #C_NO;
WHILE ##FETCH_STATUS = 0 AND #oC_NO = #C_NO
BEGIN
PRINT ' ' + #Vol;
PRINT ' ' + #WT;
FETCH NEXT FROM mytable_cursor
INTO #CC, #Descr, #C_NO, #Vol, #Wt
END
SET #oC_NO = #C_NO
END
SET #oDescr = #Descr
END
SET #oCC = #CC
END
CLOSE mytable_cursor;
DEALLOCATE mytable_cursor;
Or you can use a GROUP BY ... WITH ROLLUP and CASE WHEN to get the results a single query.
Here's an example with dashes instead of spaces to make sure the formatting is visible:
SELECT (CASE
WHEN Descr IS NULL THEN CC
WHEN C_NO IS NULL THEN '----' + Descr
WHEN Vol IS NULL THEN '--' + C_NO
WHEN Wt IS NULL THEN '------' + Vol
ELSE '------' + Wt
END)
FROM
(SELECT CC, Descr, C_NO, Vol, Wt
FROM my
GROUP BY CC, Descr, C_NO, Vol, Wt
WITH ROLLUP) AS x
WHERE CC IS NOT NULL
ORDER BY CC, Descr, C_NO, Vol, Wt
You can't do this in tsql code. You need to do this sort of thing in the application code.
One of the best way to represent data in hierarchical order is using XML. Something more, often the use of XML is connected with great performance.
Using your example information and this peace of code:
;WITH DistinctValues (CC,Descr ) AS
(
SELECT DISTINCT CC,Descr
FROM #TableOne
)
SELECT (
SELECT CC AS "CC/#CC"
,Descr AS "CC/Descr"
,(
SELECT C_NO AS "C_NO/#C_NO",
Vol AS "C_NO/Vol",
Wt AS "C_NO/Wt"
FROM #TableOne AS Data
WHERE Data.CC=DV.CC AND Data.Descr=DV.Descr
FOR XML PATH(''),TYPE
) AS "CC"
FROM DistinctValues AS DV
FOR XML PATH(''),TYPE
)
FOR XML PATH('Source'),TYPE
I get the following result (in the form of one row return by the statement above):
<Source>
<CC CC="2050">
<Descr>Des1</Descr>
<C_NO C_NO="123">
<Vol>20</Vol>
<Wt>40</Wt>
</C_NO>
<C_NO C_NO="125">
<Vol>20</Vol>
<Wt>40</Wt>
</C_NO>
<C_NO C_NO="126">
<Vol>20</Vol>
<Wt>40</Wt>
</C_NO>
</CC>
<CC CC="2060">
<Descr>Des2</Descr>
<C_NO C_NO="123">
<Vol>30</Vol>
<Wt>50</Wt>
</C_NO>
<C_NO C_NO="125">
<Vol>30</Vol>
<Wt>50</Wt>
</C_NO>
</CC>
</Source>
Note that the XML functions in T-SQL combined with the XML language structure gives you a huge of possible variations of output data formats - you use one or many nodes, you can represent the the data as attributes or node text. Combine this as you like and as you feel it will be easiest to work with in your application level.
Here is the whole code (just copy and paste) that I have used to generated the previous XML structure:
DECLARE #TableOne TABLE
(
CC BIGINT,
Descr NVARCHAR(10),
C_NO INT,
Vol SMALLINT,
WT SMALLINT
)
INSERT INTO #TableOne(CC,Descr,C_NO,Vol,WT)
VALUES (2050,'Des1',123,20,40)
,(2060,'Des2',123,30,50)
,(2050,'Des1',125,20,40)
,(2060,'Des2',125,30,50)
,(2050,'Des1',126,20,40)
;WITH DistinctValues (CC,Descr ) AS
(
SELECT DISTINCT CC,Descr
FROM #TableOne
)
SELECT (
SELECT CC AS "CC/#CC"
,Descr AS "CC/Descr"
,(
SELECT C_NO AS "C_NO/#C_NO",
Vol AS "C_NO/Vol",
Wt AS "C_NO/Wt"
FROM #TableOne AS Data
WHERE Data.CC=DV.CC AND Data.Descr=DV.Descr
FOR XML PATH(''),TYPE
) AS "CC"
FROM DistinctValues AS DV
FOR XML PATH(''),TYPE
)
FOR XML PATH('Source'),TYPE
This works like a charm and it is tested on Microsoft SQL Server Management Studio 2012.
I have a table as below
DECLARE #T TABLE(Data VARCHAR(MAX))
INSERT INTO #T
SELECT 'SQL' UNION ALL SELECT 'JOB'
need output as below but without using any UDF.
Data String
------------
SQL S,Q,L
JOB J,O,B
Please help me on this
Sure you can :). You can make it shorter too...
DECLARE #T TABLE(Data VARCHAR(MAX))
INSERT INTO #T
SELECT 'SQL' UNION ALL SELECT 'JOB';
With cte as
(
Select Data, Len(Data) DataLength, 1 level
From #t
Union All
Select Data, DataLength - 1, level + 1
From cte
Where DataLength > 1
),
cte2 as
(
Select Data, SUBSTRING(Data, DataLength, 1) DataLetter, level
From cte
),
cte3 as
(
Select Data,
(
SELECT DataLetter + ','
FROM cte2 c
Where c.Data = cte2.Data
Order By level desc
FOR XML PATH(''), TYPE
).value('.[1]', 'NVARCHAR(1000)') DataComa
From cte2
Group By Data
)
Select Data, substring(DataComa, 1, Len(DataComa) - 1) Data2
From cte3
Late to the party, but here's a slightly shorter version:
DECLARE #T TABLE(Data VARCHAR(MAX));
INSERT INTO #T VALUES('SQL'),('JOB'),('FLOOB');
;WITH n AS (SELECT TOP (SELECT MAX(LEN(Data)) FROM #T)
n = ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects
),
t AS (SELECT n, Data, Letter = SUBSTRING(t.Data, n.n, 1) FROM n
INNER JOIN #T AS t ON SUBSTRING(t.Data, n.n, 1) > ''
)
SELECT Data, STUFF((SELECT ',' + letter FROM t AS t2
WHERE t2.Data = t.Data ORDER BY t2.n FOR XML PATH(''),
TYPE).value(N'./text()[1]', N'varchar(max)'), 1, 1, '')
FROM t GROUP BY Data;
Results:
FLOOB F,L,O,O,B
JOB J,O,B
SQL S,Q,L
It is very easy to do with UDF.
But If you want with out UDF, the only one way I can think of is
something like this
DECLARE #T TABLE(Data VARCHAR(MAX))
INSERT INTO #T
SELECT 'SQL' UNION ALL SELECT 'JOB'
select replace(replace(replace(data,'S','S,'),'Q','Q,'),'L','L,') from #T
here you have to replace all the 26 characters with replace function. ie, 'A' with 'A,' 'B' with 'B,' .... 'Z' with 'Z,'
Using the same approach I used for Initcap function here http://beyondrelational.com/modules/2/blogs/70/posts/10901/tsql-initcap-function-convert-a-string-to-proper-case.aspx
DECLARE #T TABLE(Data VARCHAR(MAX))
INSERT INTO #T
SELECT 'SQL' UNION ALL SELECT 'JOB'
select data,
upper(replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(
' '+data ,
' a','a,'),' b','b,'),'c','c,'),'d','d,'),'e','e,'),'f','f,'),
' g','g,'),' h','h,'),'i','i,'),'j','j,'),'k','k,'),'l','l,'),
' m','m,'),' n','n,'),'o','o,'),'p','p,'),'q','q,'),'r','r,'),
' s','s,'),' t','t,'),'u','u,'),'v','v,'),'w','w,'),'x','x,'),
' y','y,'),' z','z,')) as splitted_data
from
#t