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

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 '))

Related

MS SQL Server - concatenating in a particular way

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

How can I join together this querys sql server?

SQL FIDDLE DEMO HERE
I have this table structure for Workers table:
CREATE TABLE Workers
(
[Name] varchar(250),
[IdWorker] varchar(250),
[work] varchar(250)
);
INSERT INTO Workers ([Name], [IdWorker], [work])
values
('Sam', '001', 'Director'),
('Julianne', '002', 'Recepcionist'),
('Jose', '003', 'Recepcionist');
What I want is to get for each job the name of workers separate by commas, like this:
Director Recepcionist
------- ------------
Sam Julianne, Jose
I tried to used this query:
DECLARE #rec VARCHAR(MAX)
SELECT #rec = COALESCE(#rec + ', ', '') + Name from
Workers where job = 'Recepcionist' SELECT #dir AS Recepcionist
And I got this result:
Recepcionist
------------
Julianne, Jose
This works only for one job, but I need to add more, so I tried then to use this query:
SELECT [Director] , [Recepcionist]
FROM
(SELECT [job], [Name],RANK() OVER (PARTITION BY [job] ORDER BY [job],[Name]) as rnk
FROM Workers ) p
PIVOT(
Min([Name])
FOR [job] IN
( [Director] , [Recepcionist] )
) AS pvt
And I get this result:
Director Recepcionist
-------- ------------
Sam Julianne
Jose
I need to get the results in the same row separate by commas, how can I combine the two querys?
I accept suggestions, thanks.
I am assuming in your example query you meant job to reference the work column. The following query should do the job as per your sql fiddle.
SELECT STUFF(
(
SELECT ', ' + cast([Name] as varchar(max))
FROM Workers
WHERE [work] = 'Recepcionist'
FOR XML PATH('')
), 1, 2, ''
) AS Recepcionist
,STUFF(
(
SELECT ', ' + cast([Name] as varchar(max))
FROM Workers
WHERE [work] = 'Director'
FOR XML PATH('')
), 1, 2, '') AS Director;
the way you would do this using PIVOT would be like this.
SELECT *
FROM (SELECT [work],
STUFF((SELECT ', ' + [Name]
FROM Workers s
WHERE s.WORK = w.WORK
FOR XML PATH('')),
1, 2, '') AS [workers]
FROM Workers w) t
PIVOT (
MAX([workers])
FOR [work] IN ([Director], [Recepcionist])
) p
another alternative to PIVOT is MAX(CASE)
SELECT MAX(CASE WHEN [work] = 'Director' THEN [workers] END) AS [Director],
MAX(CASE WHEN [work] = 'Recepcionist' THEN [workers] END) AS [Recepcionist]
FROM (SELECT [work],
STUFF((SELECT ', ' + [Name]
FROM Workers s
WHERE s.WORK = w.WORK
FOR XML PATH('')),
1, 2, '') AS [workers]
FROM Workers w) t
both of these allow you to separate the data by other fields like Company or Department
you can do it like this
SELECT
t1.job
,STUFF(
(SELECT
', ' + t2.Name
FROM Workers t2
WHERE t1.job =t2.job
ORDER BY t2.Name
FOR XML PATH(''), TYPE
).value('.','varchar(max)')
,1,2, ''
) AS ChildValues
FROM Workers t1
GROUP BY t1.job

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

Have all Records in one Field

how is possible to have all records of one field into one field
Id, No , FDevice
1 , 1 , 'A'
2 , 1 , 'B'
3 , 1 , 'C'
4 , 2 , 'D'
5 , 2 , 'E'
I want to have
No , FDevice
1 , A-B-C
2 , D-E
Thank you for your help
use STUFF() - which inserts a string into another string.
SELECT
[No],
STUFF(
(SELECT '-' + [FDevice]
FROM TableName
WHERE [No] = a.[No]
FOR XML PATH (''))
, 1, 1, '') AS FDevice
FROM TableName AS a
GROUP BY [No]
SQLFiddle Demo
There're a well-known solution for aggregate concatenation in SQL Server, using select ... for xml path(''), but I have to say that many people using it incorrectly. Correct way to do this would be
select
a.[No],
stuff(
(
select '-' + t.[FDevice]
from TableName as t
where t.[No] = a.[No]
for xml path(''), type
).value('.', 'nvarchar(max)')
, 1, 1, '') as FDevice
from (select distinct [No] from TableName) as a;
sql fiddle demo
The main part is to use xml type inside the query and then to convert it into varchar using value function, otherwise you can end up with incorrectly converted special chars like '>', '<', '&' and so on. SQLfiddle somehow doesn't show the difference, but here's a script which can show you what can happen if you don't use xml type:
declare #TableName table
([Id] int, [No] int, [FDevice] varchar(3))
;
INSERT INTO #TableName
([Id], [No], [FDevice])
VALUES
(1, 1, 'A<'),
(2, 1, 'B'),
(3, 1, '&C'),
(4, 2, 'D'),
(5, 2, 'E')
;
SELECT
[No],
STUFF(
(SELECT '-' + [FDevice]
FROM #TableName
WHERE [No] = a.[No]
FOR XML PATH (''))
, 1, 1, '') AS FDevice
FROM #TableName AS a
GROUP BY [No];
outputs
No FDevice
--------------------
1 A<-B-&C
2 D-E
select
a.[No],
stuff(
(
select '-' + t.[FDevice]
from #TableName as t
where t.[No] = a.[No]
for xml path(''), type
).value('.', 'nvarchar(max)')
, 1, 1, '') as FDevice
from (select distinct [No] from #TableName) as a;
outputs
No FDevice
--------------------
1 A<-B-&C
2 D-E

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