Group by and having clauses

標準 group by 和 having 查詢

  • 選擇列表中的列必須也出現(xiàn)在 group by 表達式中著榴,或者必須是集合函數(shù)的參數(shù)。
  • group by 表達式只能包含選擇列表中出現(xiàn)的列名泌类。不過,選擇列表中僅作為集合函數(shù)的參數(shù)使用的列不適用此限定痹屹。
  • having 表達式中的列必須是單值的(例如集合的參數(shù))境氢,而且它們必須出現(xiàn)在選擇列表或 group by 子句中。使用選擇列表集合和 having 子句的查詢必須 包含 group by 子句车要。如果在未使用選擇列表集合的查詢中省略 group by允粤,則所有未被 where 子句排除的行將被視為單個組。

在非分組查詢中翼岁,“使用 where 排除行”的原則非常簡單直接类垫。在分組查詢中,此原則擴展為“使用 where 在 group by 之前排除行琅坡,使用 having 從顯示的結(jié)果中排除行”

  • SQL 標準允許連接兩個或更多表的查詢使用 group by 和 having悉患,只要它們遵循上述原則。指定連接或其它復(fù)雜查詢時榆俺,請使用groupby和having的標準語法售躁,除非您完全理解Transact-SQL擴展對這兩個子句的影響。

group by 和 having 的 Transact-SQL 擴展

對標準 SQL 的 Transact-SQL 擴展使得數(shù)據(jù)的顯示更加靈活茴晋,因為在擴展中允許引用未在創(chuàng)建組或摘要計算時使用的列和表達式:

  • 包含集合的選擇列表可以包含既不是集合函數(shù)的參數(shù)迂求,又未包含在 group by 子句中的擴展 列。擴展列影響最終結(jié)果的顯示晃跺,因為顯示了附加的行揩局。

  • group by 子句可包含未列于選擇列表中的列或表達式。

  • group by all 子句顯示所有組掀虎,甚至是那些由 where 子句從計算中排除的組凌盯。

  • having 子句可以包含未出現(xiàn)在選擇列表以及 group by 子句中的列或表達式付枫。

Transact-SQL 擴展將行或列添加到顯示中時,或省略 group by 時驰怎,查詢結(jié)果可能難以理解阐滩。

實例解析

One long running SQL in my work. It is a wrong SQL in fact:

  • 問題
    這個SQL語句最后取的是笛卡爾積,而不是看上去想要的內(nèi)容
SELECT                                                                                                                                                                                                                                                          
     p.party_id,                                                                                                                                                                                                                                                 
     p.party_ticker,                                                                                                                                                                                                                                             
     p.party_rtr_ticker,                                                                                                                                                                                                                                         
     p.dbs_cid,                                                                                                                                                                                                                                                  
     p.party_cntry_incorp_cd,                                                                                                                                                                                                                                    
     p.party_long_name,                                                                                                                                                                                                                                          
     p.debt_issued_fl,                                                                                                                                                                                                                                           
     p.party_setup_dt,                                                                                                                                                                                                                                           
     e.last_chg_dt,                                                                                                                                                                                                                                              
     datediff(hour, e.last_chg_dt, getdate() ) AS AGE_in_hours                                                                                                                                                                                                   
 FROM                                                                                                                                                                                                                                                            
     dmo_govcorp..party p, dmo_misc..entity_changed e                                                                                                                                                                                                            
 where     e.obj_oid = p.party_id                                                                                                                                                                                                                                
       AND e.obj_type_cd = 'GCPA'                                                                                                                                                                                                                                
 GROUP BY                                                                                                                                                                                                                                                        
     p.party_rtr_ticker                                                                                                                                                                                                                                          
 HAVING                                                                                                                                                                                                                                                          
     (COUNT(p.party_rtr_ticker)>1) 
  • 排解過程
    運行SQL發(fā)現(xiàn)县忌,從Select列表中去掉第二個表dmo_misc..entity_changed的項掂榔,可以得到我們想要的結(jié)果。查閱相關(guān)文檔發(fā)現(xiàn)症杏,如果在select列表包含既不是集合函數(shù)的參數(shù)装获,那么就是Transact-SQL 擴展的group by, 這種方式有時看起來就像一個查詢忽略了where 子句
  • 解決
    We can solve the problem by adding all the conditions in where clauses into having clauses as below to solve it as below:
