How to combine string in one column based on grouping - sql

I have a table has data like this
And want to combine the job which has same template in one column, like this
I try to use FOR XML PATH
select t.JBTemplate,
Stuff(
(SELECT N', ' + Contract FROM Table1 FOR XML PATH(''),TYPE)
.value('text()1','nvarchar(max)'),1,2,N'') Job
from Table1 t
group by t.JBTemplate, Contract
However, it combine all job for each template.

Please try this:
IF (OBJECT_ID('tempdb..#my_job_template') IS NOT NULL)
BEGIN
DROP TABLE #my_job_template
END;
CREATE TABLE #my_job_template (JCCO INT NOT NULL, [Contract] nvarchar(max) NULL, [JBTemplate] nvarchar(max) NULL);
INSERT INTO #my_job_template(JCCO, [JBTemplate], [Contract])
VALUES (17, 'Ascend AL', '601226.17')
,(17, '1192-10803', '601236.17')
,(17, 'P66_4Sites', '600948.17')
,(17, 'P66_4Sites', '601219.17')
,(17, 'P66_4Sites', '601234.17')
--select * from #my_job_template
SELECT [JCCO]
, [JBTemplate]
,STUFF((SELECT ', ' + CAST([Contract] AS VARCHAR(MAX)) [text()]
FROM #my_job_template
WHERE [JBTemplate] = t.[JBTemplate]
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') [Contract]
FROM #my_job_template t
GROUP BY [JBTemplate] , [JCCO]

Related

Execute create table query from column in SQL server

I have two select statements which are to create table and insert values into table. How to execute all the queries inside the column at one go? Below is my code and the output:
select n.*
into #norm
from specNormalization n
select n.*
into #raw
from rawdata n
select distinct 'CREATE TABLE raw' + c.desttablename + ' (' + STUFF(
(select ','+QUOTENAME( c.[destfieldname] ) + c.datatype
from #norm c
group by c.destfieldname, c.datatype
for xml path ('')),1,1,'') as createTableSQL
select distinct 'INSERT INTO raw' + c.desttablename +
select d.contents
from #raw d join #norm c on d.tablename = c.desttablename
as insertTableSQL
rawdata table
desttablename
destfieldname
datatype
rawtable
SbjNum
int
rawtable
Surveyor
nvarchar(20)
rawtable
Location
nvarchar(20)
rawtable2
SbjNum
int
rawtable2
Name
nvarchar(20)
rawtable2
Address
nvarchar(20)
specnomalization table
tablename
destfieldname
contents
rawtable
SbjNum
1
rawtable
Surveyor
Alex
rawtable
Location
Georgia
rawtable2
SbjNum
1
rawtable2
Name
Sandra
rawtable2
Address
Portland
createTableSQL
CREATE TABLE rawtable ([Sbjnum])int, ([Surveyor])nvarchar(200), ([Location])nvarchar(200)
CREATE TABLE rawtable2 ([Sbjnum])int, ([Name])nvarchar(200), ([Address])nvarchar(200)
insertTableSQL
INSERT INTO rawtable SELECT [Sbjnum], [Surveyor], [Location] from #raw
INSERT INTO rawtable2 SELECT [Sbjnum], [Name], [Address] from #raw
You can create the create query by using stuff. Since you would have multiple tables so you have to group by the query to return multiple table names and it's columns separately. So the result query you can set into a variable and can execute by using
EXEC sp_executesql
So you can easily create as much as tables based on your table data.
The following query will help you to create multiple tables. This you can optimize if needed, but this will give you the insight to do the same for inserting values to the tables respectively.
Declare #sql nvarchar(MAX) = ( SELECT ' CREATE TABLE '+ desttablename +' (' + STUFF((SELECT ', ' + sn.[destfieldname] + ' ' +datatype
FROM dbo.specNormalization As sn
ORDER BY sn.destfieldname
FOR XML PATH(''), TYPE).value('.[1]', 'varchar(max)'), 1, 2, '') + ' )'
FROM dbo.specNormalization as P2
GROUP BY P2.desttablename FOR XML PATH('') )
-- Uncomment to see the created query
-- SELECT #sql
-- To execute the created query. This will create the tables with column and datatype
EXEC sp_executesql #sql
Hope this helps. Happy coding :)
Too long for a comment. Try to generate SELECT .. INTO .. FROM to create and populate a target table. Kind of
SELECT cast([Sbjnum] as int) [Sbjnum], cast([Surveyor] as nvarchar(200)) [Surveyor], cast([Location] as nvarchar(200)) [Location]
INTO rawtable
FROM #raw
If the source types are the same as target, skip cast functions. Can't tell what is the query to generate it as no sample data are provided.

