最近做的一個財物管理系統中查詢過期或逾期的存儲過程,返回 “財物所屬的案件名稱”,“財物名稱”,“財物編號”,“
過期或逾期時間
”(超期或逾期前7天開始預警)。
遇到“
union all 內不能使用
order by
”的問題,百度了很久,都沒有一個找到一個好的解決方案。最終還是自己實現了,記錄一下。
為什么用存儲過程,非得用union all 而不在程序中拼接表數據?
這個
存儲過程不是供我們Web程序使用的,它是提供給運行在服務器上的C/S程序調用(
用來投放到機房外的LED顯示屏
)。
因為這個C/S程序不是我們寫的,別人要求用存儲過程並一次性返回超期和預期的數據。
當時我正在客戶那里安裝這個系統,這個功能是客戶臨時加的,所以就匆忙趕了一個,當時沒排序,回來后整理時才遇到這個問題。
涉及到的數據庫表(字段):
案件表【
AnJian
】
:(Id,案件名稱【anjianmingcheng】)
財物表【
CaiWu
】
:(Id,所屬案件【Id]anjianId】,財物編號【caiwubianhao】,財物名稱【
caiwumingcheng】,保存指定的保存結束時間【caoqi】
)
財物調用記錄表【
CaiWuDiaoYongJiLu
】
:(Id,被調用財物Id【caiwuId】,調用時指定的歸還時間【yujingTime】)
注 保存結束時間和調用歸還時間不能為空,如果是長期會在程序中指定一個超大的時間值(9999/12/30)。
最初版本:

1 ALTER proc [dbo].[pr_get_time_limit] 2 3 as 4 5 select 6 cast(a.anjianmingcheng as varchar(100)) as anjianmingcheng, 7 cast(c.caiwumingcheng as varchar(100)) as caiwumingcheng, 8 cast(c.caiwubianhao as varchar(100)) as caiwubianhao, 9 case 10 when datediff(day,c.caoqi,getdate())> 0 then '保存超期'+cast(abs(datediff(day,c.caoqi,getdate())) as varchar(50))+'天' 11 else cast(abs(datediff(day,c.caoqi,getdate())) as varchar(50))+'天后保存超期' 12 end as state, 13 c.caoqi as tagtime 14 from SACW_CaiWu c 15 left join SACW_CaiWuDiaoYongJiLu as d on c.Id=d.caiwuId 16 left join SACW_AnJian as a on c.anjianId=a.id 17 where c.jiazhijine>0 and getdate()>dateadd(day,-7,c.caoqi) or c.kucunshuliang>0 and getdate()>dateadd(day,-7,c.caoqi) 18 19 union all 20 21 select 22 cast(a.anjianmingcheng as varchar(100)) as anjianmingcheng, 23 cast(c.caiwumingcheng as varchar(100)) as caiwumingcheng, 24 cast(c.caiwubianhao as varchar(100)) as caiwubianhao, 25 case 26 when datediff(day,d.yujingTime,getdate())> 0 then '歸還逾期'+cast(abs(datediff(day,d.yujingTime,getdate())) as varchar(50))+'天' 27 else cast(abs(datediff(day,d.yujingTime,getdate())) as varchar(50))+'天后歸還逾期' 28 end as state, 29 d.yujingTime as tagtime 30 from SACW_CaiWuDiaoYongJiLu d 31 left join SACW_CaiWu c on c.Id=d.caiwuId 32 left join SACW_AnJian as a on c.anjianId=a.id 33 where d.jiazhijine>0 and getdate()> dateadd(day,-7,d.yujingTime) or d.caiwushuliang>0 and getdate()>dateadd(day,-7,d.yujingTime)
優化后的代碼:

1 ALTER proc [dbo].[pr_get_time_limit] 2 3 as 4 5 DECLARE @TempTime datetime 6 SET @TempTime = DATEADD(DAY,7,GETDATE()) 7 8 SELECT 9 a.anjianmingcheng as [anjianmingcheng], 10 t.cm as [caiwumingcheng], 11 t.cb as [caiwubianhao], 12 t.tagtime as [tagtime], 13 case 14 when t.orderby = 0 then 15 case 16 when t.timeSpan > 0 then '調用逾期'+cast(t.timeSpan as varchar(50))+'天' 17 --when t.timeSpan = 0 then '即將逾期' 18 else cast(abs(t.timeSpan) as varchar(50))+'天后調用逾期' 19 end 20 else 21 case 22 when t.timeSpan > 0 then '保存超期'+cast(t.timeSpan as varchar(50))+'天' 23 --when t.timeSpan = 0 then '即將超期' 24 else cast(abs(t.timeSpan) as varchar(50))+'天后保存超期' 25 end 26 end as [state] 27 28 FROM ( 29 select 30 c.anjianId as aid, 31 cast(c.caiwumingcheng as varchar(100)) as cm, 32 cast(c.caiwubianhao as varchar(100)) as cb, 33 datediff(day,d.yujingTime,getdate()) as timeSpan, 34 d.yujingTime as tagtime, 35 0 as orderby 36 from SACW_CaiWuDiaoYongJiLu d 37 left join SACW_CaiWu c on c.Id=d.caiwuId 38 where (d.jiazhijine>0 or d.caiwushuliang>0) and @TempTime > d.yujingTime 39 40 union all 41 42 select 43 c.anjianId as aid, 44 cast(c.caiwumingcheng as varchar(100)) as cm, 45 cast(c.caiwubianhao as varchar(100)) as cb, 46 datediff(day,c.caoqi,getdate()) as timeSpan, 47 c.caoqi as tagtime, 48 1 as orderby 49 from SACW_CaiWu c 50 where (c.jiazhijine>0 or c.kucunshuliang>0) and @TempTime > c.caoqi 51 ) as t 52 left join SACW_AnJian as a on t.aid=a.id 53 order by t.orderby,t.timeSpan
問題,最初版本中的代碼中datediff函數計算值怎樣用一個臨時變量存起來供后面使用,而不是重新計算。不知道這樣寫在存儲過程中會不會有性能損失(理論上的)。
網上其它相關解決方案:
關於union all中使用多個order by 子句引起的問題
UNION ALL 子句不能包含ORDER BY的解決之道
union all和order by一起使用出問題
order by 和union all 如何共存