SQL 查询以获取具有单个不同字段的多条记录
SQL Query to get multiple records with a single different field
我有一个 table(它不是真正的 table,而是另一个查询的结果),如下所示:
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 | ...
我需要的是通过每个对象的记录获得不同的结果,在此示例中为 'abc' 和 'qwe' 以及一个像 OPTIONALS 这样的列,其中包含每个对象的所有 optional_name对象。
输出类型对我来说不重要(JSON,XML,查询输出)
我试过 'group by' 但我没有得到想要的结果。
一种解决方案是使用 FOR XML
为每个组合并行:
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)
对于查询输出中的逗号分隔列表,使用:
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)
XML 解决方案可能类似于...
测试数据
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' );
查询
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 输出
<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>
试试这个(我只考虑了相关的列):
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
如果您想要 JSON
,则在上次查询中将 XML
替换为 JSON
(需要最新的 SQL 服务器)。
另一个选项(稍微修改了之前的查询):
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
我有一个 table(它不是真正的 table,而是另一个查询的结果),如下所示:
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 | ...
我需要的是通过每个对象的记录获得不同的结果,在此示例中为 'abc' 和 'qwe' 以及一个像 OPTIONALS 这样的列,其中包含每个对象的所有 optional_name对象。
输出类型对我来说不重要(JSON,XML,查询输出)
我试过 'group by' 但我没有得到想要的结果。
一种解决方案是使用 FOR XML
为每个组合并行:
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)
对于查询输出中的逗号分隔列表,使用:
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)
XML 解决方案可能类似于...
测试数据
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' );
查询
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 输出
<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>
试试这个(我只考虑了相关的列):
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
如果您想要 JSON
,则在上次查询中将 XML
替换为 JSON
(需要最新的 SQL 服务器)。
另一个选项(稍微修改了之前的查询):
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