1

I have a table (it's not a table for real but a result of another query) like this:

ID | NAME | OPTIONAL_ID | OPTIONAL_NAME | OTHER FIELDS
1  | abc  | 34          | optional 1    | ...
1  | abc  | 35          | optional 2    | ...
1  | abc  | 36          | optional 3    | ...
1  | abc  | 37          | optional 4    | ...
2  | qwe  | 34          | optional 1    | ...
2  | qwe  | 35          | optional 2    | ...
2  | qwe  | 36          | optional 3    | ...

What I need is to get a different result with a record for every object, in this example 'abc' and 'qwe' and a Column like OPTIONALS that contains all optional_name for each object.

It's not important for me the output type ( JSON,XML, query output)

I tried with 'group by' but i didn't get the desired result.

5
  • 1
    Columns, not fields... Commented Feb 13, 2018 at 9:32
  • 1
    could you show us desired output? Commented Feb 13, 2018 at 9:34
  • I guess you want something like abc | optional 1, optional 2, optional 3, optional 4, do you? Commented Feb 13, 2018 at 9:42
  • A column like that for each object: OPTIONALS optional1,optional2,optional3 or in JSON: {id:1,Name:'abc',Optionals:['optional1','optional2','optional3','optional4']} {id:2,Name:'qwe',Optionals:['optional1','optional2','optional3']} Commented Feb 13, 2018 at 9:44
  • @MichałTurczyn yes, I do. Commented Feb 13, 2018 at 9:46

3 Answers 3

1

Try this (I considered only relevant columns):

declare @table table (name char(3), optional_name char(10))
insert into @table values
('abc', 'optional 1'),
('abc', 'optional 2'),
('abc', 'optional 3'),
('abc', 'optional 4'),
('qwe', 'optional 1'),
('qwe', 'optional 2'),
('qwe', 'optional 3')

select name,
       (select optional_name from @table where name = T.name for xml path(''), type)
from @table [T]
group by name

If you want JSON, then replace XML with JSON in last query (newest SQL Server required).

Another option (slightly modified previous query):

select name,
       (select optional_name + ', ' from @table where name = T.name for xml path(''), type).value('(/)[1]','varchar(2000)') [optional_name]
from @table [T]
group by name
Sign up to request clarification or add additional context in comments.

2 Comments

this query returns to me all records with the optionals column but not in distinct mode and if I add distinct on select SQL get me an error for distinct usage on XML data.
@GrazianoDimatteo Another solution added, if you would like another way :)
1

One solution is to use FOR XML to combine rows for each group:

CREATE TABLE #testdata (ID int, NAME varchar(3), OPTIONAL_ID int, OPTIONAL_NAME varchar(10));
INSERT INTO #testdata (ID, NAME, OPTIONAL_ID, OPTIONAL_NAME) VALUES
    (1, 'abc', 34, 'optional 1'),
    (1, 'abc', 35, 'optional 2'),
    (1, 'abc', 36, 'optional 3'),
    (1, 'abc', 37, 'optional 4'),
    (2, 'qwe', 34, 'optional 1'),
    (2, 'qwe', 35, 'optional 2'),
    (2, 'qwe', 36, 'optional 3');

WITH names AS (
    SELECT DISTINCT NAME
    FROM #testdata
)
SELECT *
FROM names
CROSS APPLY (
    SELECT OPTIONAL_NAME
    FROM #testdata
    WHERE names.NAME = #testdata.NAME
    FOR XML PATH(''), ROOT('OPTIONAL_NAMES'), TYPE
) AS ca(xmldata)

Query Result

For comma separated list inside query output, use:

SELECT names.NAME, STUFF(xmldata, 1, 1, '')
FROM names
CROSS APPLY (
    SELECT ',' + OPTIONAL_NAME
    FROM #testdata
    WHERE names.NAME = #testdata.NAME
    FOR XML PATH('')
) AS ca(xmldata)

Comments

0

An XML Solution can look something like....

Test Data

CREATE TABLE #temp (ID INT , NAME VARCHAR(20), OPTIONAL_ID INT 
                    ,  OPTIONAL_NAME VARCHAR(20), OTHER_FIELDS VARCHAR(20))

INSERT INTO #temp VALUES 
(1  ,'abc'  , 34  ,'optional 1' , 'Some Data' ),
(1  ,'abc'  , 35  ,'optional 2' , 'Some Data' ),
(1  ,'abc'  , 36  ,'optional 3' , 'Some Data' ),
(1  ,'abc'  , 37  ,'optional 4' , 'Some Data' ),
(2  ,'qwe'  , 34  ,'optional 1' , 'Some Data' ),
(2  ,'qwe'  , 35  ,'optional 2' , 'Some Data' ),
(2  ,'qwe'  , 36  ,'optional 3' , 'Some Data' );

Query

SELECT
           t.[ID] AS [@ID]
        ,  t.Name AS [@Name]
        , (  
            SELECT  t2.OPTIONAL_ID
                  , t2.OPTIONAL_NAME
                  , t2.OTHER_FIELDS
            FROM #temp t2
            WHERE t.ID = t2.ID
            FOR XML PATH('OPTIONALS') , TYPE
           )
FROM 
(
    SELECT DISTINCT [ID] , Name
    FROM #temp 
)t
FOR XML PATH('x')

XML OUTPUT

<x ID="1" Name="abc">
  <OPTIONALS>
    <OPTIONAL_ID>34</OPTIONAL_ID>
    <OPTIONAL_NAME>optional 1</OPTIONAL_NAME>
    <OTHER_FIELDS>Some Data</OTHER_FIELDS>
  </OPTIONALS>
  <OPTIONALS>
    <OPTIONAL_ID>35</OPTIONAL_ID>
    <OPTIONAL_NAME>optional 2</OPTIONAL_NAME>
    <OTHER_FIELDS>Some Data</OTHER_FIELDS>
  </OPTIONALS>
  <OPTIONALS>
    <OPTIONAL_ID>36</OPTIONAL_ID>
    <OPTIONAL_NAME>optional 3</OPTIONAL_NAME>
    <OTHER_FIELDS>Some Data</OTHER_FIELDS>
  </OPTIONALS>
  <OPTIONALS>
    <OPTIONAL_ID>37</OPTIONAL_ID>
    <OPTIONAL_NAME>optional 4</OPTIONAL_NAME>
    <OTHER_FIELDS>Some Data</OTHER_FIELDS>
  </OPTIONALS>
</x>
<x ID="2" Name="qwe">
  <OPTIONALS>
    <OPTIONAL_ID>34</OPTIONAL_ID>
    <OPTIONAL_NAME>optional 1</OPTIONAL_NAME>
    <OTHER_FIELDS>Some Data</OTHER_FIELDS>
  </OPTIONALS>
  <OPTIONALS>
    <OPTIONAL_ID>35</OPTIONAL_ID>
    <OPTIONAL_NAME>optional 2</OPTIONAL_NAME>
    <OTHER_FIELDS>Some Data</OTHER_FIELDS>
  </OPTIONALS>
  <OPTIONALS>
    <OPTIONAL_ID>36</OPTIONAL_ID>
    <OPTIONAL_NAME>optional 3</OPTIONAL_NAME>
    <OTHER_FIELDS>Some Data</OTHER_FIELDS>
  </OPTIONALS>
</x>

1 Comment

why this query returns to me only the first element?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.