2008-08-19 22 views
4

Aylık Durum veritabanı görünümüne sahibim. görünümünde veri şöyle görünür:SQL sorgusu ile ay sonuna göre ürün satışlarını karşılaştırmak için

Category | Revenue | Yearh | Month 
Bikes  10 000  2008  1 
Bikes  12 000  2008  2 
Bikes  12 000  2008  3 
Bikes  15 000  2008  1 
Bikes  11 000  2007  2 
Bikes  11 500  2007  3 
Bikes  15 400  2007  4 


... Ve benzeri

görünümü bir ürün kategorisi, bir gelir, bir yıl ve bir ay vardır. Satışları olmayan aylar için 0'ı gösteren, 2007 ve 2008'i karşılaştıran bir rapor oluşturmak istiyorum. fark

Category | Month | Rev. This Year | Rev. Last Year 
Bikes   1   10 000    0 
Bikes   2   12 000    11 000 
Bikes   3   12 000    11 500 
Bikes   4   0     15 400 


önemli şey ay 1 sadece ay 4 sadece 2008 yılında hiçbir satış var, 2008 yılında satışlarını sahiptir ve bu nedenle de 2007 yılı için 0 nasıl geçerli: rapor bu gibi görünmelidir Yani Bu nedenle, 0, satışları 2007 yılında iken ve hala ortaya çıkıyor.

Ayrıca, rapor mali yıl için aslında - ben 2007 veya 2008

Tipler var sorgu biri için diyelim ki ayda 5 satış yapmıyorsanız orada hem eğer 0 ile boş sütunlar sahip olmak isterdim böyle bir şey:

SELECT 
    SP1.Program, 
    SP1.Year, 
    SP1.Month, 
    SP1.TotalRevenue, 
    IsNull(SP2.TotalRevenue, 0) AS LastYearTotalRevenue 

FROM PVMonthlyStatusReport AS SP1 
    LEFT OUTER JOIN PVMonthlyStatusReport AS SP2 ON 
       SP1.Program = SP2.Program AND 
       SP2.Year = SP1.Year - 1 AND 
       SP1.Month = SP2.Month 
WHERE 
    SP1.Program = 'Bikes' AND 
    SP1.Category = @Category AND 
    (SP1.Year >= @FinancialYear AND SP1.Year <= @FinancialYear + 1) AND 
    ((SP1.Year = @FinancialYear AND SP1.Month > 6) OR 
    (SP1.Year = @FinancialYear + 1 AND SP1.Month <= 6)) 

ORDER BY SP1.Year, SP1.Month 

bu sorgu ile sorun 2008 yılında herhangi bir satış yoktu çünkü, yukarıda benim örnek veriler dördüncü satır dönmek olmazdı yani, ama aslında 2007

yaptığı

Bu, muhtemelen ortak bir sorgu/sorundur, ancak SQL çok uzun zamandır ön uç geliştirme yaptıktan sonra paslı. Herhangi bir yardım büyük beğeni topluyor!

Oh, btw, bu sorgu için SQL 2005 kullanıyorum, bu yüzden bana bildirmeme yardımcı olabilecek herhangi bir yardımcı yeni özellik varsa.

cevap

4

Durum Beyanı en iyi sql arkadaşım. Ayrıca her iki ayda 0 sürenizi oluşturmak için bir tabloya da ihtiyacınız var.

satış:

Varsayımlar aşağıdaki tablolarda kullanılabilirliği dayanmaktadır Kategori | Gelir | Yearh | Ay

ve

tm: Yıl | Ay boş satırlar olmadan

Örnek 1 (raporlama için gerekli tüm tarihleri ​​ile doldurulur):

select 
    Category 
    ,month 
    ,SUM(CASE WHEN YEAR = 2008 THEN Revenue ELSE 0 END) this_year 
    ,SUM(CASE WHEN YEAR = 2007 THEN Revenue ELSE 0 END) last_year 

from 
    sales 

where 
    year in (2008,2007) 

group by 
    Category 
    ,month 

GETİRİLERİ: Boş satırlarla

Category | Month | Rev. This Year | Rev. Last Year 
Bikes   1   10 000    0 
Bikes   2   12 000    11 000 
Bikes   3   12 000    11 500 
Bikes   4   0     15 400 

Örnek 2: gidiyorum Bir alt sorgu (ama diğerleri olmayabilir) kullanın ve her ürün ve yıl için açılan bir satır için boş bir satır döndürür.

select 
    fill.Category 
    ,fill.month 
    ,SUM(CASE WHEN YEAR = 2008 THEN Revenue ELSE 0 END) this_year 
    ,SUM(CASE WHEN YEAR = 2007 THEN Revenue ELSE 0 END) last_year 

