SQL 查詢本月無數據用上個月的數據
前言
因為標題有長度限制,先簡要說明一下應用場景。比如我們要查一段時間范圍內(2013-08-01至2013-12-31)每個月每個運營商的用戶總量,每個運營商用戶量每個月更新的時間可能不同也可能該月沒有數據,如果某個運營商本月用戶量沒有值,則用上個月的用戶量。
下面就給大家一步一步分析,解決該問題。
1. 創建基礎的表和示例數據
首先我們需要創建一個用戶量表,具體的表結構和表內容如下:
2. 分析題目要求
通過對前言中描述的應用場景分析,我們可以得出以下幾點訊息:
l 獲取一個時間范圍內的各個運營商的各個月的數據
l 個別運營商本月無數據的用距離本月日期最近的數據
結合上邊的示例數據分析,也就是如果我們要求2013-09-01到2013-12-31之間各個運營商這幾個月的數據得到的結果應該是如下圖所示:
上圖中紅框標注的部分在數據庫中是不存在的,也就是說12月份數據庫中沒有數據,我們就使用距離12月最近的數據。
3. 逐步解決問題
題目要求的是求一個時間段內的幾個月的各運營商的用戶總量,這樣我們先把問題分解,先求出一個月的各運營商的用戶總量。
3.1要求一個月的各運營商的用戶總量,我們先求出該月或者據該月最近的用戶總量更新的日期。
為了更好的做演示示例,12月份沒有數據,我們就用12月份來做演示。
具體代碼如下:
select SP_Name as name,MAX(Create_Date) as "group" from UserCount where Create_Date<'2013-12-31' group by SP_Name
執行結果如下:
3.2求出該月的最近的更新日期后,求出相對應的值.
具體代碼如下:
with sub as ( select SP_Name as name,MAX(Create_Date) as "group" from UserCount where Create_Date<'2013-12-31' group by SP_Name ) select us.SP_Name as "name",'201312' as "date" ,SUM(us.User_Count) as "value" from UserCount us right join sub s on s.name=us.SP_Name where us.Create_Date=s."group" group by us.SP_Name,s."group"
執行結果如下:
這樣我們就完成的題目所需的求出某個月的用戶量,且該月沒有值,采用距離該月日期最近的更新日期的值。
3.3 循環求出每個月的用戶量,最后將幾個月的用戶量合並
但是,問題又來了,既然我們求出了某一個月的值,那么如何求出一個時間范圍內也就是幾個月的用戶量呢?
很明顯,這需要通過循環分別查出時間范圍內每一個月的值,然后將這些值Union就可以了。為了考慮到實用性,我們將這一部分的操作封裝在一個函數里。
具體代碼如下:
create procedure getMonthData(@str1 varchar(200),@str2 varchar(200))--傳入兩個日期范圍的字符串,形如:20130901, as declare @date1 date;--定義兩個日期變量,用來將傳入的字符串轉換為時間,並作為循環的控制條件 declare @date2 date; begin set @date1=DATEADD("mm",1,cast(@str1+'01' as date));--處理傳入的字符串,轉換為時間默認為, set @date2=DATEADD("mm",1,cast(@str2+'01' as date)); create table #temp1 (name varchar(200),"group" varchar(200),"value" int);--創建一個臨時表用來存儲每次循環產生的數據,相當於將每個月查詢出的數據union while @date1<=@date2 begin with sub as --求出當前月,用戶量最新的更新日期 ( select SP_NAME as "name",MAX(Create_Date) as "value" from UserCount where Create_Date<@date1 group by SP_NAME ), sub1 as --求出當前月各運營商的用戶總量 ( select SP_NAME as "name",@str1 as "group",MAX(User_Count) as "value" from UserCount ue right join sub s on s."name"=ue.SP_NAME group by ue.SP_NAME ) insert into #temp1 select * from sub1 --將當前月的用戶總量插入的臨時表保存 set @date1=dateadd("mm",1,@date1)--更改循環條件 set @str1=cast(CAST(@str1 as int )+1 as varchar(200))--更改月份 end select * from #temp1;--查詢臨時表,展現所有的數據 end
具體結果如下:
這樣就基本上上完成的題目的要求了,但是,這還不是最完美的,請注意上邊黃色高亮部分,如果日期為參數為201309,201401時,查詢出來的結果就是這樣的。
也就是說在日前跨年的情況下,月份的展示是亂的,這樣我們可以再創建一個函數處理這樣的問題。
具體代碼如下:
create function modifydate(@date varchar(200)) returns varchar(200) as begin declare @month int; set @month=cast(SUBSTRING(@date,5,2) as int) if @month>12 begin set @date=cast(cast(SUBSTRING(@date,1,4) as int)+@month/12 as varchar) + (case when @month%12=0 then '01' when @month%12<10 then '0'+CAST(@month%12 as varchar) else CAST(@month%12 as varchar) end) end return @date; end
這樣就很好的解決了跨年時顯示的日期格式不正確的問題,同時還需要將上邊高亮的那一行代碼改為如下代碼即可:
set @str1=dbo.modifydate(cast(CAST(@str1 as int )+1 as varchar(200)))--更改月份
好了,今天就總結到這里了,希望能給大家一些幫助。主要是一個思路吧,之前寫過一個同樣需求的sql,當時就只是用一個sql語句就實現了,但是時間長了,忘了怎么做的,回頭找找,再跟大家分享。