2015-10-08 23 views
5

Xin lỗi vì chủ đề xấu nhưng tôi không chắc chắn những gì để gọi nó ..Chạy SUM trong T-SQL

Tôi có một bảng tìm kiếm như thế này:

+-----++-----+ 
| Id ||Count| 
+-----++-----+ 
| 1 || 1 | 
+-----++-----+ 
| 2 || 5 | 
+-----++-----+ 
| 3 || 8 | 
+-----++-----+ 
| 4 || 3 | 
+-----++-----+ 
| 5 || 6 | 
+-----++-----+ 
| 6 || 8 | 
+-----++-----+ 
| 7 || 3 | 
+-----++-----+ 
| 8 || 1 | 
+-----++-----+ 

Tôi đang cố gắng để làm cho một lựa chọn từ bảng này, nơi mỗi khi SUM của row1 + row2 + row3 (etc) đạt đến 10, thì đó là "HIT" và số đếm bắt đầu lại. sản lượng

yêu cầu:

+-----++-----++-----+ 
| Id ||Count|| HIT | 
+-----++-----++-----+ 
| 1 || 1 || N | Count = 1 
+-----++-----++-----+ 
| 2 || 5 || N | Count = 6 
+-----++-----++-----+ 
| 3 || 8 || Y | Count = 14 (over 10) 
+-----++-----++-----+ 
| 4 || 3 || N | Count = 3 
+-----++-----++-----+ 
| 5 || 6 || N | Count = 9 
+-----++-----++-----+ 
| 6 || 8 || Y | Count = 17 (over 10..) 
+-----++-----++-----+ 
| 7 || 3 || N | Count = 3 
+-----++-----++-----+ 
| 8 || 1 || N | Count = 4 
+-----++-----++-----+ 

Làm thế nào để làm điều này, và với hiệu suất tốt nhất? Tôi không có ý tưởng ..

+0

[xem tại đây] (http://stackoverflow.com/a/31497897/3094533) –

+0

Thú vị nghĩ về việc sử dụng dense_rank(). Có lẽ điều này sẽ làm việc. Nếu không, tôi sợ một proc được lưu trữ với một con trỏ có lẽ là những gì cần thiết. –

+0

Nếu 'dense_rank()' không thực hiện thủ thuật, bạn cũng có thể thực hiện điều này với chế độ xem đệ quy. Tôi tin rằng tuyến đường 'dense_rank() 'sẽ được tối ưu hóa tốt hơn mặc dù. – JNevill

Trả lời

3

Bạn có thể sử dụng Recursive Queries

Xin lưu ý các truy vấn sau đây giả sử giá trị id là tất cả trong chuỗi, nếu không, hãy sử dụng ROW_NUMBER() để tạo ra một id mới

WITH cte AS (
    SELECT id, [Count], [Count] AS total_count 
    FROM Table1 
    WHERE id = 1 
    UNION ALL 
    SELECT t2.id,t2.[Count], CASE WHEN t1.total_count >= 10 THEN t2.[Count] ELSE t1.total_count + t2.[Count] END 
    FROM Table1 t2 
    INNER JOIN cte t1 
    ON t2.id = t1.id + 1 
) 
SELECT * 
FROM cte 
ORDER BY id 

SQL Fiddle

1

Tôi thực sự hy vọng một người nào đó có thể hiển thị cho chúng tôi nếu có thể thực hiện việc này bằng các chức năng cửa sổ thẳng về phía trước. Đó là thách thức thực sự.

Trong thời gian chờ đợi, dưới đây là cách tôi sẽ làm điều đó bằng cách sử dụng đệ quy. Điều này xử lý các khoảng trống trong chuỗi và xử lý trường hợp cạnh của hàng đầu tiên đã là >= 10.

Tôi cũng đã thêm gợi ý maxrecursion để xóa giới hạn đệ quy mặc định. Nhưng tôi thành thật không biết nó sẽ chạy như thế nào với lượng dữ liệu lớn hơn.

with NumberedRows as (
    select Id, Cnt, 
     row_number() over(order by id) as rn 
    from CountTable 
), RecursiveCTE as (
    select Id, Cnt, rn, 
     case when Cnt >= 10 then 0 else Cnt end as CumulativeSum, 
     case when Cnt >= 10 then 'Y' else 'N' end as hit 
    from NumberedRows 
    where rn = 1 
    union all 
    select n.Id, n.Cnt, n.rn, 
     case when (n.Cnt + r.CumulativeSum) >= 10 then 0 else n.Cnt + r.CumulativeSum end as CumulativeSum, 
     case when (n.Cnt + r.CumulativeSum) >= 10 then 'Y' else 'N' end as hit 
    from RecursiveCTE r 
    join NumberedRows n 
     on n.rn = r.rn + 1 
) 
select Id, Cnt, hit 
from RecursiveCTE 
order by Id 
option (maxrecursion 0) 

SQLFiddle Demo

4

Đây là quá dài cho một nhận xét.

Bạn không thể thực hiện việc này bằng các chức năng cửa sổ/phân tích, vì các điểm ngắt không được biết trước. Đôi khi, có thể tính toán các điểm ngắt. Tuy nhiên, trong trường hợp này, các điểm ngắt phụ thuộc vào một hàm phi tuyến tính của các giá trị trước đó (tôi không thể nghĩ ra một từ tốt hơn là "phi tuyến tính" ngay bây giờ). Tức là, đôi khi việc thêm "1" vào giá trị trước đó sẽ không ảnh hưởng đến việc tính toán cho hàng hiện tại. Đôi khi nó có tác dụng lớn. Hàm ý là phép tính phải bắt đầu ngay từ đầu và lặp qua dữ liệu.

Sửa đổi nhỏ cho sự cố sẽ có thể giải được bằng các chức năng như vậy. Nếu vấn đề là, thay vào đó, để thực hiện số tiền vượt quá cho mỗi nhóm (thay vì khởi động lại tổng), vấn đề sẽ được giải quyết bằng cách sử dụng tổng tích lũy (và một số thủ thuật khác).

Truy vấn đệ quy (mà những người khác đã cung cấp) hoặc hoạt động tuần tự là cách tốt nhất để tiếp cận vấn đề này. Thật không may, nó không có một phương pháp dựa trên thiết lập để giải quyết nó.

1

Làm thế nào về vấn đề này bằng Chạy Tổng cộng:

DECLARE @Data TABLE(
    Id INT 
    ,SubTotal INT 
) 


INSERT INTO @Data 
    VALUES(1, 5) 

INSERT INTO @Data 
    VALUES(2, 3) 

INSERT INTO @Data 
    VALUES(3, 4) 

INSERT INTO @Data 
    VALUES(4, 4) 

INSERT INTO @Data 
    VALUES(5, 7) 

DECLARE @RunningTotal INT = 0 
DECLARE @HitCount INT = 0  

SELECT 
     @RunningTotal = CASE WHEN @RunningTotal < 10 THEN @RunningTotal + SubTotal ELSE SubTotal END 
     ,@HitCount = @HitCount + CASE WHEN @RunningTotal >= 10 THEN 1 ELSE 0 END 
     FROM @Data ORDER BY Id 

SELECT @HitCount -- Outputs 2 

Sau khi đọc lại những câu hỏi tôi thấy điều này không đáp ứng được yêu cầu đầu ra - Tôi sẽ để lại câu trả lời vì nó có thể được sử dụng một số với một ai đó tìm kiếm ví dụ về giải pháp tổng thể đang chạy cho loại sự cố này không cần mỗi hàng được gắn thẻ với Y hoặc N.