from 
    sales 
    Right join (select distinct --try out left, right and cross joins to test results. 
        product 
        ,year 
        ,month 
       from 
        sales --this ideally would be from a products table 
        cross join tm 
       where 
        year in (2008,2007)) fill 


where 
    fill.year in (2008,2007) 

group by 
    fill.Category 
    ,fill.month 

GETİRİLERİ: En raporlama araçları bu çapraz tablo veya matris işlevselliği yapacak ve şimdi düşünüyorum da SQL Server 2005 de bunu yapacak Pivot sözdizimi vardır

Category | Month | Rev. This Year | Rev. Last Year 
Bikes   1   10 000    0 
Bikes   2   12 000    11 000 
Bikes   3   12 000    11 500 
Bikes   4   0     15 400 
Bikes   5   0     0 
Bikes   6   0     0 
Bikes   7   0     0 
Bikes   8   0     0 

Not.

Bazı ek kaynaklar aşağıda verilmiştir. DURUM http://www.4guysfromrolla.com/webtech/102704-1.shtml SQL SERVER 2005 MİL http://msdn.microsoft.com/en-us/library/ms177410.aspx

3

@Christian - markdown düzenleyici - UGH; özellikle de önizleme ve yazının son sürümü katılmıyorsa ... @Christian - tam dış birleştirme - tam dış birleşim, WHERE yan tümcesinde SP1'e başvurular olduğu ve WHERE yan tümcesinin olduğu gerçeği tarafından reddedilir. JOIN'den sonra uygulanır. Tablolardan birinde filtreleme ile tam bir dış birleştirme yapmak için, WHERE yan tümcesini bir alt sorgunun içine koymanız gerekir, bu nedenle süzme, üyeliğinden önce olur veya tüm WHERE ölçütlerinizi JOIN ON yan tümcesi üzerine oluşturmaya çalışır, çılgınca çirkin olan. Aslında bunu yapmak için güzel bir yol yok.

@Jonas: Bu göz önüne alındığında: Ayrıca

, rapor mali yıl için aslında - Ben söz hakkından hiçbir satış ay 5 oldu hem eğer 0 ile boş sütunlar sahip olmak isterdim böylece ya 2007 veya

2008. ve bu işi oldukça sorgu ile yapılamaz gerçeği, kesinlikle aslında istediğiniz sonuçları almak için çalışacağını söyledi. Çirkin bir sorguya sahip olmanın ve gerçekte istediğiniz gerçek verileri bile almanın bir anlamı yok.Sonuçlarınız 1-12 içinde olan, on iki satırlarla
2. doldurulmasını eşleştirebilmemizi
1. İstediğiniz formatta geçici bir tablo oluşturmak:;)

Yani, 5 adımda bunu öneririm ay sütun
3. güncelleme SP2 mantığı kullanarak SP1 mantığı
4. güncelleme "Geçen Yıl" sütunu kullanarak "Bu Yıl" sütununda
5. elbette

geçici tablodan seçmek ben Bunu gerçekleştirmek için saklı bir yordam oluşturabileceğiniz varsayımından çalışıyorum. Teknik olarak tüm bu seriyi inline çalıştırabilirsiniz, ancak bu tür çirkinlik çok nadir görülür. Bir SP yapamazsanız, alt sorgu yoluyla tam dış birleştirme sürecine geri dönmenizi öneririm, ancak her iki ayda bir satış olmadığı zaman size bir satır alamazsınız.

1

İşaretleme hakkında - Evet bu sinir bozucu. Editör HTML tablosumu önizlemişti, ancak yayınladıktan sonra gitmişti - Bu yüzden tüm HTML biçimlendirmelerini postadan kaldırmak zorunda kaldım ...

Kcrumley Sanırım benzer sonuçlara vardık. Bu sorgu kolayca çirkin oluyor. Benzer bir (ama yine de farklı bir yaklaşım) kullanarak cevabınızı okumadan önce bunu çözdüm. Raporlama veritabanında saklı yordamları ve işlevleri oluşturmak için erişimim var. Bir ürün kategorisini ve bir mali yılı parametre olarak kabul eden bir Tablo Değerli işlev oluşturdum. Buna bağlı olarak, işlev 12 satır içeren bir tabloyu dolduracaktır. Satır mevcut değilse, satırlar 0 değerine sahipse, satırlar görünümden veriyle doldurulur.

Daha sonra işlevler tarafından döndürülen iki tabloya katılıyorum. Biliyorum bu yana tüm tabloları daha kolay tahsis var oniki Roves olacak ve ben Ürün Kategorisi ve Ay üzerinde katılabilirsiniz:

