如何使用SQL視窗子句減少語法開銷

2021-08-29 23:17:57 字數 4613 閱讀 2920

sql是一種冗長的語言,其中最冗長的特性之一是視窗函式.

在.最近遇到的堆疊溢位問題,有人要求計算某一特定日期的時間序列中的第乙個值和最後乙個值之間的差額:

輸入

volume  tstamp
---------------------------
29011   2012-12-28 09:00:00
28701   2012-12-28 10:00:00
28830   2012-12-28 11:00:00
28353   2012-12-28 12:00:00
28642   2012-12-28 13:00:00
28583   2012-12-28 14:00:00
28800   2012-12-29 09:00:00
28751   2012-12-29 10:00:00
28670   2012-12-29 11:00:00
28621   2012-12-29 12:00:00
28599   2012-12-29 13:00:00
28278   2012-12-29 14:00:00
期望輸出

first  last   difference  date
------------------------------------
29011  28583  428         2012-12-28
28800  28278  522         2012-12-29
請注意,值和時間戳級數可能不相關。所以,沒有一條規定如果timestamp2 > timestamp1然後value2 < value1。否則,這個簡單的查詢就能工作(使用postgresql語法):

select
max(volume)               as first,
min(volume)               as last,
max(volume) - min(volume) as difference,
cast(tstamp as date)      as date
from t
group by cast(tstamp as date);
有幾種方法可以在不涉及視窗函式的組中找到第乙個和最後乙個值。例如:

有關各種方法的更多細節可以在這裡找到:

最好的方法是使用像oracle這樣的聚合函式,但是很少有資料庫具有這種功能。所以,我們將使用first_valuelast_value視窗函式:

select distinct
first_value(volume) over (
partition by cast(tstamp as date)
order by tstamp
rows between unbounded preceding and unbounded following
) as first,
last_value(volume) over (
partition by cast(tstamp as date)
order by tstamp
rows between unbounded preceding and unbounded following
) as last,
first_value(volume) over (
partition by cast(tstamp as date)
order by tstamp
rows between unbounded preceding and unbounded following
)
- last_value(volume) over (
partition by cast(tstamp as date)
order by tstamp
rows between unbounded preceding and unbounded following
) as diff,
cast(tstamp as date) as date
from t
order by cast(tstamp as date)
哎呀。

看上去不太容易讀。但它將產生正確的結果。當然,我們可以包裝列的定義。firstlast在派生表中,但這仍然會給我們留下兩次視窗定義的重複:

partition by cast(tstamp as date)
order by tstamp
rows between unbounded preceding and unbounded following
幸運的是,至少有3個資料庫實現了sql標準。window條款:

上面的查詢可以重構為這個查詢:

select distinct
first_value(volume) over w as first,
last_value(volume) over w as last,
first_value(volume) over w
- last_value(volume) over w as diff,
cast(tstamp as date) as date
from t
window w as (
partition by cast(tstamp as date)
order by tstamp
rows between unbounded preceding and unbounded following
)
order by cast(tstamp as date)
請注意,如何使用視窗規範來指定視窗名稱,就像定義公共表示式一樣(with條款):

window
as ()
我不僅可以重用整個規範,還可以根據部分規範構建規範,並且只重用部分規範。我以前的查詢可以這樣重寫:

select distinct
first_value(volume) over w3 as first,
last_value(volume) over w3 as last,
first_value(volume) over w3
- last_value(volume) over w3 as diff,
cast(tstamp as date) as date
from t
window
w1 as (partition by cast(tstamp as date)),
w2 as (w1 order by tstamp),
w3 as (w2 rows between unbounded preceding
and unbounded following)
order by cast(tstamp as date)
每個視窗規範可以從頭建立,也可以基於先前定義的視窗規範。注在引用視窗定義時也是如此。如果我想重用partition by條款和order by子句,但請更改frame條款(rows ...),那麼我就可以這樣寫了:

select distinct
first_value(volume) over (
w2 rows between unbounded preceding and current row
) as first,
last_value(volume) over (
w2 rows between current row and unbounded following
) as last,
first_value(volume) over (
w2 rows unbounded preceding
) - last_value(volume) over (
w2 rows between 1 preceding and unbounded following
) as diff,
cast(tstamp as date) as date
from t
window
w1 as (partition by cast(tstamp as date)),
w2 as (w1 order by tstamp)
order by cast(tstamp as date)

SQL 過濾資料(使用WHERE子句)

只檢索所需要資料需要指定搜尋條件,搜尋條件也稱為過濾條件。在select語句中,資料根據where子句中指定的搜尋條件進行過濾,即where 子句用於過濾記錄,也就是where 子句用於提取那些滿足指定標準的記錄。where子句在表名 from子句 之後給出。where子句不僅用於select語法,...

如何優雅地拼SQL的in子句

in 語句如何優雅拼接 name list 在專案中,經常會碰到這樣的場景,要按 name list 獲取這些name對應的記錄,比如要獲取 king,jones,ford 對應的記錄,顯然想到的是使用 in 子句,比如 select id from employee where emp name ...

如何使用 Xmonad,Linux的平鋪視窗管理器

平鋪視窗管理器讓你在螢幕上自動排列 windows,使你的生活變得更加輕鬆。xmonad是乙個很容易開始的最簡單的方法 你只需要學習一些鍵盤快捷鍵。xmonad也是高度可以配置的。儘管如這裡,如果不希望 它不能從框中工作,就不必觸控配置檔案。預設情況下,xmonad不包括應用程式啟動器。你可能還需要...