2017-04-02 12 views
5

Tôi có một đầu vào trong định dạng sau: Input ImageSum hàng trên cơ sở hàng hiện tại và tiếp theo

tôi phải tìm ra sự khác biệt của điểm dừng chân của hàng hiện tại và sự bắt đầu của hàng tiếp theo, và nếu sự khác biệt là nhỏ hơn 25, tôi cần tổng hợp các giá trị trong [TimeDiff_Start_Stop]. Nếu chênh lệch lớn hơn 25 thì tôi không cần phải làm tổng.

Như trong hình trên, sự khác biệt

giữa Dừng của Row 1 và bắt đầu của Row 2 là 13, giữa Dừng của Row 2 và bắt đầu của Row 3 là 2, giữa Dừng của Row 3 và bắt đầu của hàng 4 là 1, giữa Ngừng của hàng 4 và bắt đầu của hàng 5 là 3, giữa Ngừng của hàng 5 và bắt đầu của hàng 6 là 8,
nhưng sự khác biệt giữa Dừng của hàng 6 và bắt đầu của hàng 7 là 37, do đó chỉ [TimeDiff_Start_Stop] trong 6 hàng đầu tiên được tóm tắt, tạo ra hàng 1 ở đầu ra.

Di chuyển chênh lệch hơn nữa giữa Dừng của hàng 7 và bắt đầu của hàng 8 là 20, do đó [TimeDiff_Start_Stop] của hàng 7 và hàng 8 được tổng hợp, tạo ra hàng 2 ở đầu ra. sản lượng

buộc

Output Image

Làm thế nào tôi nên đạt được điều này?

Hãy tìm thấy bên dưới kịch bản cho đầu vào và đầu ra:

Input:

select 'Sample' as COL1,'1' AS COL2,1 as 'RN','2016-05-09 02:45:18.239669' AS Start,'2016-05-09 02:45:25.837316' as Stop,7 as TimeDiff_Start_Stop 
union 
select 'Sample' as COL1,'1' AS COL2,2 as 'RN','2016-05-09 02:45:38.809919' AS Start,'2016-05-09 02:46:59.856081' as Stop,81 as TimeDiff_Start_Stop 
union 
select 'Sample' as COL1,'1' AS COL2,3 as 'RN','2016-05-09 02:47:01.831128' AS Start,'2016-05-09 02:48:55.211807' as Stop,114 as TimeDiff_Start_Stop 
union 
select 'Sample' as COL1,'1' AS COL2,4 as 'RN','2016-05-09 02:48:56.305736' AS Start,'2016-05-09 02:50:06.107262' as Stop,70 as TimeDiff_Start_Stop 
union 
select 'Sample' as COL1,'1' AS COL2,5 as 'RN','2016-05-09 02:50:09.269354' AS Start,'2016-05-09 02:50:16.081159' as Stop,7 as TimeDiff_Start_Stop 
union 
select 'Sample' as COL1,'1' AS COL2,6 as 'RN','2016-05-09 02:50:24.819440' AS Start,'2016-05-09 02:51:04.736300' as Stop,40 as TimeDiff_Start_Stop 
union 
select 'Sample' as COL1,'1' AS COL2,7 as 'RN','2016-05-09 02:51:41.029165' AS Start,'2016-05-09 02:54:04.186215' as Stop,143 as TimeDiff_Start_Stop 
union 
select 'Sample' as COL1,'1' AS COL2,8 as 'RN','2016-05-09 02:54:24.537167' AS Start,'2016-05-09 02:55:26.926029' as Stop,62 as TimeDiff_Start_Stop 

Output:

select 'Sample' as COL1,'1' AS COL2,'2016-05-09 02:45:18.239669' AS Start,'2016-05-09 02:51:04.736300' as Stop,319 as Time 
union 
select 'Sample' as COL1,'1' AS COL2,'2016-05-09 02:51:41.029165' AS Start,'2016-05-09 02:55:26.926029' as Stop,205 as Time 
+0

Luôn giúp thêm DDL và chèn cho dữ liệu mẫu thay vì ảnh chụp màn hình. –

+0

Cảm ơn @MaxSzczurek. Đã cập nhật tập lệnh. – Logical

+0

LAG và LEAD hữu ích tại đây – Mihai

