MS SQL Server - concatenating in a particular way - sql

I've got a particular table that I need to concatenate using something like substring, but in a particular way. There are going to be lots of nulls but we still need to pay attention to them.
Basically, I've got something like...
PID Date Flag1 Flag2 Code
11 01/01/2014 1 0 16
11 25/12/2014 1 1 48
11 16/07/2016 0 1 9
12 07/01/2014 0 16
12 08/01/2014 1
12 09/01/2014 16
13 01/10/2014 1 4
13 01/11/2014 1 0 16
13 01/12/2014 0 48
Would result in (very long)...
PID Date Flag1 Flag2 Code
11 01/01/2014,25/12/2014,16/07/2014, 1,1,0, 0,1,1, 16,48,9,
12 07/01/2014,08/01/2014,09/01/2014, ,1,, 0,,, 16,,16,
13 01/10/2014,01/11/2014,01/12/2014, 1,1,, ,0,0, 4,16,48,
This way, in some code I would use later, I would be able to tell which date each flag belongs to.
Any ideas? So far I've just been using the regular substring commands which do put things into the correct fields, but I can't tell what belongs with what.
SELECT DISTINCT PS2.PID, substring
((SELECT ',' + CAST(CONVERT(VARCHAR(10), PS1.Date, 111) AS NVARCHAR) AS [text()]
FROM dbo.PS PS1
WHERE PS1.PID = PS2.PID
ORDER BY PS1.PID, PS1.Date FOR XML PATH('')), 2, 9999) + ',' [Date], substring
((SELECT ',' + LEFT(CAST(LUC.Code AS NVARCHAR), 2) AS [text()]
FROM dbo.PS PS1 INNER JOIN
dbo.MyCodes LUC ON PS1.Code = LUC.Id
WHERE PS1.PID = PS2.PID
ORDER BY PS1.PID, PS1.Date FOR XML PATH('')), 2, 9999) + ',' [Code], substring
((SELECT ',' + LEFT(CAST(PS1.Flag1 AS NVARCHAR), 1) AS [text()]
FROM dbo.PS PS1
WHERE PS1.PID = PS2.PID
ORDER BY PS1.PID, PS1.Date FOR XML PATH('')), 2, 9999) + ',' [Flag1], substring
((SELECT ',' + LEFT(CAST(PS1.Flag2 AS NVARCHAR), 1) AS [text()]
FROM dbo.PS PS1
WHERE PS1.PID = PS2.PID
ORDER BY PS1.PID, PS1.Date FOR XML PATH('')), 2, 9999) + ',' [Flag2]
FROM dbo.PS PS2
Should also note, we will always have a Date. That will not be null. Same with the PID (as that's what they're grouped on).

Please try this, I have used Date column as Edate so please replace that column and table name with your original one:
SELECT t1.PID,
STUFF(
(SELECT ',' + cast(EDate AS varchar)
FROM #tmpone t WHERE t.PID = t1.PID
FOR XML PATH(''))
, 1, 1, '') Edate,
STUFF(
(SELECT ',' + cast(Flag1 AS varchar)
FROM #tmpone t WHERE t.PID = t1.PID
FOR XML PATH(''))
, 1, 1, '') Flag1,
STUFF(
(SELECT ',' + cast(Flag2 AS varchar)
FROM #tmpone t WHERE t.PID = t1.PID
FOR XML PATH(''))
, 1, 1, '') Flag2,
STUFF(
(SELECT ',' + cast(Code AS varchar)
FROM #tmpone t WHERE t.PID = t1.PID
FOR XML PATH(''))
, 1, 1, '') Code
FROM #tmpone t1
GROUP BY t1.PID

Related

MSSQL - GROUP_CONCAT