SELECT 
    SP1.Program, 
    SP1.Year, 
    SP1.Month, 
    SP1.TotalRevenue AS ThisYearRevenue, 
    SP2.TotalRevenue AS LastYearRevenue 
FROM GetFinancialYear(@Category, 'First Look', 2008) AS SP1 
    RIGHT JOIN GetFinancialYear(@Category, 'First Look', 2007) AS SP2 ON 
     SP1.Program = SP2.Program AND 
     SP1.Month = SP2.Month 

Ben GetFinancialYear fonksiyonu oldukça dağınık olduğu gibi yaklaşımınız muhtemelen biraz daha temiz olduğunu düşünüyorum! Ama en azından çalışır - şimdi beni mutlu ediyor;)

1

hüner bir TAM ISNULL en ya tablodan katılan sütunlar almak ile, JOIN yapmaktır. Genellikle bunu bir görünüm veya türetilmiş bir tabloya sardım, aksi takdirde ISHERI WHERE yan tümcesinde de kullanmanız gerekir.

SELECT 
    Program, 
    Month, 
    ThisYearTotalRevenue, 
    PriorYearTotalRevenue 
FROM (
    SELECT 
     ISNULL(ThisYear.Program, PriorYear.Program) as Program, 
     ISNULL(ThisYear.Month, PriorYear.Month), 
     ISNULL(ThisYear.TotalRevenue, 0) as ThisYearTotalRevenue, 
     ISNULL(PriorYear.TotalRevenue, 0) as PriorYearTotalRevenue 
    FROM (
     SELECT Program, Month, SUM(TotalRevenue) as TotalRevenue 
     FROM PVMonthlyStatusReport 
     WHERE Year = @FinancialYear 
     GROUP BY Program, Month 
    ) as ThisYear 
    FULL OUTER JOIN (
     SELECT Program, Month, SUM(TotalRevenue) as TotalRevenue 
     FROM PVMonthlyStatusReport 
     WHERE Year = (@FinancialYear - 1) 
     GROUP BY Program, Month 
    ) as PriorYear ON 
     ThisYear.Program = PriorYear.Program 
     AND ThisYear.Month = PriorYear.Month 
) as Revenue 
WHERE 
    Program = 'Bikes' 
ORDER BY 
    Month 

Bu, minimum gereksinimlerinizi almalıdır - 2007 veya 2008'de veya her ikisinde de satışa sahip satırlar. Her iki yılda da hiçbir satış yapmadan satır almak için, 1-12 sayılı bir tabloya (1 have one of those yaparsanız, INNER JOIN) ihtiyacınız var, değil mi?

0

kullanma Pivot ve Dinamik SQL biz bu sonucu elde edebilirsiniz

SET NOCOUNT ON 
IF OBJECT_ID('TEMPDB..#TEMP') IS NOT NULL 
DROP TABLE #TEMP 

;With cte(Category , Revenue , Yearh , [Month]) 
AS 
(
SELECT 'Bikes', 10000, 2008,1 UNION ALL 
SELECT 'Bikes', 12000, 2008,2 UNION ALL 
SELECT 'Bikes', 12000, 2008,3 UNION ALL 
SELECT 'Bikes', 15000, 2008,1 UNION ALL 
SELECT 'Bikes', 11000, 2007,2 UNION ALL 
SELECT 'Bikes', 11500, 2007,3 UNION ALL 
SELECT 'Bikes', 15400, 2007,4 
) 
SELECT * INTO #Temp FROM cte 

Declare @Column nvarchar(max), 
     @Column2 nvarchar(max), 
     @Sql nvarchar(max) 


SELECT @Column=STUFF((SELECT DISTINCT ','+ 'ISNULL('+QUOTENAME(CAST(Yearh AS VArchar(10)))+','+'''0'''+')'+ 'AS '+ QUOTENAME(CAST(Yearh AS VArchar(10))) 
FROM #Temp order by 1 desc FOR XML PATH ('')),1,1,'') 

SELECT @Column2=STUFF((SELECT DISTINCT ','+ QUOTENAME(CAST(Yearh AS VArchar(10))) 
FROM #Temp FOR XML PATH ('')),1,1,'') 

SET @Sql= N'SELECT Category,[Month],'+ @Column +'FRom #Temp 
      PIVOT 
      (MIN(Revenue) FOR yearh IN ('[email protected]+') 
      ) AS Pvt 

      ' 
EXEC(@Sql) 
Print @Sql 

Sonucu

Category Month 2008 2007 
---------------------------------- 
Bikes  1  10000 0 
Bikes  2  12000 11000 
Bikes  3  12000 11500 
Bikes  4  0  15400