SQL Server 2012: How to find common values in a column - sql-server

SQL Server 2012: How to find common values in a column
Please find below my exact requirement and help me with the Fine tuned query.
Please find below my exact requirement and help me with the Fine tuned query.
Please find below my exact requirement and help me with the Fine tuned query.
Input :
select 1, 'sankar', 'GROUPLG'
union all
select 1, 'sankar', 'GROUPLS'
union all
select 1, 'sankar', 'GROUPNG'
union all
select 1, 'sankar', 'GROUPNS'
union all
select 2, 'Srini', 'HYDRSPMLG'
union all
select 2, 'Srini', 'HYDRSPMLS'
union all
select 3, 'Ravi', 'AADSCLS'
union all
select 4, 'Arun', 'RREDFTLS'
union all
select 4, 'Arun', 'RREDFTNG'
union all
select 5, 'Raja', '1234567'
union all
select 5, 'Raja', 'ABCDESLS'
union all
select 5, 'Raja', 'ABCDESLG'
union all
select 6, 'Dhilip', 'GGGGRASCDW_RV'
Output :
-- 1 Sankar GROUP(LG,LS,NG,NS)
-- 2 Srini HYDRSPM(LG,LS)
-- 3 Ravi AADSCLS
-- 4 Arun RREDFT(LS,NG)
-- 5 Raja 1234567
-- 5 Raja ABCDESLG(LG,LS)
-- 6 dhilip GGGGRASCDW_RV