Here is the sample data :
IdProduit Localisation Qte_EnMain
4266864286880063006 E2-R40-B-T 13.00000
4266864286880063006 E2-R45-B-T 81.00000
4266864286880063007 E2-R45-C-T 17.00000
4266864286880063008 E2-R37-B-T 8.00000
And this is what i would like to have
IdProduit AllLocalisation
4266864286880063006 E2-R40-B-T (13), E2-R45-B-T (81)
4266864286880063007 E2-R45-C-T (17)
4266864286880063008 E2-R37-B-T (8)
I watched all the examples of GROUP_CONCAT on the forum and I tried several tests.
I don't really understand STUFF().
Here is what i would like to do :
SELECT
a.IdProduit,
GROUP_CONCAT(
CONCAT(b.Localisation, ' (', CAST(ROUND(a.Qte_EnMain, 0) AS NUMERIC(36, 0)), ')')
) AS AllLocation
FROM
ogasys.INV_InventENTLoc a
LEFT JOIN ogasys.INV_LocName b ON a.IdLoc = b.IdLoc
GROUP BY a.IdProduit, b.Localisation, a.Qte_EnMain
Now because GROUP_CONCAT is nto working with MSSQL this is the query i have created with all example on this forum.
SELECT
DISTINCT
a1.IdProduit,
STUFF((SELECT DISTINCT '' + b2.Localisation
FROM
ogasys.INV_InventENTLoc a2
LEFT JOIN ogasys.INV_LocName b2 ON a2.IdLoc = b2.IdLoc
WHERE a2.IdLoc = a1.IdLoc
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 0, '') data
FROM
ogasys.INV_InventENTLoc a1
LEFT JOIN ogasys.INV_LocName b1 ON a1.IdLoc = b1.IdLoc
ORDER BY a1.IdProduit
The query only return one localisation by row i don't understand how to make this query working.
EDIT:
Here is the solution for my situation :
SELECT
a.IdProduit,
STUFF(
(SELECT ', ' + b2.Localisation + ' (' + CAST(CAST(ROUND(a2.Qte_EnMain, 0) AS NUMERIC(36, 0)) AS VARCHAR(32)) + ')'
FROM ogasys.INV_InventENTLoc a2
LEFT JOIN ogasys.INV_LocName b2 ON a2.IdLoc = b2.IdLoc
WHERE a.IdProduit = a2.IdProduit
FOR XML PATH (''))
, 1, 1, '') AS AllLocalisation
FROM
ogasys.INV_InventENTLoc a
LEFT JOIN ogasys.INV_LocName b ON a.IdLoc = b.IdLoc
GROUP BY a.IdProduit
using STUFF
declare #table table (IdProduit varchar(100), Localisation varchar(50), Qte_EnMain float)
insert into #table
values
('4266864286880063006','E2-R40-B-T', 13.00000),
('4266864286880063006','E2-R45-B-T', 81.00000),
('4266864286880063007','E2-R45-C-T', 17.00000),
('4266864286880063008','E2-R37-B-T', 8.00000)
select IdProduit,
STUFF (
(SELECT
',' + localisation + concat(' (',cast(qte_enMain as varchar(4)),') ')
FROM #table t2
where t2.IdProduit = t1.IdProduit
FOR XML PATH('')), 1, 1, ''
)
from #table t1
group by
IdProduit

How to include string text in a STUFF function (XML Path)?

Code:
ISNULL(LTRIM(STUFF( (SELECT ', ' + PL.Pipe_Product
FROM Reporting.PipelineInformation PL
WHERE PL.Project_ID = TI.Project_ID
FOR XML PATH('')), 1, 1, '')),'___________') AS Pipe_Product
How can I do this?
Another approach can be to add a ROW_NUMBER into the sub-query to decide whether a comma or and should be inserted. This should be faster since you don't have separate queries against the same PipelineInformation table both of which are correlated sub-queries.
DECLARE #PL TABLE (Pipe_Product VARCHAR(50), Project_ID INT)
INSERT #PL VALUES ('gas', 1),('oil', 1),('orange juice', 1), ('milk', 2), ('honey', 2)
SELECT
TI.Project_ID,
SUBSTRING((
SELECT
CASE WHEN RowNum = 1 THEN ' and ' ELSE ', ' END + T.Pipe_Product AS [text()]
FROM (
SELECT
Pipe_Product,
Project_ID,
ROW_NUMBER() OVER (ORDER BY Pipe_Product DESC) AS RowNum
FROM #PL
WHERE Project_ID = TI.Project_ID
) T
ORDER BY RowNum DESC
FOR XML PATH('')
), 3, 4000) AS [Pipe_Product]
FROM (SELECT 1 UNION ALL SELECT 2) AS TI (Project_ID)
The sample data above outputs:
Project_ID Pipe_Product
----------- -----------------------------
1 gas, oil and orange juice
2 honey and milk
Try this edited result instead:
reverse(stuff(reverse(ISNULL(LTRIM(STUFF((
SELECT ', ' + PL.Pipe_Product
FROM Reporting.PipelineInformation PL
WHERE PL.Project_ID = TI.Project_ID
FOR XML PATH('')
), 1, 1, '')), '___________')), charindex(' ,', reverse(ISNULL(LTRIM(STUFF((
SELECT ', ' + PL.Pipe_Product
FROM Reporting.PipelineInformation PL
WHERE PL.Project_ID = TI.Project_ID
FOR XML PATH('')
), 1, 1, '')), '___________'))), 2, ' dna '))

SQL XML path conversion results error

Actually I m begineer to SQL XML path as so making me professional, Got a scenario...
I have a CTE Function That results as
Data Chars NumberOfOccurance
12 1 1 appears (1 ) times
12 2 2 appears (1 ) times
xx x x appears (2 ) times
and CTE function is :
;with cte as
(
select Data , SUBSTRING(Data,1,1) as Chars,1 as startpos from #t
union all
select Data, SUBSTRING(Data, startpos+1,1) as char,startpos+1 from cte where startpos+1<=LEN(data)
)
select Data,Chars,Cast(Chars as varchar(1)) + ' appears (' + cast(COUNT(*) as varchar(5))+ ' ) times' as 'NumberOfOccurance' from cte
group by data, chars
Actually I just want to make my answer into this :
data Number_of_occurances
12 1 appears (1) times 2 appears (1) times
xx x appears (2) times
I have tries this :
; With Ctea as
(
select Data , SUBSTRING(Data,1,1) as Chars,1 as startpos from #t
union all
select Data, SUBSTRING(Data, startpos+1,1) as char,startpos+1 from ctea where startpos+1<=LEN(data)
)
select Data,Chars,REPLACE((SELECT (Cast(Chars as varchar(1)) + ' appears (' + cast(COUNT(*) as varchar(5))+ ' ) times') AS [data()] FROM Ctea t2 WHERE t2.Data = t1.data FOR XML PATH('')), ' ', ' ;') As Number_of_occurances from ctea as t1
group by t1.data, t1.Chars
It says :
Column 'Ctea.Chars' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
when I use temp table and getting my exact answer , but cant do it CTE
Can anyone make my result ?
The problem has nothing to do with your CTE. It actually lies in the following subquery:
SELECT (Cast(Chars as varchar(1)) +
' appears (' +
cast(COUNT(*) as varchar(5)) +
' ) times') AS [data()]
FROM Ctea t2
WHERE t2.Data = t1.data
FOR XML PATH('')
Note how you are using the aggregate COUNT(*) here as well as the column Chars. You need to group by at least Chars here:
SELECT (Cast(Chars as varchar(1)) +
' appears (' +
cast(COUNT(*) as varchar(5)) +
' ) times') AS [data()]
FROM Ctea t2
WHERE t2.Data = t1.data
GROUP BY t2.Chars
FOR XML PATH('')
Furthermore, you do not want to select or group by t1.Chars in the outer query because it will result in one row per value of Chars:
data chars Number_of_occurances
12 1 1 appears (1) times 2 appears (1) times
12 2 1 appears (1) times 2 appears (1) times
xx x x appears (2) times
Finally you should most likely be using the STUFF function, and not REPLACE, as you are trying to create a space-delimited list ("1 appears (1) times 2 appears (1) times"), not replace all space characters with a space and a semicolon ("1 ;appears ;(1) ;times ;2 ;appears ;(1) ;times").
Therefore your final query should be:
; With Ctea as
(
select Data , SUBSTRING(Data,1,1) as Chars,1 as startpos from #t
union all
select Data, SUBSTRING(Data, startpos+1,1) as char,startpos+1 from ctea
where startpos+1<=LEN(data)
)
select Data,
STUFF((SELECT cast(' ' as varchar(max)) + (Cast(Chars as varchar(1)) + ' appears (' + cast(COUNT(*) as varchar(5))+ ' ) times') AS [data()]
FROM Ctea t2
WHERE t2.Data = t1.data
GROUP BY t2.Chars
FOR XML PATH('')), 1, 1, '') As Number_of_occurances
from ctea as t1
group by t1.data
You can use FOR XML PATH like this for concatenation
;with cte as
(
select Data , SUBSTRING(Data,1,1) as Chars,1 as startpos from #t
union all
select Data, SUBSTRING(Data, startpos+1,1) as char,startpos+1 from cte where startpos+1<=LEN(data)
), CTE2 AS
(
select Data,Chars,Cast(Chars as varchar(1)) + ' appears (' + cast(COUNT(*) as varchar(5))+ ' ) times' as 'NumberOfOccurance' from cte
group by data, chars
)
SELECT Data,(SELECT NumberOfOccurance + ' ' FROM CTE2 c2 WHERE c2.Data = C1.Data FOR XML PATH(''),type).value('.','VARCHAR(MAX)') as Number_of_occurances
FROM CTE2 C1
GROUP BY Data

TSQL Select query that generates output similar to the ms access multiple value fields

I have tables in SQL Server 2008 such as:
TopicTable
TopicID: nvarchar (Primary Key)
ProgID: nvarchar
topic1: bit
topic2: bit
topic3: bit
topic4: bit
The topic table looks something like the following:
TopicID ProgID topic1 topic2 topic3 topic4
topic001 prog001 1 1 0 0
topic002 prog002 1 0 1 1
topic003 prog003 1 0 0 0
topic004 prog004 1 1 1 1
Program table:
ProgID: nvarchar (Primary Key)
ProgramName: nvarchar
The Program table looks like this:
ProgID ProgramName
prog001 programA
prog002 programB
prog003 programC
prog004 programD
I want to create a view to get the output like:
ProgID ProgramName Topic
prog001 programA topic1,topic2
prog002 programB topic1,topic3,topic4
prog003 programB topic1
prog004 programD topic1,topic2,topic3,topic4
Please can someone help me how to get this.
Thank You.
It would look like this:
;WITH cteTopics AS (
SELECT T.ProgID
,STUFF((
SELECT T1.TopicID + ','
FROM TopicTable T1
WHERE T1.ProgID = T.ProgID
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR (MAX)')
,1,0,'') [Topics]
FROM TopicTable T
GROUP BY T.ProgID)
SELECT P.ProgID, P.ProgramName, T.Topics
FROM Program P
LEFT JOIN cteTopics T ON T.ProgID = P.ProgID
http://sqlfiddle.com/#!3/b9e4a/4
You will have some extra commas here but you can tweak the code a little bit more to eliminate the extra commas . this is what I have got for you so far
CREATE Table Topic (Topic NVARCHAR(20), Programe NVARCHAR(20), Topic1 bit, Topic2 bit,Topic3 bit,Topic4 bit)
GO
INSERT INTO Topic
VALUES
('topic001','prog001',1,1,0,0),
('topic002','prog002',1,0,1,1),
('topic003','prog003',1,0,0,0),
('topic004','prog004',1,1,1,1)
GO
CREATE TABLE Programe (P_ID NVARCHAR(20) , Name NVARCHAR(20))
GO
INSERT INTO Programe VALUES
('prog001','programA'),
('prog002','programB'),
('prog003','programC'),
('prog004','programD')
GO
View Definition
CREATE VIEW vw_ViewName
AS
SELECT P_ID, Name, ISNULL(STUFF(L1.Topic1L, 1, 1 , '') + ', ', '') + ISNULL(STUFF(L2.Topic2L, 1, 1, '') + ', ', '')
+ ISNULL( STUFF(L3.Topic3L, 1, 1, '')+ ', ', '') + ISNULL(STUFF(L4.Topic4L, 1, 1, '')+ ', ', '') AS Topics
FROM Programe P CROSS APPLY (
SELECT ' ' + CASE WHEN Topic1 = 1 THEN 'Topic1' ELSE NULL END [text()]
FROM Topic
WHERE Programe = P.P_ID
FOR XML PATH('')
)L1(Topic1L)
CROSS APPLY (
SELECT ', ' + CASE WHEN Topic2 = 1 THEN 'Topic2' ELSE NULL END [text()]
FROM Topic
WHERE Programe = P.P_ID
FOR XML PATH('')
)L2(Topic2L)
CROSS APPLY (
SELECT ', ' + CASE WHEN Topic3 = 1 THEN 'Topic3' ELSE NULL END [text()]
FROM Topic
WHERE Programe = P.P_ID
FOR XML PATH('')
)L3(Topic3L)
CROSS APPLY (
SELECT ', ' + CASE WHEN Topic4= 1 THEN 'Topic4' ELSE NULL END [text()]
FROM Topic
WHERE Programe = P.P_ID
FOR XML PATH('')
)L4(Topic4L)
RESULT SET
P_ID Name Topics
prog001 programA Topic1, Topic2,
prog002 programB Topic1, Topic3, Topic4,
prog003 programC Topic1,
prog004 programD Topic1, Topic2, Topic3, Topic4,

sql server(find the count of table base on condition)

i have a table like following
RequestNo Facility status
1 BDC1 Active
1 BDC2 Active
1 BDC3 Active
2 BDC1 Active
2 BDC2 Active
i want like this
RequestNo Facilty Count
1 BDC (1,2,3) 1
2 BDC(1,2) 1
the count should display based on Status with facilty.Fcilityv should take as BDC only
Try this, (assuming that your facility is fixed 4 character code)
SELECT RequestNo, Fname + '(' + FnoList + ')' Facilty, count(*) cnt
FROM
(
SELECT distinct RequestNo,
SUBSTRING(Facility,1,3) Fname,
stuff((
select ',' + SUBSTRING(Facility,4,4)
from Dummy
where RequestNo = A.RequestNo AND
SUBSTRING(Facility,1,3) = SUBSTRING(A.Facility,1,3)
for xml path('')
) ,
1, 1, '') as FnoList
FROM Dummy A
) x
group by RequestNo, Fname, FnoList;
SQL DEMO
This doesn't put any constraints on the length of the Facility field. It strips out the chars from the beginning and the numeric numbers from the ending:
SELECT RequestNo, FacNameNumbers, COUNT(Status) as StatusCount
FROM
(
SELECT DISTINCT
t1.RequestNo,
t1.Status,
substring(facility, 1, patindex('%[^a-zA-Z ]%',facility) - 1) +
'(' +
STUFF((
SELECT DISTINCT ', ' + t2.fac_number
FROM (
select distinct
requestno,
substring(facility, 2 + len(facility) - patindex('%[^0-9 ]%',reverse(facility)), 9999) as fac_number
from facility
) t2
WHERE t2.RequestNo = t1.RequestNo
FOR XML PATH (''))
,1,2,'') + ')' AS FacNameNumbers
FROM Facility t1
) final
GROUP BY RequestNo, FacNameNumbers
And the SQL Fiddle