I am trying to Parse Table data into JSON and in the process want to skip the Table Column Names in the Post conversion to JSON. Below is the sample Snippet.
DECLARE #table1 TABLE (k1 nvarchar(max), v1 nvarchar(max))
-- Note k1 is unique
INSERT INTO #table1 (k1,v1) VALUES( 'Apple', 'One')
INSERT INTO #table1 (k1,v1) VALUES( 'Banana', 'Two')
INSERT INTO #table1 (k1,v1) VALUES( 'Orange', 'Three')
SELECT k1, v1 FROM #table1
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
--output: {"k1":"Apple","v1":"One"},{"k1":"Banana","v1":"Two"},{"k1":"Orange","v1":"Three"}
-- Expected: {"Apple","One"},{"Banana","Two"},{"Orange","Three"}
Appreciate direction!
--string concatenation&aggregation (string_agg() for sql2017&later or for xml path() for sql2016)
select string_agg(concat('{"', string_escape(k1, 'json'), '":"', string_escape(v1, 'json'), '"}'), ',') /*within group (order by k1)*/
from #table1
Related
create table #t(org varchar(50), area int)
insert into #t values ('a', 500), ('b', 200), ('c', 400)
select * from #t
Output:
org area
--------------
a 500
b 200
c 400
I want to convert the output to this format:
org area
-----------------
a,b,c 1100
i.e. comma-separated all the orgs and sum of it's area value.
Sub-query is really not necessary :
select stuff((select ','+t1.org from #t t1 for xml path('')), 1, 1, '') as org,
sum(area) as area
from #t t;
Use a SubQuery/CTE, a window function SUM() OVER(), and STRING_AGG()
create table #t(org varchar(50), area int)
insert into #t values ('a',500),('b',200),('c',400);
select string_agg(org, ',') org, area
from
(
select org, sum(area) over() area
from #t
)t
group by area
or
select org, sum(area) area
from
(
select stuff(
(select ',' + org from #t for xml path('')), 1, 1, '') org, area
from #t tt
) t
group by org
If use sql server upper than 2017, you can use String_agg()
create table #t(org varchar(50), area int)
insert into #t values ('a',500),('b',200),('c',400)
select String_agg(org, ',') as org, Sum(area) as sumarea
from #t
You can use the following query in two parts as shown below.
In the first part get all the values in the comma-separated and in a final query select the sum of all the values of the area.
create table #t(org varchar(50), area int)
insert into #t values ('a', 500), ('b', 200), ('c', 400)
DECLARE #List VARCHAR(8000)
SELECT #List = COALESCE(#List + ',', '') + org
FROM #t --For getting values in comma separated
SELECT #List as AllValues
, sum(area) as Total
from #t
Live db<>fiddle demo.
I have a temp table with one column of xml type.
How can I write a single SELECT query to list all unique values of attribute 'z'
CREATE TABLE #TEST3 ([Data] XML)
INSERT INTO #TEST3 VALUES ('<r><a z="1" /> <a z="2" /></r>')
INSERT INTO #TEST VALUES ('<r><b z="2" /><b z="3" /></r>')
INSERT INTO #TEST3 VALUES ('<r><c z="3"><c z="4" /></c></r>')
Select
Distinct t.m.value( '#z[1]', 'varchar(max)' ) ZAttribute
From
#Test3 tempTable
Cross Apply tempTable.Data.nodes( '/your/node/path/here' ) t(m)
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;
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
I have a simple problem , Although i believe its simple , am not able to figure out the same.
Consider i have the below table with exactly same data as given below :
CREATE TABLE #temp
(
link varchar(255),
number INT,
fname varchar(255)
)
insert into #temp VALUES ('abc',1,'f1')
insert into #temp VALUES ('abc',2,'f2')
insert into #temp VALUES ('abc',3,'f3')
insert into #temp VALUES ('abc',4,'f6')
insert into #temp VALUES ('abc',10,'f100')
insert into #temp VALUES ('abe',-1,'f0')
insert into #temp VALUES ('abe',1,'f1')
insert into #temp VALUES ('abe',2,'f2')
insert into #temp VALUES ('abe',3,'f3')
insert into #temp VALUES ('abe',4,'f6')
insert into #temp VALUES ('abe',20,'f200')
insert into #temp VALUES ('cbe',-1,'f0')
insert into #temp VALUES ('cbe',1,'f1')
insert into #temp VALUES ('cbe',2,'f2')
insert into #temp VALUES ('cbe',3,'f3')
Now for a given link , i need to get the max 'number' and the corresponding 'fname' which has the max 'number' for the given 'link'.
1)Ex : if link is 'abc' , output should be
abc, 10, f100
2)Ex : if link if 'abe' , Output should be
abe, 20, f200
3)Now link can be also given as a pattern , like (link like 'ab%') , so output should be
abc, 10, f100
abe, 20, f200
4)if (link like 'cb%') , so output should be
cbe, 3, f3
Any help in writing this group by query. I have a solution using CAST and string concat like below , but that seems to be in-efficient.
select link,number,fname from #temp
where link like 'ab%' and link+'_'+CAST(number AS varchar(255))
in (select link+'_'+CAST(MAX(number) AS varchar(255)) from #temp
group by link)
Thanks..
Using a self join:
SELECT x.link,
x.number,
x.fname
FROM #temp x
JOIN (SELECT t.link,
MAX(t.number) AS max_number
FROM #temp t
GROUP BY t.link) y ON y.link = x.link
AND y.max_number = x.number
Using a CTE and ROW_NUMBER (SQL Server 2005+):
WITH cte AS (
SELECT x.link,
x.number,
x.fname,
ROW_NUMBER() OVER(PARTITION BY x.link
ORDER BY x.number DESC) rank
FROM #temp x)
SELECT c.link,
c.number,
c.fname
FROM cte c
WHERE c.rank = 1