Using FOR XML PATH('') to concatenate the groups:
SQL Fiddle
SELECT
t.Userid,
t.Username,
Groupname = 'GROUP(' +
STUFF((
SELECT ',' + STUFF(GroupName, 1, 5, '')
FROM tbl
WHERE Userid = t.Userid
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
, 1, 1, '') + ')'
FROM tbl t
GROUP BY t.Userid, t.Username
DROP TABLE tbl
RESULT:
| Userid | Username | Groupname |
|--------|----------|--------------------|
| 1 | sankar | GROUP(LG,LS,NG,NS) |
| 2 | Srini | GROUP(LG,LS) |
| 3 | Aathi | GROUP(LS) |

Try the below code snippet -
select a.userid,a.username,
CASE WHEN PATINDEX('%,%',a.groupname) > 0 THEN
LEFT(a.groupname,PATINDEX('%,%',a.groupname)-3)+'('+REPLACE(a.groupname,LEFT(a.groupname,PATINDEX('%,%',a.groupname)-3),'')+')'
ELSE a.groupname
END as groupname
from
(select userid,username,
stuff((
select ',' + t.[Groupname]
from #users t
where t.Userid = t1.userid
order by t.[Groupname]
for xml path('')
),1,1,'') as groupname
from #users t1
group by userid,Username) a
Edit: Changed the code as per the requirement. Please re-check now.

Assuming userid + username combination is unique, please try following query. Also considering that you don't need parenthesis around group in case of a single group, I'v updated the below query.
explanation: I've used STUFF function to calculate the grouping of groups with a comma followed by every group code like LS,LG,
Now based on comparison of position of comma using CHARINDEX with length of string using LEN, we attach the logic either adding GROUP() or GROUP to the string
select
userid,
username,
CASE
WHEN CHARINDEX(',',groupname)<LEN(groupname)
THEN 'GROUP('+ SUBSTRING(groupname,1,LEN(groupname)-1) +')'
ELSE 'GROUP'+SUBSTRING(groupname,1,LEN(groupname)-1)
end as groupname
from
(
select
userid,
username,
stuff((
select
replace(groupname,'group','') + ','
from tbl
where
userid=t.userid and username=t.username
for xml path(''),type).value('.','varchar(max)'),1,0,'')
as groupname
from tbl t
group by userid, username
)t
and updated
sql fiddle link http://sqlfiddle.com/#!6/21f65/1
gives this exact output
Userid Username Groupname
1 Sankar GROUP(LG,LS,NG,NS)
2 Srini GROUP(LG,LS)
3 Aathi GROUPLS

Finally i have succeeded by the below query which i have developed. Thanks for you all. If you want You can copy the below query and execute in SSMS.
begin tran
Create table #temp (userid int, username varchar(50), groupname varchar(50))
insert into #temp(userid , username , groupname)
select 1, 'sankar', 'GROUPLG'
union all
select 1, 'sankar', 'GROUPLS'
union all
select 1, 'sankar', 'GROUPNG'
union all
select 1, 'sankar', 'GROUPNS'
union all
select 2, 'Srini', 'HYDRSPMLG'
union all
select 2, 'Srini', 'HYDRSPMLS'
union all
select 3, 'Ravi', 'AADSCLS'
union all
select 4, 'Arun', 'RREDFTLS'
union all
select 4, 'Arun', 'RREDFTNG'
union all
select 5, 'Raja', '1234567'
union all
select 5, 'Raja', 'ABCDESLS'
union all
select 5, 'Raja', 'ABCDESLG'
union all
select 6, 'Dhilip', 'GGGGRASCDW_RV'
union all
select 6, 'Dhilip', 'CDW_RV'
union all
select 6, 'Dhilip', 'GFNG'
union all
select 6, 'Dhilip', 'GFNS'
union all
select 7, 'Satya', '184518451845'
select * from #temp
select tp.userid , tp.username, groupname + CASE WHEN tp.flag = 1 THEN CASE WHEN ct.cnt > 1 then ' (' else '' end +
ISNULL(pt.grouptype1,'')+case when grouptype2 is not null
and grouptype1 is not null then ',' else '' end +
ISNULL(pt.grouptype2,'')+case when grouptype3 is not null
and (grouptype1 is not null
or grouptype2 is not null ) then ',' else '' end +
ISNULL(pt.grouptype3,'')+case when grouptype4 is not null
and (grouptype1 is not null
or grouptype2 is not null
or grouptype3 is not null) then ',' else '' end +
ISNULL(pt.grouptype4,'') + case when ct.cnt > 1 then ')' else '' end
ELSE ''
END as Permission
from (SELECT distinct userid , username, CASE WHEN RIGHT(groupname,2) IN ('LG','LS','NG','NS') THEN Substring(groupname,1,len(groupname)-2)
ELSE groupname END as groupname ,
CASE WHEN RIGHT(groupname,2) IN ('LG','LS','NG','NS') THEN 1
ELSE 0 END as flag from #temp ) tp
--WHERE Substring(groupname,1,len(groupname)-2) IN ('LG','LS','NG','NS')
join (select userid , [LG] as grouptype1 , [LS] as grouptype2 , [NG] as grouptype3 ,
[NS] as grouptype4
FROM (SELECT userid , RIGHT(groupname,2) as grouptype FROM #temp) as Sourcetable
PIVOT (MAX(grouptype)
for grouptype in ([LG],[LS],[NG],[NS])) As Pivottable) pt
ON tp.userid = pt.userid
join (select userid, count(*) as cnt from #temp group by userid ) ct
on ct.userid = tp.userid
DROP TABLE #temp
-- Expected Output
-- 1 Sankar GROUP(LG,LS,NG,NS)
-- 2 Srini HYDRSPM(LG,LS)
-- 3 Ravi AADSCLS
-- 4 Arun RREDFT(LS,NG)
-- 5 Raja 1234567
-- 5 Raja ABCDESLG(LG,LS)
-- 6 dhilip GGGGRASCDW_RV
rollback

Related

FREE TEXT SQL extract from fullname

Need help with extracting the firstname, middlename and lastname from a
freetext fullname. How to extract them out with all these formats?
Need to figure out how to handle format 2,5,9,7
--fullname sample data
DECLARE #name TABLE
(fullname VARCHAR(100))
INSERT INTO #name SELECT
'Malone,Susan M' UNION ALL SELECT --1
'Conn,Chris G' UNION ALL SELECT --2
'Van Pess,Wen B' UNION ALL SELECT --3
'DESHPANDE, ANN W.' UNION ALL SELECT --4
'Asif,LEE' UNION ALL SELECT --5
'CERVANTES MANDY'UNION ALL SELECT --6
'Bill, Dave' UNION ALL SELECT --7
'SMITH,ANN M' UNION ALL SELECT --8
'BHULLER, MATT' UNION ALL SELECT --9
'KIM (DAUM), GAIL' UNION ALL SELECT --10
'John.Mills'--11
DECLARE #DELIMITER1 varchar(5), #DELIMITER2 varchar(5), #DELIMITER3
varchar(5),#MAX_LENGTH int
SET #DELIMITER1 = ','
SET #DELIMITER2 = ' '
SET #MAX_LENGTH = 50
--LastName
SELECT fullname,
case when
CHARINDEX(#DELIMITER2, fullname) >=1
then replace(SUBSTRING(fullname, 1, CHARINDEX(#DELIMITER2, fullname)
),',','')--replace to empty string if contains a ","
when
CHARINDEX(#DELIMITER2, fullname) =0
then replace(SUBSTRING(fullname, 1, CHARINDEX(#DELIMITER1, fullname)
),',','')--replace to empty string if contains a ","
else null
end as Lastname,
--Middle Name
CASE
-- Middle fullname follows two-fullname first fullnames like Mary Ann
WHEN LEN(SUBSTRING(fullname, CHARINDEX(#DELIMITER1,fullname)+
2,#MAX_LENGTH)) - LEN(REPLACE(SUBSTRING(fullname,
CHARINDEX(#DELIMITER1,fullname)+ 2,#MAX_LENGTH), #DELIMITER2, '')) > 0
--when len is greater than 0
THEN SUBSTRING(fullname, LEN(fullname) - CHARINDEX(#DELIMITER2,
REVERSE(fullname))+2, #MAX_LENGTH)
ELSE NULL
END AS Middlefullname,
--First Name
CASE
-- Count the number of #DELIMITER2. Choose the string between the
WHEN LEN(SUBSTRING(fullname, CHARINDEX(#DELIMITER1,fullname)+
2,#MAX_LENGTH)) - LEN(REPLACE(SUBSTRING(fullname,
CHARINDEX(#DELIMITER1,fullname)+ 2,#MAX_LENGTH), #DELIMITER2, '')) > 0 --
--when len is greater than 0
Then replace(ltrim(SUBSTRING(fullname, CHARINDEX(#DELIMITER1,fullname)+
1,
---need help here
(LEN(SUBSTRING(fullname, CHARINDEX(#DELIMITER1,fullname)+ 2,#MAX_LENGTH))-
LEN(SUBSTRING(fullname, LEN(fullname) - CHARINDEX(#DELIMITER2,
REVERSE(fullname))+2, #MAX_LENGTH))))),'-','') --replace the "-" to empty
string
ELSE ltrim(SUBSTRING(fullname,CHARINDEX(#DELIMITER1,fullname)+
1,#MAX_LENGTH))--trimmed leading spaces
END AS Firstname
FROM #name
order by fullname
First logic to concatenate the "name parts" with dots. Note my comments.
--fullname sample data
DECLARE #name TABLE
(nameid int identity, fullname VARCHAR(100))
INSERT INTO #name SELECT
'Malone,Susan M' UNION ALL SELECT --1
'Conn,Chris G' UNION ALL SELECT --2
'Van Pess,Wen B' UNION ALL SELECT --3
'DESHPANDE, ANN W.' UNION ALL SELECT --4
'Asif,LEE' UNION ALL SELECT --5
'CERVANTES MANDY'UNION ALL SELECT --6
'Bill, Dave' UNION ALL SELECT --7
'SMITH,ANN M' UNION ALL SELECT --8
'BHULLER, MATT' UNION ALL SELECT --9
'KIM (DAUM), GAIL' UNION ALL SELECT --10
'John.Mills';--11
select original = fullname, prepped = dotted.fn, total.spaces
from #name
cross apply (values (patindex('%(%),%',fullname),fullname)) prep1(x,fn) -- check for parentheses:
cross apply (values ( -- remove parentheses if they exist, replace commas w/ dots, dots w/ spaces:
case
when prep1.x > 1 then substring(fn,1,x-1) + substring(fn,charindex(',',fn,x)+1,8000)
else replace(replace(fn, ',', '.'),'.',' ')
end)) prep(fn)
cross apply (values (replace(rtrim(ltrim(replace(prep.fn,' ',' '))),' ',' '))) clean(fn)
cross apply (values (len(clean.fn)-len(replace(clean.fn,' ','')))) total(spaces) -- count spaces
cross apply (values (replace(clean.fn, ' ','.'))) dotted(fn); -- replace spaces with dots
This returns
original prepped spaces
------------------------ -------------------- -------
Malone,Susan M Malone.Susan.M 2
Conn,Chris G Conn.Chris.G 2
Van Pess,Wen B Van.Pess.Wen.B 3
DESHPANDE, ANN W. DESHPANDE.ANN.W 2
Asif,LEE Asif.LEE 1
CERVANTES MANDY CERVANTES.MANDY 1
Bill, Dave Bill.Dave 1
SMITH,ANN M SMITH.ANN.M 2
BHULLER, MATT BHULLER.MATT 1
KIM (DAUM), GAIL KIM.GAIL 1
John.Mills John.Mills 1
The rest can be done using parsename like so:
--fullname sample data
DECLARE #name TABLE
(nameid int identity, fullname VARCHAR(100))
INSERT INTO #name SELECT
'Malone,Susan M' UNION ALL SELECT --1
'Conn,Chris G' UNION ALL SELECT --2
'Van Pess,Wen B' UNION ALL SELECT --3
'DESHPANDE, ANN W.' UNION ALL SELECT --4
'Asif,LEE' UNION ALL SELECT --5
'CERVANTES MANDY'UNION ALL SELECT --6
'Bill, Dave' UNION ALL SELECT --7
'SMITH,ANN M' UNION ALL SELECT --8
'BHULLER, MATT' UNION ALL SELECT --9
'KIM (DAUM), GAIL' UNION ALL SELECT --10
'John.Mills';--11
with clean as
(
select original = fullname, prepped = dotted.fn, total.spaces
from #name
cross apply (values (patindex('%(%),%',fullname),fullname)) prep1(x,fn) -- check for parentheses:
cross apply (values ( -- remove parentheses if they exist, replace commas w/ dots, dots w/ spaces:
case
when prep1.x > 1 then substring(fn,1,x-1) + substring(fn,charindex(',',fn,x)+1,8000)
else replace(replace(fn, ',', '.'),'.',' ')
end)) prep(fn)
cross apply (values (replace(rtrim(ltrim(replace(prep.fn,' ',' '))),' ',' '))) clean(fn)
cross apply (values (len(clean.fn)-len(replace(clean.fn,' ','')))) total(spaces) -- count spaces
cross apply (values (replace(clean.fn, ' ','.'))) dotted(fn)
)
select original, cleaned =
case spaces
when 1 then parsename(prepped,1)+' '+parsename(prepped,2)
when 2 then parsename(prepped,2)+' '+parsename(prepped,1)+' '+parsename(prepped,3)
when 3 then parsename(prepped,2)+' '+parsename(prepped,1)+' '+parsename(prepped,3)+
' '+parsename(prepped,4)
end
from clean
Returns:
original cleaned
-------------------- ------------------
Malone,Susan M Susan M Malone
Conn,Chris G Chris G Conn
Van Pess,Wen B Wen B Pess Van
DESHPANDE, ANN W. ANN W DESHPANDE
Asif,LEE LEE Asif
CERVANTES MANDY MANDY CERVANTES
Bill, Dave Dave Bill
SMITH,ANN M ANN M SMITH
BHULLER, MATT MATT BHULLER
KIM (DAUM), GAIL GAIL KIM
John.Mills Mills John
Alternatively you can use a regex clr (mdq.regexreplace). Note my post on SSC a few years ago.

how can i find changes in a specific column and get the old value

Good morning all
I would appreciate any help you can give me in this subject
I have a table that grows in time with the same Id1
but some time Id2 change , like a historic of a park.
I would like to find the best way with a query to retrieve
the rows where id2 changes and time
example if table contents are
Id1 Id2 time
1 1 10:00
1 1 10:30
1 2 10:40
1 2 10:45
1 2 11:00
1 3 11:45
1 3 12:45
query output would be
Id1 oldId2 newId2 time
1 1 2 10:40
1 2 3 11:45
i have done with a stored procedure, but I was wondering of there is a faster/cleaner way to get this
thanks in advance
You can do this by Ranking functions..
Schema:
CREATE TABLE #TAB (Id1 INT,Id2 INT, timeS TIME )
INSERT INTO #TAB
SELECT 1 AS Id1 , 1 Id2, '10:00' AS timeS
UNION ALL
SELECT 1, 1, '10:30'
UNION ALL
SELECT 1, 2, '10:40'
UNION ALL
SELECT 1, 2, '10:45'
UNION ALL
SELECT 1, 2, '11:00'
UNION ALL
SELECT 1, 3, '11:45'
UNION ALL
SELECT 1, 3, '12:45'
Now do select with ROW_NUMBER and CTE for retrieving previous/next row values.
;WITH CTE
AS (
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RNO
,ID1
,ID2
,timeS
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY ID2 ORDER BY TIMES) AS SNO
,*
FROM #TAB
) A
WHERE SNO = 1
)
SELECT C1.Id1
,C1.Id2 AS OLD_ID2
,C2.Id2 AS NEW_ID2
,C2.timeS
FROM CTE C1
LEFT JOIN CTE C2 ON C1.RNO + 1 = C2.RNO
WHERE C2.Id1 IS NOT NULL
Result:
+-----+---------+---------+------------------+
| Id1 | OLD_ID2 | NEW_ID2 | timeS |
+-----+---------+---------+------------------+
| 1 | 1 | 2 | 10:40:00.0000000 |
| 1 | 2 | 3 | 11:45:00.0000000 |
+-----+---------+---------+------------------+
Note: If you want to get Previous/Next Row values into current row, you can use LEAD LAG functions. But they support only in SQL Server 2012+.
The above Left Join with CTE will work for lower versions too.
declare #t table (Id1 int, Id2 int, [time] time)
insert into #t
select 1, 1, '10:00' union
select 1, 1, '10:30' union
select 1, 2, '10:40' union
select 1, 2, '10:45' union
select 1, 2, '11:00' union
select 1, 3, '11:45' union
select 1, 3, '12:45'
select Id1, oldId = (select top 1 id2 from #t where Id1=t.Id1 and Id2 < t.Id2 order by id2, time desc), newId = id2, time = min(time)
from #t t
where id2 > 1
group by Id1, id2
i have done some changes to the code from Shakeer Mirza.
the pratical problem that originated the question in the first place is:
i have a table that represents the history of an equipment. Being machine internal id(Num_TPA).
Each time there is a malfunction, the machine is replaced by another it keeps the same Num_TPA but Serial_number changes
i needed to know what is the historic on internal_id->Num_TPA . the new and the old serial_number , and the date of replacement
and this is what it came out.
;WITH CTE
AS (
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RNO
,[Num_TPA]
,[Serial_number]
,[Time]
,a.SNO
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY [Num_TPA]
ORDER BY [Data_Hora_Ficheiro]) AS SNO
,*
FROM tab_values
) A
WHERE SNO > 1
)
SELECT C1.[Num_TPA]
,C1.[Serial_number] AS OLD_ID2
,C2.[Serial_number] AS NEW_ID2
,C2.[Data_Hora_Ficheiro]
,c2.SNO
,c2.RNO
FROM tab_values C1
LEFT JOIN CTE C2 ON (
C1.[Num_TPA] = C2.[Num_TPA]
AND c1.[Serial_number] != c2.[Serial_number]
AND C2.[Time] > c1.TIME
)
WHERE C2.[Num_TPA] IS NOT NULL
AND SNO = 2
UNION
SELECT C1.[Num_TPA]
,C1.[Serial_number] AS OLD_ID2
,C2.[Serial_number] AS NEW_ID2
,C2.[Data_Hora_Ficheiro]
,c2.SNO
,c2.RNO
FROM CTE C1
LEFT JOIN CTE C2 ON (
C1.SNO + 1 = C2.SNO
AND C1.[Num_TPA] = C2.[Num_TPA]
)
WHERE C2.[Num_TPA] IS NOT NULL
AND C2.SNO > 2

. It’s working fine when I pass 10-15 input but taking more than 5 minutes for 30 input. I need to make it work for 100 inputs

Here is my ask:
Go through the code and understand it.
As first solution, query should complete within 10 secs for 30 input
It should be working with good performance for 100 input as well.
My code:
/**************************************************
Populating the Array values in table variable
**************************************************/
DECLARE #PUZZLE table(
ID int IDENTITY(1,1) NOT NULL,
Value int NOT NULL)
/****Sample 1*****/
INSERT INTO #PUZZLE (value)
--SELECT 0 UNION ALL
--SELECT -22 UNION ALL
--SELECT -33 UNION ALL
--SELECT -44 UNION ALL
--SELECT 55 UNION ALL
--SELECT -100 UNION ALL
--SELECT 100 UNION ALL
--SELECT 10 UNION ALL
--SELECT -30 UNION ALL
--SELECT -60 UNION ALL
--SELECT -60 UNION ALL
SELECT -60 UNION ALL
SELECT -10 UNION ALL
SELECT 10 UNION ALL
SELECT 10 UNION ALL
SELECT -10 UNION ALL
SELECT 0 UNION ALL
SELECT -22 UNION ALL
SELECT -33 UNION ALL
SELECT -44 UNION ALL
SELECT 55 UNION ALL
SELECT -100 UNION ALL
SELECT 100 UNION ALL
SELECT 10 UNION ALL
SELECT -30 UNION ALL
SELECT -60 UNION ALL
SELECT -60 UNION ALL
SELECT -60 UNION ALL
SELECT -10 UNION ALL
SELECT 10 UNION ALL
SELECT 10
/**************************************************
Populating possible hierarchy/path
**************************************************/
DECLARE #puzHierarchy table (parentid int, childid int,value int)
INSERT #puzHierarchy (parentid,childid,value)
SELECT *-- INTO #puzHierarchy
FROM (
SELECT NULL AS ParentId,ID AS ChildId, Value
FROM #PUZZLE
WHERE ID = (SELECT MIN(ID) FROM #PUZZLE)
UNION ALL
SELECT B.Id,C.ID,C.Value
FROM #PUZZLE B
JOIN #PUZZLE C
ON C.ID > B.ID AND C.ID < (B.ID + 7)
) A
--SELECT * FROM #puzHierarchy order by parentid
/*******************************************************
Logic using recursive CTE to get the path with max value
*******************************************************/
;WITH children AS
(
SELECT ParentId
,CAST(ISNULL(CAST(ParentId AS NVARCHAR) + '->' ,'') + CAST(ChildId AS NVARCHAR) AS NVARCHAR(Max)) AS Path
,value As PathValue
FROM #puzHierarchy
WHERE ChildId = (SELECT MAX(ChildId) FROM #puzHierarchy)
UNION ALL
SELECT t.ParentId
,list= CAST(ISNULL(CAST(t.ParentId AS NVARCHAR) + '->' ,'') + d.Path AS NVARCHAR(Max))
,(t.value+d.PathValue) As PathValue
FROM #puzHierarchy t
INNER JOIN children AS d
ON t.ChildId = d.ParentId
)
SELECT [Path],PathValue
FROM children c
WHERE ParentId IS NULL
AND c.PathValue = (SELECT max(PathValue) FROM children WHERE ParentId IS NULL)
A. Your code goes through too many cycles/data unrelated to result you want.
B. After running your sample data, the results are not accurate.
Parentid Path PathValue
NULL 1->3->4->6->10->12->13->19->20 145
NULL 1->3->4->10->12->13->19->20 145
The first result is wrong.
Basically you just want starting from ParentId IS NULL and ChildId = 1, among ParentId = 1 finding which ChildId has the MAX value, this ChildId becomes ParentID to find next MAX value, and so on.
;WITH cte_base AS (SELECT Parentid
, Childid
, Value
, ROW_NUMBER() OVER(PARTITION BY Parentid ORDER BY Value DESC) AS Rownum
FROM #puzHierarchy
), cte_re AS (SELECT ParentId
, Childid
, CAST(CAST(ChildId AS NVARCHAR) AS NVARCHAR(Max)) AS Path
, Value As PathValue
, Rownum
FROM cte_base
WHERE Parentid IS NULL
UNION ALL
SELECT b.parentid, b.childid
, CAST(Path + '->' + ISNULL(CAST(b.parentid AS NVARCHAR) ,'') AS NVARCHAR(Max))
,(b.value + r.PathValue) As PathValue
, b.Rownum
FROM cte_base AS b
INNER JOIN cte_re AS r
ON b.Parentid = r.childid
where b.Rownum = 1
)
SELECT *
FROM cte_re
(I changed your sample table variable to a temporary table.)

Consolidate rows of data in SQL Server

I have multiple rows of order data which i need to consolidate in one row per part.
An example is as follows:
OrderNum PartNum Qty
-------------------------------
1 24 2
2 25 10
3 24 5
4 24 10
This then needs to be consolidated into:
OrderNum PartNum Qty
-------------------------------
1, 3, 4 24 17
2 25 10
Does anybody have any ideas how I can do this?
I have had a look around online but cannot find a solution to this use case.
Many thanks in advance,
Try this
SELECT STUFF((SELECT ',' + CAST(OrderNum AS VARCHAR(4))
FROM mytable AS s
WHERE s.PartNum = t.PartNum
FOR XML PATH('')), 1, 1, '') AS OrderNum
PartNum, SUM(Qty)
FROM mytable AS t
GROUP BY PartNum
This can be done by grouping on PartNum, sum the quantities with SUM() and concatenating strings using FOR XML PATH('') in a correlated subquery. Using FOR XML PATH('') to concatenate string is explained in this answer on SO.
DECLARE #t TABLE(OrderNum INT, PartNum INT, Qty INT);
INSERT INTO #t(OrderNum,PartNum,Qty)
VALUES(1,24,2),(2,25,10),(3,24,5),(4,24,10);
SELECT
OrderNum=STUFF((
SELECT
','+CAST(i.OrderNum AS VARCHAR)
FROM
#t AS i
WHERE
i.PartNum=o.PartNum
FOR XML
PATH(''), TYPE
).value('.[1]','VARCHAR(MAX)'),1,1,''),
o.PartNum,
Qty=SUM(o.Qty)
FROM
#t AS o
GROUP BY
o.PartNum;
Result:
OrderNum | PartNum | Qty
------------------------
1,3,4 | 24 | 17
2 | 25 | 10
SQL Server 2016 added the STRING_AGG function.
In your case, you could write
select STRING_ACC(OrderId,','),PartNum, Sum(Qty)
from MyTable
Group by PartNum
For earlier versions you'd have to use one of the techniques described by Aaron Bertrand in Grouped Concatenation in SQL Server. The fastest is to use a SQLCLR method. Next comes the FOR XML method posted by #GiorgosBetsos
DECLARE #t TABLE(OrderNum INT, PartNum INT, Qty INT)
INSERT INTO #t VALUES(1 , 24 , 2)
INSERT INTO #t VALUES(2 , 25 , 10)
INSERT INTO #t VALUES(3 , 24 , 5)
INSERT INTO #t VALUES(4 , 24 , 10)
SELECT OrderNum =
STUFF((SELECT ', ' + CONVERT(VARCHAR(50),OrderNum)
FROM #t b
WHERE b.PartNum = a.PartNum
FOR XML PATH('')), 1, 2, ''),
PartNum,
SUM(Qty) as Qty
FROM #t a
GROUP BY PartNum
Result
There are many ways to do this.
create table tablename (Name varchar(100), Rnk int)
Insert into tablename values
('Northshore', 1),
('F3', 2),
('Borderline', 3),
('Mattoon',3),
('Vinemane',5),
('Arizona',5),
('WestShore', 5),
('Schumburg', 5),
('Wilson',5)
--Method2
Select distinct
names= REPLACE(
(
Select a.Name as [data()]
From tablename A
Where A.Rnk = b.Rnk
Order by a.Name
FOR XML PATH ('') ), ' ', ',') ,Rnk
From tablename B Order by Rnk
OR
CREATE TABLE TestTable (ID INT, Col VARCHAR(4))
GO
INSERT INTO TestTable (ID, Col)
SELECT 1, 'A'
UNION ALL
SELECT 1, 'B'
UNION ALL
SELECT 1, 'C'
UNION ALL
SELECT 2, 'A'
UNION ALL
SELECT 2, 'B'
UNION ALL
SELECT 2, 'C'
UNION ALL
SELECT 2, 'D'
UNION ALL
SELECT 2, 'E'
GO
SELECT *
FROM TestTable
GO
-- Get CSV values
SELECT t.ID, STUFF(
(SELECT ',' + s.Col
FROM TestTable s
WHERE s.ID = t.ID
FOR XML PATH('')),1,1,'') AS CSV
FROM TestTable AS t
GROUP BY t.ID
GO
OR
CREATE TABLE #mable(mid INT, token nvarchar(16))
INSERT INTO #mable VALUES (0, 'foo')
INSERT INTO #mable VALUES(0, 'goo')
INSERT INTO #mable VALUES(1, 'hoo')
INSERT INTO #mable VALUES(1, 'moo')
SELECT m1.mid,
( SELECT m2.token + ','
FROM #mable m2
WHERE m2.mid = m1.mid
ORDER BY token
FOR XML PATH('') ) AS token
FROM #mable m1
GROUP BY m1.mid ;
Also, see this.
http://blog.sqlauthority.com/2009/11/25/sql-server-comma-separated-values-csv-from-table-column/

How to select only data with consecutive row number starting from 1

I have a table similar to the one below.
What I want to do is to select the rows with consecutive RowNo with the same job name must be selected if it begins with RowNo = 1. Here is the sample output:
Hope you can help. Thank you.
Try this
DECLARE #Tbl TABLE (RowNo INT, Jobname NVARCHAR(50), AuditDate DATETIME)
INSERT INTO #Tbl
SELECT 3, 'Backup Database Sales', '2016.07.26' UNION ALL
SELECT 1, 'Send Autoemail Sales Report', '2016.07.26' UNION ALL
SELECT 2, 'Send Autoemail Sales Report', '2016.07.25' UNION ALL
SELECT 3, 'Send Autoemail Sales Report', '2016.07.24' UNION ALL
SELECT 4, 'Update Sales Stats', '2016.07.23' UNION ALL
SELECT 4, 'Update Sales Stats', '2016.07.22' UNION ALL
SELECT 1, 'Generate new item codes', '2016.07.26' UNION ALL
SELECT 2, 'Generate new item codes', '2016.07.25'
;WITH CTE
AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS Id FROM #Tbl
)
SELECT
*
FROM
#Tbl T
WHERE
EXISTS
(
SELECT TOP 1
1
FROM
(
SELECT
C.Jobname,
MIN(C.RowNo) MinRowNo,
MAX(C.RowNo) MaxRow
FROM
CTE C
GROUP BY
C.Jobname,
C.Id - C.RowNo
) A
WHERE
A.MinRowNo <> A.MaxRow AND
A.MinRowNo = 1 AND
A.Jobname = T.Jobname AND
T.RowNo BETWEEN A.MinRowNo AND A.MaxRow
)
Output
RowNo Jobname AuditDate
----------- -------------------------------------------------- -----------------------
1 Send Autoemail Sales Report 2016-07-26 00:00:00.000
2 Send Autoemail Sales Report 2016-07-25 00:00:00.000
3 Send Autoemail Sales Report 2016-07-24 00:00:00.000
1 Generate new item codes 2016-07-26 00:00:00.000
2 Generate new item codes 2016-07-25 00:00:00.000
SELECT T1.*
FROM
YourTable T1
INNER Join
YourTable T2
ON T1.RowNo = 1 AND T2.RowNo =1 AND T1.JobName=T2.Jobname
OR T1.RowNo > 1 AND T1.RowNo - 1 = T2.RowNo AND T1.JobName=T2.Jobname

Resources