Merge column value based on another column value - TSQL

I m using the below query to merge column Message based on column 'Customer_Name' from table Customers
SELECT
[Customer_Name],
STUFF((SELECT
', ' + LTRIM(RTRIM([Message]))
FROM [dbo].[Customers] t2
WHERE t2.[Customer_Name] = t1.[Customer_Name]
FOR XML PATH ('')), 1, 1, '')
FROM [dbo].[Customers] t1
GROUP BY [Customer_Name]
Using the above code, the Message are separated by , but i want a new line. i try to use CHAR(13)+CHAR(10) but i getting #x0D; and the merge column seems to be wrong.
Any idea on how to fix it will greatly appreciate.
Answer using #Larnu help and posts on comments
SELECT
[Customer_Name],
STUFF((SELECT
(CHAR(13) + CHAR(10)) + LTRIM(RTRIM([Message]))
FROM [Customers] t2
WHERE t2.[Customer_Name] = t1.[Customer_Name]
FOR XML PATH (''),TYPE
).value('(./text())[1]','varchar(MAX)'),1,2,'')
FROM [Customers] t1
GROUP BY [Customer_Name]
Your solution use xml serialization .
#x0D; is xml serialization of char(13)
If you use at least SQL Server 2017 you can use STRING_AGG function
SELECT
[Customer_Name],
STRING_AGG([Message],', ') as [Messages]
FROM [dbo].[Customers] t1
GROUP BY [Customer_Name]
otherwise you can add replace.
SELECT
[Customer_Name],
REPLACE(
STUFF((SELECT
', ' + LTRIM(RTRIM([Message]))
FROM [dbo].[Customers] t2
WHERE t2.[Customer_Name] = t1.[Customer_Name]
FOR XML PATH ('')), 1, 2, ''),
'#x0D;',
CHAR(13)) as [Messages]
FROM [dbo].[Customers] t1
GROUP BY [Customer_Name]
The correct method to prevent XML entitization is actually to generate it as the xml data type using the TYPE option, then pull it back out with .value
DECLARE #sep NVARCHAR(10) = ', '; -- or you can use CHAR(13)+CHAR(10)
SELECT
[Customer_Name],
STUFF(
(SELECT #sep + LTRIM(RTRIM([Message]))
FROM [dbo].[Customers] t2
WHERE t2.[Customer_Name] = t1.[Customer_Name]
FOR XML PATH (''), TYPE
).value('text()[1]','nvarchar(max)'), 1, LEN(#sep), '')
FROM [dbo].[Customers] t1
GROUP BY [Customer_Name]

In SQL Server - How do I combine all rows where the RecID is the same, with CR/LF?

I need to combine rows where Recid is the same, but using a carriage return/linefeed between row values, rather than a comma.
See example data below:
create table #Temp
(
Companyid nvarchar(2),
Recid nvarchar(1),
Notes nVarchar(max)
)
insert into #Temp
Values (
'A','1','NotesA1'),
('A','1','NotesA11'),
('A','1','NotesA111'),
('A','2','NotesA2'),
('A','2','NotesA22'),
('B','1','NotesB1')
select Recid, Notes from #Temp where Companyid='A'
drop table #Temp
How do I end up with the below:
Recid Notes
1 NotesA1
NotesA11
NotesA111
2 NotesA2
NotesA22
I have tried using the following but it returns semi-colons between values:
create table #Temp
(
Companyid nvarchar(2),
Recid nvarchar(1),
Notes nVarchar(max)
)
insert into #Temp
Values (
'A','1','NotesA1'),
('A','1','NotesA11'),
('A','1','NotesA111'),
('A','2','NotesA2'),
('A','2','NotesA22'),
('B','1','NotesB1')
SELECT dr.Recid,
STUFF((SELECT '; ' + cast(US.notes as nvarchar(max))
FROM #Temp US
WHERE US.Recid = DR.Recid and us.COMPANYID='A'
FOR XML PATH('')), 1, 1, '') [Notes]
FROM #Temp DR
where (dr.Companyid='A')
GROUP BY DR.Recid
ORDER BY dr.Recid
drop table #Temp
Returns:
Recid Notes
1 NotesA1;NotesA11;NotesA111
2 NotesA2;NotesA22
Cheers for all help!
You were very close. A Carriage return is ASCII character 13 and the Line break is 10, so be represented by CHAR(13) & CHAR(10) (or NCHAR(13) & NCHAR(10) for an nvarchar). Because of the way XML works, some characters might be escaped (specifally the linebreak would be shown as '&#x0D'). Therefore I prefer to use the TYPE keyword and then extract the values by using the value XML functionality (something I was only introduced to this year):
SELECT DR.Recid,
STUFF((SELECT NCHAR(13) + NCHAR(10) + CAST(US.Notes AS nvarchar(MAX))
FROM #Temp AS US
WHERE US.Recid = DR.Recid
AND US.Companyid = 'A'
FOR XML PATH(N''),TYPE).value(N'.','nvarchar(MAX)'),1,2,N'') AS [Notes]
FROM #Temp AS DR
WHERE (DR.Companyid = 'A')
GROUP BY DR.Recid
ORDER BY DR.Recid;

With IN Clause when Passing Collection as Parameter In Sql Server

Query Gives O/p as
ItemSizeNM
(colName)
'U','V','X','Y'
But when I used this as input to IN Query in the Code Which I did.
It Doesn't Gives same resultset. Why This Happens...?
Table MstItemSize Has Proper Data.
declare #tblRingSize table ( ringSize varchar(100))
declare #ringSize varchar(100)
select #ringSize= cast((otherringSize) as varchar)
from ##tempBand where styleNo='BD00002';
INSERT INTO #tblRingSize SELECT Item FROM dbo.SplitStrings_CTE (#ringSize, ',');
select ItemSizeNm from MstItemSize where SizeTypeNm ='Ring' and
ItemSizeNm
in --('U','V','X','Y')
( select Replace (
(select STUFF( (select ''',''' + ringSize from #tblRingSize For XML PATH('')),1,2,'') +'''' )
,' ',''))
select Replace (
(select STUFF( (select ''',''' + ringSize from #tblRingSize For XML PATH('')),1,2,'') +'''' )
,' ','')
You don't need to use STUFF, FOR XML, or REPLACE for the subquery:
select
ItemSizeNm
from
MstItemSize
where SizeTypeNm ='Ring'
and ItemSizeNm in (select ringSize from #tblRingSize)

Flatten SQL Server Table to a string

I have a table like:
ID | Value
----------------
1 | One
2 | Two
3 | Three
What I need to do is create a single string from these values, in the format:
'1: One, 2: Two, 3: Three'
I know how to do this using cursors, but it will be used as a column in a view, so it's not really a performant option.
Any pointers?
WITH T(ID,Value) AS
(
SELECT 1, 'One' UNION ALL
SELECT 2, 'Two' UNION ALL
SELECT 3, 'Three'
)
SELECT STUFF(
(SELECT ', ' + CAST(ID as varchar(11)) + ': ' + Value
FROM T
FOR XML PATH (''))
, 1, 2, '')
Have a look at something like
DECLARE #Table TABLE(
ID INT,
Value VARCHAR(20)
)
INSERT INTO #Table SELECT 1,'One'
INSERT INTO #Table SELECT 2,'Two'
INSERT INTO #Table SELECT 3,'Three'
SELECT STUFF(
(
SELECT ', ' + CAST(ID AS VARCHAR(MAX)) + ': ' + Value
FROM #Table
FOR XML PATH(''), TYPE
).value('.','varchar(max)')
,1,2, ''
)
SELECT STUFF((
SELECT ' ' + CAST(ID AS VARCHAR(2)) + ': '+ Value
FROM dbo.Table
FOR XML PATH('')
), 1, 1, ''
) As concatenated_string
DECLARE #ans VARCHAR(max)
SET #ans=''
SELECT #ans = #ans + str(id)+':'+value FROM table
SELECT #ans
Change the max to 8000 if your version of SQL doesn't support it
I would simply not do this in the database if at all possible. It's not designed for formatting data in a certain way; let the calling application handle that.
In C# (assuming data is an instance of SqlDataReader):
var l = new List<string>();
while (reader.Read())
l.Add(string.Format("{0}: {1}", reader[0], reader[1]));
var s = string.Join(", ", l.ToArray());