Trả lời

3

Dưới đây là 2 cách tiếp cận khác nhau - cho điều này, tôi đã tạo ra một bảng @t và đã sử dụng dữ liệu mẫu của bạn để điền dữ liệu đó - cảm ơn bạn đã chứng minh điều đó. Dưới đây là định nghĩa bảng:

declare @t table (col1 varchar(10), col2 int, rn int, start datetime2, stop datetime2, timediff_start_stop int) 
insert into @t ... (from the OP) 

Đây là phương pháp sử dụng CTE. Đầu tiên, nó tạo ra một CTE mà chỉ cần thêm sự khác biệt (sử dụng LEAD để có được sự khác biệt giữa hiện tại hàng dừng/hàng tiếp theo bắt đầu) như là một cột.

Lưu ý câu lệnh isnull trong truy vấn CTE cho giá trị từ 26 đến null nếu không có hàng sau đây - điều này có nghĩa là hàng cuối cùng trong tập kết quả có giá trị 26 (> 25, do đó sẽ khớp với tiêu chí của một hàng phải là thời gian kết thúc trong tập kết quả).

;with tdiff (col1, col2, rn, start, stop, timediff_start_stop, diff, timediff) 
as 
(
select col1, col2, rn, start, stop, timediff_start_stop, isnull(datediff(ss, stop, lead(start) over (order by rn)), 26) as diff, datediff(ss, start, stop) 
from @t 
) 
select t1.col1, t1.col2, t1.start, (select min(stop) from tdiff where stop > t1.start and diff > 25) as stop, 
    (select sum(timediff_start_stop) from tdiff where start >= t1.start and stop <= (select min(stop) from tdiff where stop > t1.start and diff > 25)) AS TIME 
from tdiff t1 
left join tdiff t2 on (t1.rn - 1) = t2.rn 
where t1.rn = 1 or t2.diff > 25 

Tiếp theo, đây là giải pháp hoàn toàn khác khi sử dụng con trỏ. Các con trỏ không hiệu quả và không phù hợp với các nhiệm vụ thường xuyên, nhưng tôi thấy chúng dễ bảo trì và tuân theo như một nhà phát triển, và nghĩ rằng nó có thể hữu ích cho một số người cần chạy các tác vụ không thường xuyên hoặc một lần phù hợp với con trỏ:

declare @outputtable table (start datetime, stop datetime) 
declare @curstart datetime, @curstop datetime, @curdiff int 
declare @outputstart datetime 

DECLARE cur CURSOR FOR 
select start, stop, datediff(ss, stop, LEAD(start) over (order by rn)) 
from @t 
OPEN cur 

FETCH NEXT FROM cur 
INTO @curstart, @curstop, @curdiff 

WHILE @@FETCH_STATUS = 0 
BEGIN  
    if (@outputstart is null) 
     set @outputstart = @curstart 

    if (@curdiff > 25) 
    begin 
     insert into @outputtable values (@outputstart, @curstop) 
     set @outputstart = null 
    end 

    FETCH NEXT FROM cur 
    INTO @curstart, @curstop, @curdiff 
END 
CLOSE cur; 
DEALLOCATE cur; 

insert into @outputtable values (@outputstart, @curstop) 

select * from @outputtable 
+0

Cảm ơn rất nhiều @MaxSzczurek. Nó đã làm việc. Nhưng tôi thực sự muốn làm mà không cần sử dụng con trỏ. Dữ liệu thực tế tôi có là hàng triệu. Chúng ta có thể làm điều đó theo cách khác không? Sử dụng CTE hoặc một số thứ khác. – Logical

+0

Vâng, làm việc trên một giải pháp mà không cần một con trỏ ngay bây giờ! Con trỏ là phương sách cuối cùng, nhưng đôi khi hữu ích trong các quy trình một lần/hiếm/không thường xuyên vì logic mã dễ làm theo, IMO. –

+0

Có. Tôi đồng ý. Trong khi đó, tôi đang cố gắng để tích hợp dateiff (ss, dừng lại, LEAD (bắt đầu) hơn (theo thứ tự của rn)) một phần trong mã của tôi. Điều này có thể sẽ loại bỏ việc sử dụng tự tham gia. Cảm ơn. – Logical

Các vấn đề liên quan