SELECT                                                                                                                                                                                                                                                          
     p.party_id,                                                                                                                                                                                                                                                 
     p.party_ticker,                                                                                                                                                                                                                                             
     p.party_rtr_ticker,                                                                                                                                                                                                                                         
     p.dbs_cid,                                                                                                                                                                                                                                                  
     p.party_cntry_incorp_cd,                                                                                                                                                                                                                                    
     p.party_long_name,                                                                                                                                                                                                                                          
     p.debt_issued_fl,                                                                                                                                                                                                                                           
     p.party_setup_dt,                                                                                                                                                                                                                                           
     e.last_chg_dt,                                                                                                                                                                                                                                              
     datediff(hour, e.last_chg_dt, getdate() ) AS AGE_in_hours                                                                                                                                                                                                   
 FROM                                                                                                                                                                                                                                                            
     dmo_govcorp..party p, dmo_misc..entity_changed e                                                                                                                                                                                                            
 where     e.obj_oid = p.party_id                                                                                                                                                                                                                                
       AND e.obj_type_cd = 'GCPA'                                                                                                                                                                                                                                
 GROUP BY                                                                                                                                                                                                                                                        
     p.party_rtr_ticker                                                                                                                                                                                                                                          
 HAVING                                                                                                                                                                                                                                                          
     (COUNT(p.party_rtr_ticker)>1)  and e.obj_oid = p.party_id and e.obj_type_cd = 'GCPA' 
  • Finding
    打開統(tǒng)計信息發(fā)現(xiàn)直接將where后的條件加到having后邊跟先將分組的選出來厉颤,放到放在select的字句里效果是一樣的穴豫,推測兩者在數(shù)據(jù)庫內(nèi)部實現(xiàn)機制是一樣的。

以下為參考資料:

在 select 列表中使用不在 group by 列表中且不包含集合函數(shù)的列是一種Transact-SQL 擴展逼友。 擴展列影響最終結(jié)果的顯示精肃,因為顯示了附加的行。

Transact-SQL 擴展將行或列添加到顯示中時, 查詢結(jié)果可能難以理解帜乞。處理 Transact-SQL 擴展列的方式有時看起來就像一個查詢忽略了where 子句司抱。示例如下:

Adaptive Server 首先使用 where 子句創(chuàng)建一個僅包含類型和集合值的工作表。此工作表通過分組列 type 連接回 titles 表黎烈,以在結(jié)果中包括 price 列习柠,但連接中沒有 使用 where 子句。

select type, price, avg(price)
from titles
where price > 10.00
group by type
type price
------------ ---------------- --------------
business 19.99 17.31
business 11.95 17.31
business 2.99 17.31
business 19.99 17.31
mod_cook 19.99 19.99
mod_cook 2.99 19.99
popular_comp 22.95 21.48
popular_comp 20.00 21.48
popular_comp NULL 21.48
psychology 21.59 17.51
psychology 10.95 17.51
psychology 7.00 17.51
psychology 19.99 17.51
psychology 7.99 17.51
trad_cook 20.95 15.96
trad_cook 11.95 15.96
trad_cook 14.99 15.96
(17 rows affected)

如果還想在顯示的結(jié)果中去除價格低于 $10.00 的行怨喘,就必須添加一個重復(fù) where 子句的 having 子句

select type, price, avg(price)
from titles
where price > 10.00
group by type
having price > 10.00
type price
----------- ---------------- --------------
business 19.99 17.31
business 11.95 17.31
business 19.99 17.31
mod_cook 19.99 19.99
popular_comp 22.95 21.48
popular_comp 20.00 21.48
psychology 21.59 17.51
psychology 10.95 17.51
psychology 19.99 17.51
trad_cook 20.95 15.96
trad_cook 11.95 15.96
trad_cook 14.99 15.96
(12 rows affected)

參考文獻:Sybase 參考手冊:命令A(yù)daptive Server? Enterprise 15.0

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市振定,隨后出現(xiàn)的幾起案子必怜,更是在濱河造成了極大的恐慌,老刑警劉巖后频,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梳庆,死亡現(xiàn)場離奇詭異,居然都是意外死亡卑惜,警方通過查閱死者的電腦和手機膏执,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來露久,“玉大人更米,你說我怎么就攤上這事『梁郏” “怎么了征峦?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵迟几,是天一觀的道長。 經(jīng)常有香客問我栏笆,道長类腮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任蛉加,我火速辦了婚禮蚜枢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘针饥。我一直安慰自己厂抽,他們只是感情好,可當我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布打厘。 她就那樣靜靜地躺著修肠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪户盯。 梳的紋絲不亂的頭發(fā)上嵌施,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天,我揣著相機與錄音莽鸭,去河邊找鬼吗伤。 笑死,一個胖子當著我的面吹牛硫眨,可吹牛的內(nèi)容都是我干的足淆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼礁阁,長吁一口氣:“原來是場噩夢啊……” “哼巧号!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起姥闭,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤丹鸿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后棚品,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體靠欢,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年铜跑,在試婚紗的時候發(fā)現(xiàn)自己被綠了门怪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡锅纺,死狀恐怖掷空,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤拣帽,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布疼电,位于F島的核電站,受9級特大地震影響减拭,放射性物質(zhì)發(fā)生泄漏蔽豺。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一拧粪、第九天 我趴在偏房一處隱蔽的房頂上張望修陡。 院中可真熱鬧,春花似錦可霎、人聲如沸魄鸦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拾因。三九已至,卻和暖如春旷余,著一層夾襖步出監(jiān)牢的瞬間绢记,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工正卧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蠢熄,地道東北人。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓炉旷,卻偏偏與公主長得像签孔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子窘行,可洞房花燭夜當晚...
    茶點故事閱讀 44,678評論 2 354

推薦閱讀更多精彩內(nèi)容