Không con trỏ ở đây nhưng đây vẫn là một vòng lặp qua các hàng bằng cách sử dụng CTE đệ quy để tìm ra những hàng nào sẽ được nhóm lại với nhau. Bảng tạm thời #T
là để giữ ID
kết nối các hàng với nhau. Nó có thể đã được thực hiện mà không có bảng tạm thời nhưng vì lý do hiệu suất nó là tốt hơn để làm điều đó với một bảng tạm thời thay vì có một CTE như là nguồn cho CTE đệ quy.
Trong truy vấn cuối cùng, tôi sử dụng thủ thuật for xml path
để ghép các giá trị từ No
. Điều đó có nghĩa là CTE C
được sử dụng lần thứ hai để nó sẽ được thực thi hai lần. Bạn có thể muốn biến CTE đó thành một bảng tạm thời để tránh điều đó.
SQL Fiddle
MS SQL Server 2008 Schema Cài đặt:
create table YourTable
(
GUID varchar(4),
No varchar(2),
sDateTime datetime,
eDateTime datetime,
Name varchar(1)
);
insert into YourTable values
('0000', '01', '2013-02-02 08:00:00', '2013-02-02 08:40:00', 'A'),
('0000', '02', '2013-02-02 08:45:00', '2013-02-02 09:45:00', 'A'),
('0000', '03', '2013-02-02 11:30:00', '2013-02-02 12:00:00', 'A'),
('0000', '04', '2013-02-02 09:55:00', '2013-02-02 11:00:00', 'A'),
('0000', '05', '2013-02-02 11:05:00', '2013-02-02 12:30:00', 'B');
Query 1:
create table #T
(
ID int,
GUID varchar(4),
No varchar(2),
sDateTime datetime,
eDateTime datetime,
Name varchar(1),
primary key(ID, GUID, Name)
);
insert into #T(ID, GUID, No, sDateTime, eDateTime, Name)
select row_number() over(partition by GUID, Name order by sDateTime),
GUID, No, sDateTime, eDateTime, Name
from YourTable;
with C as
(
select T.ID, T.GUID, T.No, T.sDateTime, T.eDateTime, T.Name, 1 as Grp
from #T as T
where T.ID = 1
union all
select T.ID, T.GUID, T.No, T.sDateTime, T.eDateTime, T.Name,
C.Grp + case when datediff(minute, C.eDateTime, T.sDateTime) > 10
then 1
else 0
end
from #T as T
inner join C
on T.ID = C.ID + 1 and
T.Name = C.Name and
T.GUID = C.GUID
)
select C.GUID,
(
select ','+C2.No
from C as C2
where C.GUID = C2.GUID and
C.Name = C2.Name and
C.Grp = C2.Grp
order by C2.No
for xml path(''), type
).value('substring(text()[1], 2)', 'varchar(max)') as No,
min(C.sDateTime) as sDateTime,
max(C.eDateTime) as eDateTime,
C.Name
from C
group by C.GUID, C.Name, C.Grp
drop table #T;
Results:
| GUID | NO | SDATETIME | EDATETIME | NAME |
----------------------------------------------------------------------------------------------
| 0000 | 01,02,04 | February, 02 2013 08:00:00+0000 | February, 02 2013 11:00:00+0000 | A |
| 0000 | 03 | February, 02 2013 11:30:00+0000 | February, 02 2013 12:00:00+0000 | A |
| 0000 | 05 | February, 02 2013 11:05:00+0000 | February, 02 2013 12:30:00+0000 | B |
Chỉ để cho vui, phiên bản SQL Server 2012.
with CMinDiff as
(
select GUID, No, sDateTime, eDateTime, Name,
case when datediff(minute,
coalesce(lag(eDateTime) over(partition by GUID, Name
order by eDateTime),
sDateTime),
sDateTime) <= 10
then 0
else 1
end as MinDiff
from YourTable
), CSumMinDiff as
(
select GUID, No, sDateTime, eDateTime, Name,
sum(MinDiff) over(partition by GUID, Name
order by sDateTime
rows between unbounded preceding and current row) as Grp
from CMinDiff
)
select C.GUID,
(
select ','+C2.No
from CSumMinDiff as C2
where C.GUID = C2.GUID and
C.Name = C2.Name and
C.Grp = C2.Grp
order by C2.No
for xml path(''), type
).value('substring(text()[1], 2)', 'varchar(max)') as No,
min(C.sDateTime) as sDateTime,
max(C.eDateTime) as eDateTime,
C.Name
from CSumMinDiff as C
group by C.GUID, C.Name, C.Grp
Bạn đang sử dụng phiên bản SQL Server nào? –
@NitinMidha SQL Server 2008 Express Edition –
Ngoài ra tại sao 05 không được kết hợp với 01,02 và 04? Tôi nghĩ rằng nó đáp ứng các tiêu chí của 10 phút, nếu tôi hiểu chính xác .. –