English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
今日、この記事を見て、内容がとても豊富だと思いましたが、とても乱れており、整理が難しいです。ナイアラ教程編集者が簡単に整理しましたので、皆さん、なんとか見てください。
グループ化後の分组合計および合計SQL文
1)想一次性に分组合計および合計を取得するSQL:
SELECT 分組字段 FROM 表
GROUP BY 分組字段
compute sum(COUNT(*))
2)分组合計1:
SELECT COUNT(*) FROM (SELECT 分組字段 FROM 表 GROUP BY 分組字段 )別名
3)分组合計2:
SELECT COUNT(*) FROM (SELECT distinct 分組字段 FROM 表)別名
4)統計グループ化後の種類数:
例1:分组合計
SELECT JSSKQK_JGH FROM SJ_JSSKQK WHERE JSSKQK_JGH IN (SELECT JSJBXX_JGH FROM SJ_JSJBXX WHERE JSJBXX_JSLXM1=1) GROUP BY JSSKQK_JGH HAVING ((SUM(JSSKQK_SSKCXS1) /40)>5)
上記の文はグループ化を満たすことができます。仮に実行すると、3件の記録、どうやってこのCOUNT値を求めますか?63;
select count(*) from ( SELECT JSSKQK_JGH FROM SJ_JSSKQK WHERE JSSKQK_JGH IN (SELECT JSJBXX_JGH FROM SJ_JSJBXX WHERE JSJBXX_JSLXM1=1) GROUP BY JSSKQK_JGH HAVING ((SUM(JSSKQK_SSKCXS1) /40)>5) ) t
例2:[PL/SQL] グループ化後、グループ内の最大の日付のレコードをどうやって取得しますか?
TABLE:A
A B C D
1 2001/01/01 1 1
1 2001/12/12 2 2
3 2002/01/01 3 3
3 2003/12/12 4 4
列Aでグループ化することで、各グループの最大のデータをどうやって取得できますか?
1 2001/12/12 2 2
3 2003/12/12 4 4
私の愚かな方法:
SELECT * FROM A WHERE (A,B) IN( SELECT A,MAX(B) FROM A GROUP BY A )
もっと良い方法はありますか?
1、select * from a out
where b = (select max(b) from a in
where in.a = out.a)
2、Select * from
(select a, row_number() over (partition by a
order by b desc) rn
from a)
where rn=1
3、Select a, b,c,d from
(select a, b,c,d,row_number() over (partition by a
order by b desc) rn
from a)
where rn=1
4、select A,B,C,D from test
where rowid in
(
select rd from
(
select rowid rd ,rank() over(partition A order by B desc)rk from test
) where rk=1
)
)
例3:SQL文をグループ化してレコードの最初のデータを取得する方法
Northwind データベースを使用して
まず Employeesテーブルをクエリします
クエリ結果:
cityカラムには5の市
ROW_NUMBER() OVER(PARTITION BY COL1 ORDER BY COL2) を先にグループ化します 注意:COL1グループ化し、グループ内で COL2ソートを行い、この関数が計算する値は各グループ内のソート後の順序番号を表します(各グループ内の連続するユニークな)。
SQL文は以下の通りです:
select EmployeeID,LastName,FirstName,Title,TitleOfCourtesy,City,ROW_NUMBER() over(partition by City order by EmployeeID) as new_index
from Employees
実行結果図:
Cityに基づいてグループ化され、EmployeeIDでソートされていることがわかります。
グループ内の最初のレコードを選択します
実行文:
select * from
(選択 EmployeeID,LastName,FirstName,Title,TitleOfCourtesy,City,ROW_NUMBER() over(partition by City order by EmployeeID) as new_index
from Employees) a where a.new_index=1
from Employees) a where a.new_index=
例4実行結果図:
:sql 获取分组结果后,如何每一组的第一条记录 20
Eric red 30
eric blue 10
andy red 5
andy blue
1例えば、只获取黑体的记录。10、declare @fTable table (fName varchar(10), fColor varchar(
), fOrder int) 20)
insert into @fTable values('Eric', 'red', 30)
insert into @fTable values('eric', 'blue', 10)
insert into @fTable values('andy', 'red', 5)
-- insert into @fTable values('andy', 'blue',
select * 只获取红色
-- from @fTable where fColor = 'red'
select * from @fTable A where fName = (select top 1 各fColorから一つのレコードを取得(fOrderの順序で並べ替え)
-- 各fColorから一つのレコードを取得(fOrderの逆順で並べ替え)
select * from @fTable A where fName = (select top 1 fName from @fTable where fColor = A.fColor order by fOrder desc)
2、SQL2005以上のバージョン
select * from (select *,row=row_number()over(partition by Color order by Color) from table1)t where row=1 and color='xx'--条件を追加
SQL2000用 top 1
例5:一つのSQL文でグループ化して、各グループのレコード数を限定
このような結果セットを取得したい場合:グループ化して、各グループのレコード数を限定する、一つのSQL文でできますか?
例えば、学生の期末試験の成績で、各科目の前3名,一つのSQL文で、どう書けますか?
表[TScore]的结构
code 学号 char
subject 科目 int
score 成绩 int
可以这样写:
SELECT [code]
[subject]
[score]
FROM (
SELECT *
,RANK() OVER(PARTITION BY subject ORDER BY score DESC) AS Row
FROM TScore
) AS a
WHERE Row <= 3 ;
例6:SQL获取每个分组的第一条记录
SQL查询以下伪数据获取粗体字行的记录
ID,Name,ItemID,Price,CreatedOn
1 a 1 10.00 xxx1
2 a 1 12.00 xxx2
3 b 1 9.00 xxx1
4 b 1 11.50 xxx2
5 c 1 20.00 xxx1
6 a 2 21.00 xxx1
7 a 2 23.00 xxx2
8 b 2 35.00 xxx1
9 c 2 31.00 xxx1
10 c 2 30.50 xxx2
获取每个分组中的第一条记录,当ItemID有多条记录时,选取Price最高的
--sql2000
select *
from tbname k
where not exists(select * from tbname where
name=k.name and ITemID=K.ITemID and k.price<price
)
--sql2005
select ID,Name,ItemID,Price,CreatedOnfrom (select *,rn=ROW_NUMBER()over(PARTITION by name,ITemID order by price desc) from tb ) kwhere k.rn=1
例7:分组后取第一条记录的SQL语句
分享
有如下表结构:
字段 A, B, C
值为 a1、 b1、 c1
a2、 b2、 c2
a2、 b3、 c3
a3、 b4、 c4
a3、 b5、 c5
想要得到的结果集以A字段为分组条件,并取出每一个分组中的第一条记录,如下:
A, B, C
值为 a1、 b1、 c1 --a1分组的第一条记录。
a2、 b2、 c2 --a2分组的第一条记录。
a3、 b4、 c4 --a3分组的第一条记录。
select * from 表 tem where c=(select top 1 c from 表 where a=tem.a)
现有数据表call如下:
zj th bj
------------- -------- -------------
03106666666 00001 03101111111
13711111111 00001 031122222222
03108898888 950000
031177778777 950000
031155955555 00001 031187888876
注:th如为950000,则bj为空,th如为00001、则bj不是空。
1、bj分组
select substr(bj,1,4) as 電話番号,count(*) as 呼びかけ合計量 from call
group by substr(bj,1,4);
実行結果
電話番号 呼びかけ合計量
------------ --------------
0310 1
0311 2
2
2、zjグループ化、条件はthが950000のレコード
select substr(zj,1,4) as 電話番号,count(*) as 呼びかけ合計量 from call
where th=950000
group by substr(zj,1,4);
実行結果:
電話番号 呼びかけ合計量
------------ --------------
0310 1
0311 1
一つのクエリで以下のような結果を実現できるでしょうか:
電話番号 呼びかけ合計量
------------ --------------
0310 2
0311 3
注:以下のような結果を得るために1対応する行に加えます2対応する行
union together and sum up
select
(select substr(bj,1,4) as 電話番号,count(*) as 呼びかけ合計量 from call
group by substr(bj,1,4))
union all
(select substr(zj,1,4) as 電話番号,count(*) as 呼びかけ合計量 from call
where th=950000
group by substr(zj,1,4))
group by 電話番号;
これはOracleで実行されるべきです
select
decode(th,'950000',substr(zj,1,4),substr(bj,1,4)) as 電話番号,
count(*) as 呼びかけ合計量
from
call
group by
decode(th'950000',substr(zj,1,4),substr(bj,1,4))
decode(条件,値1,翻訳値1,値2,翻訳値2,...値n、翻訳値n、デフォルト値)
この関数の意味は以下の通りです:
IF 条件=値1 THEN
RETURN(翻訳値)1)
ELSIF 条件=値2 THEN
RETURN(翻訳値)2)
......
ELSIF 条件=値n THEN
RETURN(翻訳値n)
ELSE
RETURN(デフォルト値)
END IF
例8:SQL Server2005/2008でレコードをグループ化し、各グループの先頭N件のレコードを取得する
仮にテーブルがあると仮定し、以下のSQLクエリが以下の通りです:
CREATE TABLE [dbo].[scan](
[km] [int] NULL,
[kh] [int] NULL,
[cj] [int] NULL
) ON [PRIMARY]
でkm(科目番号)、kh(受験者番号)、cj(成績)をグループ化し、各グループの先頭2レコード(cjの降順でソート)。基本的なアイデアは、各グループにシリアル番号列を追加し、2の。SQLクエリは以下の通りです:
select * from
(
select a.km,a.kh,cj,row_number() over(partition by a.km order by a.km,a.cj desc) n
from
from (select km,kh,SUM(cj) cj from scan group by km,kh) a
) b where n<=2 order by km, cj desc
最終的な結果セットは以下の図のようになります。
例9:グループ化Groupから前N件のレコードを取得するSQL文の実現方法
表Aに根据してフィールドBでグループ化、フィールドCで並び替え、各グループの前の3件のレコードをクエリし、クエリ結果にはすべてのフィールドを含める必要があります。SQL文はどう書けますか?以下のSQL文は実行できますが、データ量が多いので時間がかかります。表の結合を通じて直接グループ化してレコードを取得する方法はありますか?ありがとうございます。
select *
from 表A as t1
where 主键 in(
select top 3 主键
from 表A as t2
where t1.B=t2.B
order by t2.C)
コメント (隠しコメント)
答え1
著者:邹建
select id=identity(int,1,1),b, 主键 into # from 表A order by B,C
select a.*
from 表A a, # b,(select id1=min(id),id2=min(id)+2 from # group by b)c
where a.主键=b.主键
and b.id between c.id1 and c.id2
drop table #
答え2
著者:aierong
各グループの前の2名前、あなたはいくつかの方法がありますか?(MS SQL2000)
create table abc(
i nvarchar(10),
ii int,
iii int,
iiii int,
price money)
Go
insert into abc
select 'b',1,2,1,11
union all
select 'b',211,2,1,211
union all
select 'a',21,2,1,311
union all
select 'd',41,42,1,411
union all
select 'd',41,42,1,511
union all
select 'd',41,42,1,611
union all
select 'e',1,2,1,11
union all
select 'e',71,2,1,31
union all
select 'e',61,2,1,911
union all
select 'e',771,2,1,1
go
要求される結果は以下の通りです:
iでグループ化し、各グループのprice最大の前の2件の記録
i ii iii iiii price
---------- ----------- ----------- ----------- ---------------------
a 21 2 1 311.0000
b 1 2 1 11.0000
b 211 2 1 211.0000
d 41 42 1 511.0000
d 41 42 1 611.0000
e 71 2 1 31.0000
e 61 2 1 911.0000
1.
select *
from abc a
where (
select counthttp://dev1.haocang.com:8080/kb/images/icons/emoticons/star_yellow.gif from abc b
where a.i=b.i and b.price>a.price)<2
order by i,price
接続クエリ、数値を判断
2.
select i,ii,iii,iiii,price
from (
select (select isnull(sum(1),0)+1 from abc b where a.i=b.i and a.price<b.price) ids,*
from abc a) tem
where ids<3
order by i,price
内部テーブルを作成し、内部テーブルtemの各グループにソートを行い、ソート番号を新しい列idsに格納します。
3.
declare @looptime int
declare @count int
declare @i nvarchar(10)
/テーブル変数@abcを定義し、テーブルABCのすべての列のタイプが同じです。/
declare @abc table(
i nvarchar(10),
ii int,
iii int,
iiii int,
price money)
declare @tem table(
ids int identity,
class nvarchar(10))
/テーブルABCのすべてのグループをすべて検索し、一時的なテーブル変数@temに一時的に保存します。/
insert into @tem(class)
select i
from abc
group by i
/テーブル変数@temの行数を求めます。/
select @count=@@rowcount
/ループ変数@looptimeの初期値は=1/
select @looptime=1
while(@looptime<=@count)
begin
/各グループの名前を変数@iに割り当てます。/
select @i=class
from @tem
where ids=@looptime
/各グループの前2名前を挿入する表の変数@abcに/
insert into @abc
select top 2 *
from abc
where i=@i
order by price desc
/ループ変数@looptimeが累積されます。1/
select @looptime=@looptime+1
end
/結果を表示します。/
select *
from @abc
order by i,price
4.
カーソルを使って処理します。
方法は私の3方法を書きましたが、皆さんも自分で試してみてください。
私は以下の4それ以外に良い方法があれば、お話しできますように、ありがとうございます。
今日使用しました。この方法を使うことで、重複の記録を削除する問題を解決できます。
もちろんテーブルにはユニークなインデックスを持っている必要があります。以下のコードを慎重に見てください。
Delete From dbo.TB_WorkflowTask a
WHERE ItemID Not in( select top 1 ItemID from TB_WorkflowTask where TaskName=a.TaskName And EmpID = a.EmpID And BillTypeID =a.BillTypeID And BillID = a.BillID And Status =a.Status AND WFStatus =a.WFStatus )
注意:InまたはNot inのみを使用できます、ExistsまたはNot Existsは使用できません。なぜなら、それは考えてみてください?
例10:グループ分け後の最後のレコードの値をどうやって取得しますか?
まだ混乱しています、再び並べ替えます:
フォーマットを再整理します:
現在のテーブル Log: Day In Out Current
2012.4.5 10 0 10
2012.4.5 0 5 5
2012.4.6 30 20 15
2012.4.6 0 3 12
………………………………………………
表示したい内容
、
2012.4.5 10 5 5
2012.4.6 30 23 12
SQLコード
with tb as(
select [day],sum([in]) as [in],sum(out) as out,sum([in])-sum(out) as [current],rank() over( order by [day]) as row from [log] group by [day]
)
select [day],[in],out,(select sum([current]) from tb b where b.row<=a.row)[current] from tb a
SQLコード
2012.4.5 10 5 5
2012.4.6 30 23 12
SQLコード
--> テストデータ:[Log]
if object_id('[Log]') is not null drop table [Log]
create table [Log]([Day] date,[In] int,[Out] int,[Current] int)
insert [Log]
select '2012.4.5',10,0,10 union all
select '2012.4.5',0,5,5 union all
select '2012.4.6',30,20,15 union all
select '2012.4.6',0,3,12
select
[Day],sum([In]) [In],sum([Out]) [Out],min([Current]) as [Current]
from [Log] group by [Day]
/*
Day In Out Current
2012-04-05 10 5 5
2012-04-06 30 23 12
*/
例11:sqlグループ分け後の二次集計
https://ja.oldtoolbag.com/article/106074.htm
例12:SQLのカテゴリ化とグループ化統計
SQLデータを整理する方法を理解する必要があります。以下の提案は、望む結果を得るために文を構築する方法について説明します。
データを意味のある方法で整理することは、時には挑戦になるかもしれません。時には単純なカテゴリ化のみが必要です。通常は、分析や計算に便利なグループ化を行う必要があります。幸いなことに、SQLはカテゴリ化、グループ化、計算に使用する大量の子句および演算子を提供しています。以下の提案は、どのタイミングでカテゴリ化、グループ化、計算を行うか、どのように行うかを理解するのに役立ちます。各子句および演算子の詳細については、を確認してください。
。
#1:カテゴリ化ソート
通常、すべてのデータをソートする必要があります。SQLのORDER BY子句は、データをアルファベットまたは数字の順序で並べ替えます。したがって、同じデータが各グループに明確にカテゴリ化されます。しかし、これらのグループはカテゴリ化の結果に過ぎず、実際のグループではありません。ORDER BYは各レコードを表示しますが、グループは複数のレコードを代表する可能性があります。
#2:グループ内の似たデータを減少させる
カテゴリ化とグループ化の最大の違いは、カテゴリ化データは(限定標準内のすべてのレコードを)表示するのに対し、グループ化データはこれらのレコードを表示しません。GROUP BY子句は、レコードの似たデータを一つにまとめます。例えば、GROUP BYは、同じ値を持つ複数のレコードを持つ元データからユニークな郵便番号リストを返すことができます:
SELECT ZIP
FROM Customers
GROUP BY ZIP
GROUP BYとSELECT列リストで定義された意味のあるグループの列のみを含めます。言い換えれば、SELECTリストはGROUPリストと一致する必要があります。例外として、SELECTリストは集計関数を含むことができます(GROUP BYは集計関数をサポートしません。)。
覚えておくべきことは、GROUP BYは結果として生成されるグループをカテゴリ化しないことです。グループをアルファベットまたは数字の順序でソートするには、ORDER BY子句を追加します(#)。1)。また、GROUP BY子句では、別名を持つドメインを参照することはできません。グループ列は基本データに存在する必要がありますが、結果に表示される必要はありません。
#3:グループ化前にデータを限定する
WHERE子句を追加して、GROUP BYでグループ化されたデータを限定できます。例えば、以下の文は、ケンタッキー地域の顧客の郵便番号リストのみを返します。
SELECT ZIP
FROM Customers
WHERE State = 'KY'
GROUP BY ZIP
GROUP BY子句でデータの値を求める前に、WHEREはデータをフィルタリングします。これは非常に重要です。
GROUP BYと同様に、WHEREは集計関数をサポートしません。
#4:すべてのグループを返す
WHEREフィルタを使用してデータをフィルタリングする場合、表示されるグループは指定したレコードのみです。グループ定義に一致するが、子句条件を満たさないデータはグループに表示されません。WHERE条件に関係なく、すべてのデータを含めたい場合は、ALL子句を追加します。例えば、前の文にALL子句を追加すると、ケンタッキー地域のグループに限らずすべての郵便番号グループが返されます。
SELECT ZIP
FROM Customers
WHERE State = 'KY'
GROUP BY ALL ZIP
このように、これらの子句は衝突を引き起こし、ALL子句をこのように使用することはありません。列の値を集計する場合、ALL子句を使用すると便利です。例えば、以下のクエリは各ケンタッキー郵便番号の顧客数を計算し、他の郵便番号値も表示します。
SELECT ZIP, Count(ZIP) AS KYCustomersByZIP
FROM Customers
WHERE State = 'KY'
GROUP BY ALL ZIP
得られたグループは元のデータのすべての郵便番号値から構成されていますが、KYCustomerByZIPという集計列は0と表示されます。これは、ケンタッキー郵便番号グループ以外の他のグループが存在しないためです。
リモートクエリはGROUP BY ALLをサポートしていません。
#5:グループ化後のデータの限定
WHERE 子句(#3):GROUP BY子句の前にデータの値を求めます。データをグループ化した後にデータを限定したい場合、HAVINGを使用します。WHEREを使用するか、HAVINGを使用するかは結果が同じになりますが、これらの子句は入れ替えることができません。これは非常に重要です。疑問がある場合は、以下のアプリケーションガイドラインを参照してください:レコードをフィルタリングする場合はWHEREを使用し、グループをフィルタリングする場合はHAVINGを使用します。
一般的に、HAVINGを使用して、グループの値を求めます。例えば、以下のクエリは郵便番号リストを返しますが、このテーブルには元のデータソースに含まれるすべての郵便番号が含まれていない可能性があります:
SELECT ZIP, Count(ZIP) AS CustomersByZIP
FROM Customers
GROUP BY ZIP
HAVING Count(ZIP) = 1
結果には、顧客が一人のグループのみが表示されます。
#6:WHEREとHAVINGの詳細
WHEREとHAVINGの使用にまだ混乱している場合は、以下のガイドラインを適用してください:
WHEREはGROUP BYの前に現れます;SQLはGROUP BYの記録をグループ化する前にWHERE子句の値を求めます。
HAVINGはGROUP BYの後に現れます;SQLはGROUP BYの記録をグループ化した後にHAVING子句の値を求めます。
#7:グループ値の合計
データの分析に役立つようにデータをグループ化しますが、時にはグループ自身以外の情報も必要になることがあります。グループデータを合計するための集計関数を追加できます。例えば、以下のクエリは各グループごとに小計を表示します:
SELECT OrderID, Sum(Cost * Quantity) AS OrderTotal
FROM Orders
GROUP BY OrderID
他のグループと同様に、SELECTとGROUP BYリストは一致する必要があります。SELECT子句に集計関数を含むのはこのルールの唯一の例外です。
#8:集約の合計
各グループの小計を表示することでデータをさらに合計できます。SQLのROLLUP演算子は、各グループに対して追加のレコードと小計を表示します。そのレコードは、各グループ中のすべてのレコードの値を集約関数で求める結果です。以下の文は、各グループのOrderTotal列を合計しています。
SELECT Customer, OrderNumber, Sum(Cost * Quantity) AS OrderTotal
FROM Orders
GROUP BY Customer, OrderNumber
WITH ROLLUP
含む20と25これらのOrderTotal値のグループのROLLUP行は、OrderTotal値を45。ROLLUPの結果の最初の値はユニークです。なぜなら、すべてのグループのレコードの値を求めるからです。その値は、整个のレコードセットの合計です。
ROLLUPは集約関数内のDISTINCTやGROUP BY ALL子句をサポートしません。
#9:各列の合計
CUBE演算子はROLLUPよりもさらに進んでおり、各グループ中の各値の合計を返します。得られる結果はROLLUPに似ていますが、CUBEはグループ中の各列の追加のレコードを含みます。以下の文は、各グループの小計と各顧客の追加の合計を示します。
SELECT Customer, OrderNumber, Sum(Cost * Quantity) AS OrderTotal
FROM Orders
GROUP BY Customer, OrderNumber
WITH CUBE
CUBEで得られる合計は最も複雑です。集約とROLLUPの仕事を完了するだけでなく、定義されたグループの他の列の値も求めます。つまり、CUBE合計はすべての可能な列の組み合わせを示します。
CUBEはGROUP BY ALLをサポートしません。
#10:合計を並べ替えます
CUBEの結果が無秩序である場合(一般的にはこのようにです)、GROUPING関数を追加することができます:
SELECT GROUPING(Customer), OrderNumber, Sum(Cost * Quantity) AS OrderTotal
FROM Orders
GROUP BY Customer, OrderNumber
WITH CUBE
その結果は、各行の2つの追加の値を含みます。
値1左側の値が合計値であることを示します——ROLLUPやCUBE演算子の結果です。
値0は、左側の値が原始のGROUP BY子句で生成された詳細なレコードであることを示します。
グループ化クエリではHAVING子句と組み合わせて使用することもできます。クエリ条件を定義します。
group byを使用してグループ化クエリを実行します。
group byキーワードを使用する際には、selectリストで指定できる項目は制限されています。select文では以下の項目のみが許可されます:
〉グループ化された列
〉各グループに対して値の式を返します。例えば、列名を引数にする集約関数を使用します。
group by に則して、selectの後ろに続くすべての列で、集約関数を使用していない列は、group byの後ろに表示する必要があります(重要)
group by例
例一
データテーブル:
姓名 科目 点数
張三 国語 80
張三 数学 98
張三 英語 65
李四 国語 70
李四 数学 80
李四 英語 90
期待されるクエリ結果:
姓名 国語 数学 英語
張三 80 98 65
李四 70 80 90
コード
create table testScore
(
tid int primary key identity(1,1),
tname varchar(30) null,
ttype varchar(10) null,
tscor int null
)
go
---データをインサートする
insert into testScore values ('張三','国語',80)
insert into testScore values ('張三','数学',98)
insert into testScore values ('張三','英語',65)
insert into testScore values ('李四','国語',70)
insert into testScore values ('李四','数学',80)
insert into testScore values ('李四','英語',90)
select tname as '姓名' ,
max(case ttype when '国語' then tscor else 0 end) '国語',
max(case ttype when '数学' then tscor else 0 end) '数学',
max(case ttype when '英語' then tscor else 0 end) '英語'
from testScore
group by tname
例二
以下のようなデータがあります:(よりわかりやすくするために、国コードを使用せずに、直接国名を使用してプライマリキーとしています)
国(country) | 人口(population) |
中国 | 600 |
アメリカ | 100 |
カナダ | 100 |
イギリス | 200 |
フランス | 300 |
日本 | 250 |
ドイツ | 200 |
メキシコ | 50 |
インド | 250 |
この国の人口データに基づいて、アジアおよび北アメリカの人口数を統計する。以下のような結果が得られるべきです。
大陸 | 人口 |
アジア | 1100 |
北アメリカ | 250 |
その他 | 700 |
コード
SELECT SUM(population), CASE country WHEN '中国' THEN 'アジア' WHEN 'インド' THEN 'アジア' WHEN '日本' THEN 'アジア' WHEN 'アメリカ' THEN '北アメリカ' WHEN 'カナダ' THEN '北アメリカ' WHEN 'メキシコ' THEN '北アメリカ' ELSE 'その他' END FROM Table_A GROUP BY CASE country WHEN '中国' THEN 'アジア' WHEN 'インド' THEN 'アジア' WHEN '日本' THEN 'アジア' WHEN 'アメリカ' THEN '北アメリカ' WHEN 'カナダ' THEN '北アメリカ' WHEN 'メキシコ' THEN '北アメリカ' ELSE 'その他' END;
同様に、この方法を使って給料のランクを判断し、各ランクの人数を統計できます。以下はSQLコードです;
SELECT CASE WHEN salary <= 500 THEN '1' WHEN salary > 500 AND salary <= 600 THEN '2' WHEN salary > 600 AND salary <= 800 THEN '3' WHEN salary > 800 AND salary <= 1000 THEN '4' ELSE NULL END salary_class, COUNT(*) FROM Table_A GROUP BY CASE WHEN salary <= 500 THEN '1' WHEN salary > 500 AND salary <= 600 THEN '2' WHEN salary > 600 AND salary <= 800 THEN '3' WHEN salary > 800 AND salary <= 1000 THEN '4' ELSE NULL END;
GROUP BYの後には通常列名が続きますが、この例ではCASE文を使ってグループ化をさらに強化しています。
例3
以下のデータがあります。
国(country) | 性別(sex) | 人口(population) |
中国 | 1 | 340 |
中国 | 2 | 260 |
アメリカ | 1 | 45 |
アメリカ | 2 | 55 |
カナダ | 1 | 51 |
カナダ | 2 | 49 |
イギリス | 1 | 40 |
イギリス | 2 | 60 |
国と性別にグループ化して、以下の結果が得られます。
国 | 男性 | 女性 |
中国 | 340 | 260 |
アメリカ | 45 | 55 |
カナダ | 51 | 49 |
イギリス | 40 | 60 |
コード
SELECT country, SUM( CASE WHEN sex = '1' THEN population ELSE 0 END), --男性人口 SUM( CASE WHEN sex = '2' THEN population ELSE 0 END) --女性人口 FROM Table_A GROUP BY country;
GROUP BY子句のNULL値の処理
GROUP BY子句でグループ化を行う列にNULL値がある場合、どのようにグループ化を行いますか?SQLでは、NULLはNULLではありません(WHERE子句で紹介されています)。しかし、GROUP BY子句では、すべてのNULL値が同じグループに分類され、それらが「等しい」とみなされます。
HAVING子句
GROUP BY子句でグループ化を行うのは、単に選択した列のデータに基づいてグループ化を行うだけでなく、条件を満たさない行グループを削除する必要がある場合があります。この機能を実現するために、SQLではHAVING子句を提供しています。以下はその文法です。
SELECT column, SUM(column) FROM table GROUP BY column HAVING SUM(column) condition value
説明:HAVINGは通常GROUP BY節と同時に使用されます。もちろん、SUM()関数以外の集計関数も可能です。DBMSはHAVING節の検索条件をGROUP BY節が生成する行グループに適用し、検索条件を満たさない行グループは結果テーブルから削除されます。
HAVING節の適用
TEACHERテーブルから少なくとも2人の教師がいる系および教師人数をクエリする。
実現コード:
SELECT DNAME, COUNT(*) AS num_teacher FROM TEACHER GROUP BY DNAME HAVING COUNT(*)>=2
HAVING節とWHERE節の違い
HAVING節とWHERE節の類似点は、それも検索条件を定義することですが、WHERE節とは異なり、HAVING節はグループに関連しており、単一の行に関連していません。
1、GROUP BY節が指定されている場合、HAVING節で定義される検索条件はそのGROUP BY節が作成するグループに適用されます。
2、WHERE節が指定されており、GROUP BY節が指定されていない場合、HAVING節で定義される検索条件はWHERE節の出力に適用され、その出力をグループとして見なします。
3、GROUP BY節が指定されていない場合、WHERE節が指定されていない場合、HAVING節で定義される検索条件はFROM節の出力に適用され、その出力をグループとして見なします。
4、SELECT文でWHERE節とHAVING節の実行順序は異なります。この本では、5.1.2セクションで紹介するSELECT文の実行手順から、WHERE節はFROM節からの入力を受け取ることができますが、HAVING節はGROUP BY節、WHERE節、FROM節からの入力を受け取ることができます。