MSSQL - GROUP_CONCAT - sql

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

Related

How to merge two queries into one

How can I join these 2 SQL statements? I want the columns of the first and the columns of the second to appear together as one SQL query.
SELECT
E.tbl1_ORG AS Organización, E.tbl1_CODE AS [Orden de Trabajo],
E.tbl1_OBJECT AS Equipo, O.tbl3_POSITION AS Posicion,
E.tbl1_JOBTYPE AS [Tipo de Trabajo],
E.tbl1_DESC AS [Descripcion OT], E.tbl1_WORKADDRESS AS Comentarios,
E.tbl1_REQM AS Error, B.tbl2_PERSON AS Trabajador,
B.tbl2_ENTERED AS Fecha, B.tbl2_HOURS AS Horas
FROM
dbo.table1 AS E
INNER JOIN
dbo.table2 AS B ON E.tbl1_CODE = B.tbl2_EVENT
INNER JOIN
dbo.table3 AS O ON O.tbl3_CODE = E.tbl1_OBJECT
WHERE
E.tbl1_JOBTYPE IN ('PM', 'CM', 'PMM') and
E.tbl1_ORG = #PROMPT('Organización')# and
B.tbl2_ENTERED between #PROMPT('Fecha_Inicio')# and #PROMPT('Fecha_Final')# and
(E.tbl1_REQM = #PROMPT('Error')# OR #PROMPT('Error')# = '%') and
(E.tbl1_OBJECT = #PROMPT('Equipo')# OR #PROMPT('Equipo')# = '%') and
(O.tbl3_POSITION = #PROMPT('Posicion')# OR #PROMPT('Posicion')# = '%')
And:
SELECT
tbl2_event 'Orden de Trabajo',
STUFF((SELECT ', ' + CAST(tbl2_person AS VARCHAR(100)) [text()]
FROM table2
WHERE tbl2_event = t.tbl2_event
FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)'),1,1,' ') Empleados,
STUFF((SELECT ', ' + CAST(tbl2_hours AS VARCHAR(100)) [text()]
FROM table2
WHERE tbl2_event = t.tbl2_event
FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)'), 1, 1, ' ') Horas
FROM table2 t
GROUP BY tbl2_event
Both work perfectly on their own, but I don't know how to merge them.
Add ROW_NUMBER to each query and then FULL JOIN them together. You'll need to decide on the ordering of rows in each query.
WITH
CTE1
AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY ...) AS rn,
E.tbl1_ORG AS Organización, E.tbl1_CODE AS [Orden de Trabajo],
E.tbl1_OBJECT AS Equipo, O.tbl3_POSITION AS Posicion,
E.tbl1_JOBTYPE AS [Tipo de Trabajo],
E.tbl1_DESC AS [Descripcion OT], E.tbl1_WORKADDRESS AS Comentarios,
E.tbl1_REQM AS Error, B.tbl2_PERSON AS Trabajador,
B.tbl2_ENTERED AS Fecha, B.tbl2_HOURS AS Horas
FROM
dbo.table1 AS E
INNER JOIN
dbo.table2 AS B ON E.tbl1_CODE = B.tbl2_EVENT
INNER JOIN
dbo.table3 AS O ON O.tbl3_CODE = E.tbl1_OBJECT
WHERE
E.tbl1_JOBTYPE IN ('PM', 'CM', 'PMM') and
E.tbl1_ORG = #PROMPT('Organización')# and
B.tbl2_ENTERED between #PROMPT('Fecha_Inicio')# and #PROMPT('Fecha_Final')# and
(E.tbl1_REQM = #PROMPT('Error')# OR #PROMPT('Error')# = '%') and
(E.tbl1_OBJECT = #PROMPT('Equipo')# OR #PROMPT('Equipo')# = '%') and
(O.tbl3_POSITION = #PROMPT('Posicion')# OR #PROMPT('Posicion')# = '%')
)
,CTE2
AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY ...) AS rn,
tbl2_event 'Orden de Trabajo',
STUFF((SELECT ', ' + CAST(tbl2_person AS VARCHAR(100)) [text()]
FROM table2
WHERE tbl2_event = t.tbl2_event
FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)'),1,1,' ') Empleados,
STUFF((SELECT ', ' + CAST(tbl2_hours AS VARCHAR(100)) [text()]
FROM table2
WHERE tbl2_event = t.tbl2_event
FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)'), 1, 1, ' ') Horas
FROM table2 t
GROUP BY tbl2_event
)
SELECT ...
FROM
CTE1 FULL JOIN CTE2 ON CTE1.rn = CTE2.rn
ORDER BY ...
;
If you have more than 2-3 tables to join like this FULL JOIN would quickly become ugly and slow. Have a look at my answer for a similar question for alternative solution: best way to "glue" columns together

many rows into a single column with SQL

I have an one to many table, and if there is rows that have same reference id(Paragraph ID) I want to concatenate so LoginName value have many in same row.
This query does what I want it to do but there is a problem, It replaces first char. the STUFF function requires a replace value.
My question:
How can I do this without replacing first char?
SELECT DISTINCT
ParagraphID
, STUFF((
SELECT N'|' + CAST([LoginName] AS VARCHAR(255))
FROM [dbo].[CM_Signature] f2
WHERE f1.ParagraphID = f2.ParagraphID
FOR XML PATH ('')), 1, 2, '') AS FileNameString
FROM [dbo].[CM_Signature] f1
Expected value:
Daniel | Emma
Here is what you can use:
SELECT DISTINCT
ParagraphID
, STUFF((
SELECT N' | ' + CAST([LoginName] AS VARCHAR(255))
FROM [dbo].[CM_Signature] f2
WHERE f1.ParagraphID = f2.ParagraphID
FOR XML PATH ('')), 1, 1, '') AS FileNameString
FROM [dbo].[CM_Signature] f1
Note the STUFF("...", 1, 1, '') instead of STUFF("...", 1, 2, '').
Because you need to replace 1 char instead of 2 (To remove the first |).
Output:
Daniel|Emma
Also, if you want to have spaces before and after the |, just use this query:
SELECT DISTINCT
ParagraphID
, STUFF((
SELECT N' | ' + CAST([LoginName] AS VARCHAR(255))
FROM [dbo].[CM_Signature] f2
WHERE f1.ParagraphID = f2.ParagraphID
FOR XML PATH ('')), 1, 3, '') AS FileNameString
FROM [dbo].[CM_Signature] f1
Note that this time we removed 3 chars (STUFF("...", 1, 3, '')).
Output:
Daniel | Emma
You were starting your path at position 2 instead of first
SELECT DISTINCT
ParagraphID
, STUFF((
SELECT N'|' + CAST([LoginName] AS VARCHAR(255))
FROM [dbo].[CM_Signature] f2
WHERE f1.ParagraphID = f2.ParagraphID
FOR XML PATH ('')), 1, 1, '') AS FileNameString
FROM [dbo].[CM_Signature] f1 SELECT DISTINCT
ParagraphID
, STUFF((
SELECT N'|' + CAST([name] AS VARCHAR(255))
FROM mytable f2
WHERE f1.paragraphid = f2.paragraphid
FOR XML PATH ('')), 1, 1, '') AS FileNameString
FROM mytable f1
Use this Code:
create table #test (paragraghid int,name VARCHAR(10))
insert into #test values(1929,'Daniel')
insert into #test values(1929,'Emma')
insert into #test values(1935,'Daniel')
select distinct paragraghid,STUFF((select ' | ' + name from #test a
Where a.paragraghid=b.paragraghid for XML PATH('') ),1,2,'') as FilenameString
from #test b
You can write a query as:
DECLARE #CM_Signature table
(
RowId int,
ParagraphID int,
LoginName varchar(10))
Insert into #CM_Signature values
(4,1929,' Daniel'),
(5,1929,' Emma '),
(6,1935,'Daniel')
SELECT DISTINCT
ParagraphID
, STUFF((
SELECT N'| ' + CAST(rtrim(ltrim([LoginName])) AS VARCHAR(255))
FROM #CM_Signature f2
WHERE f1.ParagraphID = f2.ParagraphID
FOR XML PATH ('')), 1, 1, '') AS FileNameString
FROM #CM_Signature f1

sql server comma delimted string values into one row

I have a query that returns a row of multiple Itemcodes. The result is
Date group list of item code
2015-04-15 118 FYCT-00063,FYCM-00016,FYCM-00064,FYCF-00018
it's working fine but i need the result like this, with quotes around every code 'FYCT-00063','FYCM-00016','FYCM-00064','FYCF-00018'
The query is this:
SELECT DISTINCT SS.PostDate,SS.U_Unit,STUFF((
SELECT ', ',+ CAST(OWOR.ItemCode AS VARCHAR(10)) [text()]
FROM OWOR
WHERE OWOR.PostDate=SS.PostDate AND OWOR.U_Unit=SS.U_Unit AND OWOR.Status=SS.Status
FOR XML PATH('') , TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') LISTGroup
from owor SS
Where SS.PostDate='15.APRIL.15' AND SS.U_Unit='Unit No 2' and SS.Status!='C'
SELECT DISTINCT SS.PostDate,SS.U_Unit,
STUFF((
SELECT ', ',+ '''' + CAST(OWOR.ItemCode AS VARCHAR(10) + '''') [text()]
FROM OWOR
WHERE OWOR.PostDate=SS.PostDate
AND OWOR.U_Unit=SS.U_Unit
AND OWOR.Status=SS.Status
FOR XML PATH('') , TYPE) .value('.','NVARCHAR(MAX)'),1,2,' ') LISTGroup
FROM owor SS
WHERE SS.PostDate='15.APRIL.15'
AND SS.U_Unit='Unit No 2'
AND SS.Status!='C'
Try this
SELECT DISTINCT SS.PostDate
,SS.U_Unit
,STUFF((
SELECT ', '
+ QUOTENAME(CAST(OWOR.ItemCode AS VARCHAR(10), ''''))
FROM OWOR
WHERE OWOR.PostDate = SS.PostDate
AND OWOR.U_Unit = SS.U_Unit
AND OWOR.STATUS = SS.STATUS
FOR XML PATH('')
).value('.', 'NVARCHAR(MAX)'), 1, 2, ' ') LISTGroup
FROM owor SS
WHERE SS.PostDate = '15.APRIL.15'
AND SS.U_Unit = 'Unit No 2'
AND SS.STATUS != 'C'
Try like this:
DECLARE #STRING varchar(max)
SELECT #STRING = 'FYCT-00063,FYCM-00016,FYCM-00064,FYCF-00018'
SELECT '''' + REPLACE(#STRING,',',''',''') + ''''
SQLFIDDLE DEMO
In your case it would be like
select distinct SS.PostDate,SS.U_Unit,'''' + REPLACE(STUFF((
SELECT ', ',+ CAST(OWOR.ItemCode AS VARCHAR(10)) [text()]
FROM OWOR
where OWOR.PostDate=SS.PostDate AND OWOR.U_Unit=SS.U_Unit AND OWOR.Status=SS.Status
FOR XML PATH('') , TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' '),',',''',''') + '''' LISTGroup
from owor SS
Where SS.PostDate='15.APRIL.15' AND SS.U_Unit='Unit No 2' and SS.Status!='C'

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 merging cells

I have this tables:
T:
D:
What I am trying to do is to get for each s_id all it's symbols (DBSymbol) in one cell (merge cells).
I have found this tutorial, and here is my code:
select T.s_id,
(select '; ' + D.symbol
from D
where T.D_b_id = D.id
FOR XML PATH('')) [DBSymbol]
from T
but here is what I am getting:
What is wrong??
Try this -
SELECT t1.s_id,
STUFF(
(SELECT '; ' + symbol AS [text()]
FROM (
SELECT t.s_id,
d.symbol
FROM T
INNER JOIN D ON T.d_b_id = D.id
WHERE t.s_id = t1.s_id
) x
FOR XML PATH('')
), 1, 1, '')
FROM T t1
GROUP BY t1.s_id
Check it: SQL Fiddle
select DISTINCT T.s_id,
Stuff((SELECT DISTINCT '; ' + D.symbol
from D
--where T.D_b_id = D.id
FOR XML PATH('')),1,1,'') [DBSymbol]
from T
Example here