2011-03-27 36 views
8

Tôi có một bảng đăng ký, khoảng 300 nghìn bản ghi. Tôi cần một câu lệnh SQL sẽ hiển thị tổng số đăng ký cho ngày cụ thể đó?Giá trị cột tích lũy từ ngày hiện tại và trước đó

select 
count('x'),CONVERT(varchar(12),date_created,111) 
from reg group by 
cONVERT(varchar(12),date_created,111) 
order by 
CONVERT(varchar(12),date_created,111) 

Kết quả truy vấn này:

169  2011/03/24 
3016  2011/03/25 
2999  2011/03/26 

kết quả mong muốn:

2011/03/25 3016+169 
2011/03/26 2999+3016+169 

Làm thế nào điều này có thể được thực hiện?

+0

Ồ, tôi thấy [sql-server] được dành riêng cho MS: o Rất gây hiểu nhầm. – vbence

+0

@vbence: Có vẻ như bạn chưa từng nghe về SQL Server. http://en.wikipedia.org/wiki/Microsoft_SQL_Server –

+0

@ p.campbell Wow .. rất nhiều sự thù địch trong một nhận xét ngắn như vậy. – vbence

Trả lời

2

Đây là hai phiên bản để làm điều này. Tôi đã thử nghiệm với 100000 hàng trải rộng trên 6000 ngày trên một máy tính thực sự chậm với bộ nhớ không đủ, và điều đó cho thấy rằng phiên bản cte nhanh hơn phiên bản vòng lặp. Các phiên bản khác được đề xuất ở đây (cho đến nay) chậm hơn rất nhiều, miễn là tôi đã hiểu được vấn đề chính xác.

đệ quy CTE (10 giây)

-- Table variable to hold count for each day 
declare @DateCount table(d int, c int, rn int) 
insert into @DateCount 
    select 
    datediff(d, 0, date_created) as d, 
    count(*) as c, 
    row_number() over(order by datediff(d, 0, date_created)) as rn 
    from reg 
    group by datediff(d, 0, date_created) 

-- Recursive cte using @DateCount to calculate the running sum 
;with DateSum as 
(
    select 
    d, c, rn 
    from @DateCount 
    where rn = 1 
    union all 
    select 
    dc.d, ds.c+dc.c as c, dc.rn 
    from DateSum as ds 
    inner join @DateCount as dc 
     on ds.rn+1 = dc.rn 
) 
select 
    dateadd(d, d, 0) as date_created, 
    c as total_num 
from DateSum 
option (maxrecursion 0) 

Vòng (14 giây)

-- Table variable to hold count for each day 
declare @DateCount table(d int, c int, rn int, cr int) 
insert into @DateCount 
    select 
    datediff(d, 0, date_created) as d, 
    count(*) as c, 
    row_number() over(order by datediff(d, 0, date_created)) as rn, 
    0 
    from reg 
    group by datediff(d, 0, date_created) 

declare @rn int = 1 

-- Update cr with running sum 
update dc set 
    cr = dc.c 
from @DateCount as dc 
where rn = @rn 

while @@rowcount = 1 
begin 
    set @rn = @rn + 1 

    update dc set 
    cr = dc.c + (select cr from @DateCount where rn = @rn - 1) 
    from @DateCount as dc 
    where rn = @rn 
end 

-- Get the result 
select 
    dateadd(d, d, 0) as date_created, 
    cr as total_num 
from @DateCount 

Sửa 1 Phiên bản rất nhanh

The quirky update

-- Table variable to hold count for each day 
declare @DateCount table(d int primary key, c int, cr int) 
insert into @DateCount 
    select 
    datediff(d, 0, date_created) as d, 
    count(*) as c, 
    0 
    from reg 
    group by datediff(d, 0, date_created) 

declare @rt int = 0 
declare @anchor int 

update @DateCount set 
    @rt = cr = @rt + c, 
    @anchor = d 
option (maxdop 1) 

-- Get the result 
select 
    dateadd(d, d, 0) as date_created, 
    cr as total_num 
from @DateCount     
order by d 
+0

+1 Kỹ thuật cập nhật kỳ quặc là kỹ thuật nhanh nhất - Không phải ở tất cả các tài liệu hoặc được đảm bảo! Bạn nên thực sự ít nhất có một chỉ số nhóm và 'MAXDOP 1' thiết lập mặc dù (như được thảo luận ở đây http://www.sqlservercentral.com/articles/T-SQL/68467/) –

+0

@Martin -" Không được ghi chép hoặc bảo đảm "có thể là một lý do hợp lệ để chọn phiên bản cte đệ quy chậm hơn thay vì nếu hiệu suất là hợp lý. Có lẽ bản cập nhật có thể không thành công vì thứ tự cập nhật không được đảm bảo. Nó sẽ là xấu nếu nó bắt đầu làm cập nhật từ phía dưới hoặc nếu SQL Server làm cho một sự lựa chọn để chạy cập nhật song song. Tôi không biết liệu điều đó có khả năng xảy ra hay không. Tôi sẽ kiểm tra điều này tại nơi làm việc vào ngày mai, nơi tôi có một máy tính với nhiều hơn một bộ xử lý :). –

