2011-03-27 23 views
8

Kayıtlarım var, yaklaşık 300.000 kayıt. O gün için toplam kayıt sayısını gösteren bir SQL ifadesine ihtiyacım var? Bu sorgununGeçerli ve önceki tarihlerin toplam sütun değerleri

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) 

Sonuç:

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

Arzu edilen sonuç:

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

Bu nasıl yapılabilir?

+0

Oh, [sql-sunucu] bkz MS için ayrılmıştır verdik. – vbence

+0

@vbence: SQL Server'ı duymadınız gibi görünüyor. http://en.wikipedia.org/wiki/Microsoft_SQL_Server –

+0

@ p.campbell Wow .. Böyle kısa bir yorumda çok fazla düşmanlık. – vbence

cevap

2

iki versiyonlarını yazmak mümkün olacak. 100.000 satırın 6000 gün boyunca yeterince yavaş bir bilgisayara sahip olmadığını test ettim ve bu da cte versiyonunun loop versiyonundan daha hızlı olduğunu gösteriyor. Sorunu doğru bir şekilde anladım, burada (şimdiye kadar) önerilen diğer versiyonlar çok daha yavaştır.

Recursive CTE (10 saniye)

-- 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) 

Döngü (14 saniye)

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

Düzenleme 1 gerçekten hızlı sürüm

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 İlginç güncelleme tekniği en hızlı olanıdır - Sadece belgelendirilmemiş veya garanti edilmemiştir! Gerçekten de en azından kümelenmiş bir dizine sahip olmalısınız ve “MAXDOP 1” ayarlanmış olsa da (burada açıklandığı gibi http://www.sqlservercentral.com/articles/T-SQL/68467/) –

+0

@Martin - "Belgelenmemiş veya güvenilmez "performans makul ise, daha yavaş özyinelemeli cte sürümünü seçmek için geçerli bir neden olabilir. Güncelleme siparişi garanti edilmediği için güncelleme başarısız olabilir. Alttan güncellemeler yapmaya başlamışsa veya SQL Server güncellemeyi paralel olarak çalıştırmak için bir seçim yaparsa kötü olur. Bunun gerçekleşip gerçekleşmeyeceğine dair hiçbir fikrim yok. Yarın işyerinde, birden fazla işlemciye sahip bir bilgisayarım var :). –

+1

@Martin - Benim yayınlamadan önce düzenlenmiş yorumunuzu okumadım. Kümelenmiş dizin ve 'maxdop 1 ', endişelendiğim konulara çözüm gibi geliyor. –

1

Bunu deneyin. Tabii

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 

gibi bir şey ile indeksine tablo vardır: Basitçe kümülatif sayım sonucuna varmak için bir SUM kullanmak

CREATE INDEX datefilter ON reg (date_created); 
+0

bu yanlıştır; birikimli bir değer üretmez. –

+0

Belirli bir gün ve bir önceki tüm günler için kayıt sayısını verir. Bu, aldığı kadar kümülatiftir. – vbence

+0

Sorgunun sonuçları şöyle görünüyor: http://i.imgur.com/VLdrT.png –

2

: Şu

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

Sanırım bu iki önyargılı cevapla tam olarak aynı sonucu verecekti. – vbence

+0

@vbence: SQL Management Studio'yu tetikleyin, bu yanıtı yapıştırın ve yürütün. 'R2' değil, r1 değil. –

+0

O zaman benim de madenin doğru sonuçları verdiğini farz ettim. :) – vbence

2

2 seçeneğiniz vardır: Birinci vbence tarafından önerilen birleştirme kullanıyor, ikinci alt sorgu:

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

Bu 2 yaklaşım benzer yürütme planları oluşturur. Gelecekte

, SQLSunucusu toplama işlevleri OVER için ORDER BY uygular, bunu yapmak için Buraya

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

3 seçenek - Üçüncüsü bir imleci veya [daha hızlı bir imleç olarak hareket etmek için CLR] kullanıyor (http://sqlblog.com/blogs/adam_machanic/archive/2006/07/12/running-sums-yet -again-sqlclr-saves-the-day.aspx) –

+0

@Martin: Tabii ki, aynı sonuçları imleçler ile elde edebilirsiniz, ama imleçler performans yükleri var, bu yüzden onları böyle durumlarda kullanmazsınız ... – a1ex07

+1

Kaç tane bağlıdır satırlar işlenmelidir. Üçgen birleştirme iş yükü, satırların sayısının karesiyle orantılı olarak büyür. İmleç doğrusal olarak yüklenir. –

1

..Çok yanıltıcı o: İki sütun col1=Number ve col2=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 
İlgili konular