I have a table variable #Holding two columns: an id (not unique) and a message:
id message
---- -------
2 give
2 me
2 help
3 Need
3 help
1 help!
The result should be
2 give me help
3 Need help
1 help!
This it very much simplified, but shows that there are id which may exist more than once, and some kind of text which should be concatenated into a string.
I cannot manage it to loop through this table variable (but not through a table too!).
I tried a cursor (which I did not understand correctly) but it failed of course.
The number of records are not that much, not even 100 in that table variable.
Thanks yr. help
Michael
Original question
No CURSOR, WHILE loop, or User-Defined Function needed.
Just need to be creative with FOR XML and PATH.
[Note: This solution only works on SQL 2005 and later. Original question didn't specify the version in use.]
CREATE TABLE #YourTable ([ID] INT, [Name] CHAR(1), [Value] INT)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'A',4)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'B',8)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (2,'C',9)
SELECT
[ID],
STUFF((
SELECT ', ' + [Name] + ':' + CAST([Value] AS VARCHAR(MAX))
FROM #YourTable
WHERE (ID = Results.ID)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS NameValues
FROM #YourTable Results
GROUP BY ID
DROP TABLE #YourTable
This should work if you are using SQL Server.
select T1.id,
stuff((select ' '+T2.[message]
from #A as T2
where T1.id = T2.id
for xml path(''), type).value('.', 'varchar(max)'), 1, 1, '') as [message]
from #A as T1
group by T1.id
Pretty the same, just less letters in the code:
DECLARE #t AS TABLE ( id INT, msg VARCHAR(100) );
INSERT INTO #t
VALUES ( 2, 'give' );
INSERT INTO #t
VALUES ( 2, 'me' );
INSERT INTO #t
VALUES ( 2, 'help' );
INSERT INTO #t
VALUES ( 3, 'Need' );
INSERT INTO #t
VALUES ( 3, 'help' );
INSERT INTO #t
VALUES ( 1, 'help!' );
SELECT DISTINCT
id ,
(
SELECT ST1.msg + ' '
FROM #t ST1
WHERE ST1.id = ST2.id
FOR XML PATH('')
) t
FROM
#t ST2;
Related
Create Table #temp
(
Change varchar(20),
deleted_user_id int,
deleted_field_id int,
deleted_value nvarchar (4000),
inserted_user_id int,
inserted_field_id int,
inserted_value nvarchar (4000),
is_difference int,
)
insert into #temp values ('UPDATE','1', '11', '3,2,1,4','1','11','1,2,3,4','0')
insert into #temp values ('UPDATE','1', '12', '','1','12','1,2,3','0')
insert into #temp values ('UPDATE','2', '12', '1,2','2','12','','0')
select * from #temp
I am using Microsoft SQL server management studio
I am trying to compare the deleted value with inserted value. if there is a difference then set is_difference column to 1 or just return the rows.
so far I am thinking to do string split. maybe use stuff function. but not quite sure how to use all these to in a single query or is there any other option. Any help is appreciated. Thanks in advance
this query works so far.
;with cte as
(select isnull(deleted_user_id, inserted_user_id) as user_id,
isnull(deleted_field_id, inserted_field_id) as field_id,
stuff(
(
SELECT ','+ value FROM STRING_SPLIT (deleted_value, ',') group by value order by value FOR XML PATH('')
),1,1,'') as sorted_deleted_value , inserted_value
from #temp )
select * from cte where sorted_deleted_value <> inserted_value
If I have a team table with a unknown amount of members, is there a way to make the pivot query dynamic?
create table #t (
team varchar (20), member varchar (20)
)
insert into #t values ('ERP', 'Jack')
insert into #t values ('ERP', 'John')
insert into #t values ('ERP', 'Mary')
insert into #t values ('ERP', 'Tim')
insert into #t values ('CRM', 'Robert')
insert into #t values ('CRM', 'Diana')
select * from #t
select team, [1] as teamMember1, /* 1st select */
[2] as teamMember2, [3] as teamMember3
from
(select team , member, row_number () /* 3rd select */
over (partition by team order by team) as rownum
from #t) a
pivot (max(member) for rownum in ([1], [2], [3])) as pvt
drop table #t
Why yes, yes there is. Here's a script I cooked up years ago for a similar problem that was ultimately solved by giving the user Excel and washing my hands of it. I apologize it's not configured with your example data, but hopefully it's easy to follow.
Hope that helps,
John
--------------START QUERY--------------
-- Example Table
CREATE TABLE #glbTestTable
(
ProviderID INT,
Total INT,
PaymentDate SMALLDATETIME
)
--So the dates insert properly
SET DATEFORMAT dmy
-- Populate Example Table
INSERT INTO #glbTestTable VALUES (232, 12200, '12/01/09')
INSERT INTO #glbTestTable VALUES (456, 10200, '12/01/09')
INSERT INTO #glbTestTable VALUES (563, 11899, '02/03/09')
INSERT INTO #glbTestTable VALUES (221, 5239, '13/04/09')
INSERT INTO #glbTestTable VALUES (987, 7899, '02/03/09')
INSERT INTO #glbTestTable VALUES (1, 1234, '02/08/09')
INSERT INTO #glbTestTable VALUES (2, 4321, '02/07/09')
INSERT INTO #glbTestTable VALUES (3, 5555, '02/06/09')
-- Raw Output
SELECT *
FROM #glbTestTable
-- Build Query for Pivot --
DECLARE #pvtColumns VARCHAR(MAX)
SET #pvtColumns = ''
-- Grab up to the first 1023 "Columns" that we want to use in Pivot Table.
-- Tables can only have 1024 columns at a maximum
SELECT TOP 1023 #pvtColumns = #pvtColumns + '[' + CONVERT(VARCHAR, PaymentDate, 103) + '], '
FROM (SELECT DISTINCT PaymentDate FROM #glbTestTable) t_distFP
-- Create PivotTable Query
DECLARE #myQuery VARCHAR(MAX)
SET #myQuery = '
SELECT ProviderID, ' + LEFT(#pvtColumns, LEN(#pvtColumns) - 1) + '
FROM (SELECT ProviderID, PaymentDate, Total
FROM #glbTestTable) AS SourceTable
PIVOT
(
SUM(Total)
FOR PaymentDate IN (' + LEFT(#pvtColumns, LEN(#pvtColumns) - 1) + ')
) AS PivotTable'
-- Run the Pivot Query
EXEC(#myQuery)
-- Cleanup
DROP TABLE #glbTestTable
---------------END QUERY---------------
This is my table
create table #t(id varchar(10),value varchar(10))
insert into #t values('0001','a'),('0001','b'),('0002','c'),('0002','d')
I need a efficient method of making csv
id value
0001 a,b
0002 c,d
try this!
using Stuff with xml path('')
select id,
stuff(
(
select ',' + value from #t t1 where t1.id=t2.id for xml path(''),type).value('.','varchar(max)'),1,1,'') from #t t2
group by t2.id
Hello below given requirement both columns are in VARCHAR . So we can use SUBSTRING FUNCTION and CROSS APPLY to get Expected output
DECLARE #t TABLE (ID VARCHAR(10) ,VALUE VARCHAR(10) )
INSERT INTO #t (ID,VALUE)VALUES ('0001','a')
INSERT INTO #t (ID,VALUE)VALUES ('0001','b')
INSERT INTO #t (ID,VALUE)VALUES ('0002','c')
INSERT INTO #t (ID,VALUE)VALUES ('0002','d')
INSERT INTO #t (ID,VALUE)VALUES ('0003','e')
INSERT INTO #t (ID,VALUE)VALUES ('0003','f')
SELECT [Id],
SUBSTRING(d.Value,1, LEN(d.Value) - 1) VALUE
FROM
(
SELECT DISTINCT [Id]
FROM #t
) a
CROSS APPLY
(
SELECT Value + ', '
FROM #t AS B
WHERE A.[Id] = B.[Id]
FOR XML PATH('')
) D (Value)
I have a database table with a column METADATA. This METADATA may or may not contain a string. Here's the sample string:
StudentID:1234,StudentName:TestName,StudentNickName:TestNName,StudentLevel:5
Now, I want to extract the StudentNickName:TestName if it exists. Please note of the following constraint:
METADATA column doesn't always contain a value
METADATA column can contain a value without the StudentNickName clause
The StudentNickName: is fixed, while the TestNName varies per row.
For mssql 2005+
declare #t table(metadata varchar(200))
insert #t values('StudentID:1234,StudentName:TestName,StudentNickName:TestNName,StudentLevel:5')
insert #t values('')
insert #t values('StudentID:1234,StudentName:Thomas,StudentNickName:Tom,StudentLevel:3')
select left(b.a, patindex('%_,%', b.a)) StudentNickName
from #t t cross apply
(select right(metadata, patindex('%_:emaNkciNtnedutS%'
, reverse('X'+ metadata)))+',' a) b
Result:
StudentNickName
---------------
TestNName
Tom
Works in Sql Server
DECLARE #test TABLE(metadata VARCHAR(200))
INSERT #test VALUES('StudentID:1234,StudentName:TestName,StudentNickName:TestNName,StudentLevel:5')
INSERT #test VALUES('StudentID:1235,StudentName:TestName1,StudentNickName:TestNName1,StudentLevel:6')
INSERT #test VALUES('StudentID:1236,StudentName:TestName2,StudentNickName:TestNName2,StudentLevel:2')
INSERT #test VALUES('')
SELECT split.s.value('.','VARCHAR(100)') as colname FROM
(
SELECT CAST('<s>' + REPLACE(metadata,',','</s><s>') + '</s>' AS XML) col FROM #test
) AS t CROSS APPLY col.nodes('/s') AS split(s)
WHERE split.s.value('.','VARCHAR(100)') LIKE '%StudentNickName%'
Below I have shown two tables and also the result table.
How can I get the result table in this manner as I shown on above?
select min(ID) as ID,
Val,
stuff((select ','+Cat
from Table2 as T2
where T1.Val = T2.Val
for xml path(''), type).value('.', 'nvarchar(max)'), 1, 1, '') as Cat
from Table2 as T1
group by Val
order by ID
SQL Fiddle
DECLARE #Table1 TABLE
(
id INT
,Val VARCHAR(100)
)
DECLARE #Table2 TABLE
(
id INT
,Val VARCHAR(100)
,Cat VARCHAR(100)
)
INSERT INTO #Table1
VALUES(1,'XYZ')
INSERT INTO #Table1
VALUES(2,'abc')
INSERT INTO #Table2
VALUES(1,'XYZ','a')
INSERT INTO #Table2
VALUES(1,'abc','e')
INSERT INTO #Table2
VALUES(1,'XYZ','b')
INSERT INTO #Table2
VALUES(1,'XYZ','f')
INSERT INTO #Table2
VALUES(1,'abc','g')
SELECT t1.id,t1.Val ,( SELECT STUFF((SELECT ',' + cat FROM #Table2 t2 WHERE t2.Val = t1.val FOR XML PATH('')),1,1,''))
FROM #Table1 t1
You can define a CLR user-defined aggregate to do it. I posted a detailed description of such a solution as an answer to another question - TSQL Comma Separation. There you'll also find a link to a blog post that discusses the problems you may encounter while developing a CLR aggregate.
After you deploy the custom aggregate to the server (I named the function Concat but yours may be named differently), you will be able to obtain the required result with the following query:
SELECT Val, dbo.Concat(Cat)
FROM Table2
GROUP BY Val