+1

@Martin - Không đọc nhận xét đã chỉnh sửa của bạn trước khi tôi đăng bài đăng của tôi. Clustered index và 'maxdop 1' nghe như giải pháp cho những thứ tôi lo lắng. –

1

Hãy thử cái này.

SELECT r1.date_created, 
    COUNT(*) AS number 
FROM (SELECT distinct(date_created) FROM reg) AS r1 
    LEFT JOIN reg AS r2 ON (r2.date_created <= r1.date_created) 
GROUP BY r1.date_created 

Tất nhiên bạn phải chỉ số bảng của bạn với một cái gì đó như:

CREATE INDEX datefilter ON reg (date_created); 
+0

điều này là không chính xác; không tạo ra giá trị tích lũy. –

+0

Nó sẽ cung cấp cho bạn số lượng đăng ký cho một ngày nhất định và cho tất cả các ngày trước đó kết hợp. Điều này là tích lũy như nó được. – vbence

+0

Đây là kết quả của kết quả truy vấn của bạn: http://i.imgur.com/VLdrT.png –

2

Đơn giản chỉ cần sử dụng một SUM để có được một số lượng tích lũy:

SELECT reg1.date_created,  
     SUM(reg2.val) AS CumulativeValue 
FROM (
     select count(*) as RegCountForDay, 
       date_created 
     from reg 
     group by date_created 
    ) AS reg1 
LEFT JOIN reg AS reg2 ON (reg2.date_created <= reg1.date_created) 
GROUP BY reg1.date_created 
+0

Tôi nghĩ rằng điều này sẽ cho kết quả chính xác giống như hai câu trả lời tiền thưởng. – vbence

+0

@vbence: kích hoạt SQL Management Studio, dán vào câu trả lời này và thực thi nó. It's SUM'ing trên 'r2', không phải' r1'. –

+0

Lúc đó tôi giả định rằng tôi cũng đưa ra kết quả chính xác. :) – vbence

2

Hiện nay bạn có 2 lựa chọn: thứ nhất đang sử dụng tính năng tham gia theo đề xuất của vbence, thứ hai là truy vấn con:

SELECT r1.date_created, (SELECT COUNT(*) FROM reg r2 
WHERE r2.date_created<=r1.date_created) AS total_num 
FROM reg r1; 

Hai phương pháp này tạo ra các kế hoạch thực hiện tương tự.

Trong tương lai, khi SQLServer thực hiện ORDER BY cho OVER với chức năng tổng hợp, bạn sẽ có thể viết

SELECT date_created, 
COUNT(*) OVER(ORDER BY date_created) as total_num 
FROM reg; 
+0

3 tùy chọn - Thứ ba là sử dụng con trỏ hoặc [CLR hoạt động như con trỏ nhanh hơn] (http://sqlblog.com/blogs/adam_machanic/archive/2006/07/12/running-sums-yet -again-sqlclr-save-the-day.aspx) –

+0

@Martin: Chắc chắn, bạn có thể nhận được kết quả tương tự với con trỏ, nhưng con trỏ có chi phí hiệu suất, vì vậy tôi sẽ không sử dụng chúng trong các trường hợp như vậy ... – a1ex07

+1

Phụ thuộc vào bao nhiêu các hàng cần được xử lý. Khối lượng công việc nối tam giác tăng tỷ lệ thuận với bình phương của số hàng. Con trỏ lo lắng tuyến tính. –

1

bạn có thể giải quyết vấn đề này thông qua dưới đây truy vấn sql ..Ngài đã ban cho hai cột col1=Numbercol2=Date

Select DATE,OUTPUT=SUM(InnerValue) from 
(
    Select T1.Date, T1.Number, InnerValue=ISNULL(T2.Number,0) from 
    (
    Select ID=DENSE_RANK() OVER(ORDER BY DATE),Date,Number from YourTable 
) As T1 
    LEFT JOIN 
    (
    Select ID=DENSE_RANK() OVER(ORDER BY DATE),Date,Number from YourTable 
) AS T2 
    ON T1.ID >= T2.ID 
) As MainTable GROUP BY DATE 
Các vấn đề liên quan