SQL 查詢本月無數據用上個月的數據問題


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語句就實現了,但是時間長了,忘了怎么做的,回頭找找,再跟大家分享。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM