SQL 限制 join/concatenation 结果

SQL limit join/concatenation result

Table Master:

----------------------
| Name      | ID     |
----------------------
| A         | 1      |
| B         | 2      |
| C         | 3      |
----------------------

Table Detail:

----------------------
| masterID  | det     |
----------------------
| 1         | 21      |
| 1         | 31      |
| 1         | 442     |
| 1         | 76      |
| 2         | 1       |
| 2         | 90      |
| 3         | 48      |
| 3         | 56      |
| 3         | 109     |
----------------------

请求结果: 进行联接和串联,但将串联值的数量限制为 X(此处为 2),如果更多,则创建一个新行。例如,上面的预期结果将是:

----------------------
| Name      | dets   |
----------------------
| A         | 21, 31 |
| A         | 442, 76|
| B         | 1, 90  |
| C         | 48, 56 |
| C         | 109    |
----------------------

使用下面的代码我可以将所有结果连接起来,但是我需要有关如何限制连接的记录数的帮助:

SELECT Master.Name, 
STUFF((
SELECT ','+Detail.det
FROM Detail
WHERE Master.ID = Detail.masterID
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'')
FROM Master

还为它创建了 SQLFiddle:http://sqlfiddle.com/#!6/a1b69/1/0

FOR XML 适用于结果集的结构。我很确定你可以通过在子查询中使用 TOP 2 来做到这一点。

但是,您可能会发现条件聚合速度更快:

select m.name,
       (max(case when seqnum = 1 then cast(id as varchar(255)) else '' end) +
        max(case when seqnum = 2 then ', ' + cast(id as varchar(255)) else '' end) 
       ) as ids
from master m join
     (select d.*,
             row_number() over (partition by m.masterId order by (select null)) as seqnum
      from detail d
     ) d
     on m.id = d.masterid
where seqnum <= 2
group by name;

或者,因为您似乎并不关心特定的 ID,所以使用最小值和最大值:

select m.name,
       (case when minid = maxid then cast(minid as varchar(255))
             else cast(minid as varchar(255)) + ', ' + cast(maxid as varchar(255))
        end) as ids
from master m join
     (select d.masterid, min(id) as minid, max(id) as maxid
      from detail d
      group by d.masterid
     ) d
     on m.id = d.masterid;

使用 row_number() 和整数除法创建一个每隔一行递增的键。在 CTE 中执行此操作并在主查询和 for xml 查询中使用 CTE。

SQL Fiddle

MS SQL Server 2014 架构设置:

create table Master
(
  Name varchar(10),
  ID int
);

create table Detail
(
  masterID int,
  det varchar(10)
);

go

insert into Master values
('A', 1),
('B', 2),
('C', 3);

insert into Detail values
(1, 21 ),
(1, 31 ),
(1, 442),
(1, 76 ),
(2, 1  ),
(2, 90 ),
(3, 48 ),
(3, 56 ),
(3, 109);

查询 1:

with C as
(
  select M.Name,
         D.masterID,
         D.det,
         (row_number() over(partition by D.masterID order by D.det) - 1) / 2 as rn
  from dbo.Detail as D
    inner join dbo.Master as M
      on D.masterID = M.ID
)
select C.Name,
       stuff ((select ', ' + D.det
               from C as D
               where C.masterID = D.masterID and
                     C.rn = D.rn
               for xml path(''), type).value('text()[1]', 'varchar(max)'), 1, 2, '')
from C
group by C.masterID,
         C.Name,
         C.rn

Results:

| Name |         |
|------|---------|
|    A |  21, 31 |
|    A | 442, 76 |
|    B |   1, 90 |
|    C | 109, 48 |
|    C |      56 |