问题
I am trying to compile a list of dumpsters at a given location that a driver needs to pick up. I have a table like this:
Stop Number Dumpster Number
------------------------------------
1 245
1 248
2 312
2 314
2 316
I would like it to look like this:
Stop Number Dumpster Number
-------------------------------
1 245 248
2 312 314 316
The code I built is below, but I am getting the same result as the first table, with just the spaces on the end.
SELECT
[StopNumber],
CAST((CONCAT([ContainerID],' '))AS VARCHAR) AS ContainersAtStop
FROM
[TripSchedule]
GROUP BY
StopNumber, (CONCAT([ContainerID],' '))
Any help would be greatly appreciated.
回答1:
Test Data
DECLARE @t TABLE ([StopNumber] INT, [DumpsterNumber] VARCHAR(10))
INSERT INTO @t
VALUES
(1,'245'),
(1,'248'),
(2,'312'),
(2,'314'),
(2,'316')
Query
SELECT t.[StopNumber]
,STUFF((SELECT ', ' + [DumpsterNumber]
FROM TestTableOne
WHERE [StopNumber] = t.StopNumber
FOR XML PATH(''), TYPE
).value('.', 'varchar(max)'), 1, 2, '') AS [DumpsterNumber]
FROM TestTableOne t
GROUP BY t.[StopNumber]
Result Set
╔════════════╦════════════════╗
║ StopNumber ║ DumpsterNumber ║
╠════════════╬════════════════╣
║ 1 ║ 245, 248 ║
║ 2 ║ 312, 314, 316 ║
╚════════════╩════════════════╝
回答2:
Just use a correlated sub query as an expression. Take the distinct value of the results. I create a simple test table in tempdb below.

-- Just playing
use tempdb
go
-- Remove table
if object_id('d1') > 0
drop table d1
go
-- Create table
create table d1
(
stop_num int,
dumpster_num varchar(6)
);
go
-- Add data
insert into d1
values
(1, '245'),
(1, '248'),
(2, '312'),
(2, '314'),
(2, '316');
go
-- Sub-query to get list
select
stop_num,
stuff((
SELECT ISNULL(dumpster_num,'') + ','
FROM d1 as inner1
WHERE inner1.stop_num = outer1.stop_num
FOR XML PATH('')
), 1, 2, '') as list
from d1 as outer1
group by stop_num
So the question is which one is faster, the cross apply or the sub-query?
-- Show time & i/o
SET STATISTICS TIME ON
SET STATISTICS IO ON
GO
-- Remove clean buffers & clear plan cache
CHECKPOINT
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
GO
I ran the following above to turn on time and stats. Also, I cleared out buffers and query cache. Allow a 10 seconds or so for these commands to complete before taking a reading.
I changed the code below to use table d1 (dumpster) table in tempdb. Compare apples to apples.
-- Use a static table in tempdb
SELECT
stop_num,
STUFF(list.nums, 1 , 2,'') AS dumpster_num
FROM d1 t CROSS APPLY
(
SELECT ', ' + CAST(dumpster_num AS VARCHAR(10))
FROM d1
WHERE stop_num = t.stop_num
FOR XML PATH('')
) list(nums)
GROUP BY stop_num
I did get some variance between runs, but taking the best numbers after a buffer/cache clear, the run time is the same. The compile time is a little different. The I/O is exact.
--
-- Cross apply (numbers)
--
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 21 ms.
(2 row(s) affected)
Table 'd1'.
Scan count 6, logical reads 6, physical reads 0,
read-ahead reads 0, lob logical reads 0,
lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 14 ms.
--
-- sub query (numbers)
--
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 26 ms.
(2 row(s) affected)
Table 'd1'. Scan count 6, logical reads 6, physical reads 0,
read-ahead reads 0, lob logical reads 0, lob physical reads 0,
lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 14 ms.
I would say, both TSQL statements perform almost the same.
来源:https://stackoverflow.com/questions/20912675/concatenating-a-single-column-into-a-single-row-in-sql-server-management-studio