SQL限制连接/连接结果

时间:2015-04-20 10:52:30

标签: sql-server sql-server-2008 for-xml-path

Master

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

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

2 个答案:

答案 0 :(得分:3)

使用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 |

答案 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,请使用min和max:

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;