general notes

いろいろなまとめ

達人に学ぶSQL徹底指南書 1-4 HAVING句の力

データの歯抜けを探す

テーブル定義

create table tbl1_4_1_SeqTbl(
    seq int,
    name varchar(10)
)

insert into dbo.tbl1_4_1_SeqTbl values
    (1, 'ディック'),
    (2, 'アン'),
    (3, 'ライル'),
    (5, 'カー'),
    (6, 'マリー'),
    (8, 'ベン')

-- seqの歯抜けチェック
select '歯抜けあり' as gap from dbo.tbl1_4_1_SeqTbl
having count(*) <> max(seq);
--歯抜けの最小値を探す
select min(seq + 1) as gap from dbo.tbl1_4_1_SeqTbl
where (seq+1) not in (select seq from dbo.tbl1_4_1_SeqTbl)
--gap
--4

--not exists版
select min(seq + 1) as gap from dbo.tbl1_4_1_SeqTbl a
where not exists (select * from dbo.tbl1_4_1_SeqTbl b where a.seq + 1 = b.seq)
--gap
--4

最頻値を求める

テーブル定義

create table tbl1_4_3_Graduates(
    name nvarchar(10),
    income int
)

insert into dbo.tbl1_4_3_Graduates values
    ('a', 400000),
    ('b', 30000),
    ('c', 20000),
    ('d', 20000),
    ('e', 20000),
    ('f', 15000),
    ('g', 15000),
    ('h', 10000),
    ('i', 10000),
    ('j', 10000)

--最頻値を求める(allの利用)
select income, count(*) as cnt from dbo.tbl1_4_3_Graduates
group by income
having count(*) >= all(
    select count(*) from dbo.tbl1_4_3_Graduates
    group by income
)

--income   cnt
--10000    3
--20000    3
--最頻値を求める(maxの利用)
select income, count(*) as cnt from dbo.tbl1_4_3_Graduates
group by income
having count(*) >= (
    select max(cnt) from(
        select count(*) as cnt from dbo.tbl1_4_3_Graduates
        group by income
    ) tmp
)
--income   cnt
--10000    3
--20000    3

中央値(メジアン)を求める

--メジアンを求める
select avg(distinct income) as median from(
    select t1.income from dbo.tbl1_4_3_Graduates t1, dbo.tbl1_4_3_Graduates t2
    group by t1.income
    having sum(case when t2.income >= t1.income then 1 else 0 end) >= count(*) / 2
        and sum(case when t2.income <= t1.income then 1 else 0 end) >= count(*) / 2
) tmp

--median
--17500

NULLを含まない集合を探す

テーブル定義

create table tbl1_4_5_Students(
    id int,
    dpt nvarchar(10),
    submit_date date
)

insert into dbo.tbl1_4_5_Students values
    (100, '理学部', '2005-10-10'),
    (101, '理学部', '2005-09-22'),
    (102, '文学部', null),
    (103, '文学部', '2005-09-10'),
    (200, '文学部', '2005-09-22'),
    (201, '工学部', null),
    (202, '経済学部', '2005-09-25')

--提出日にnullを含まない(=全員提出)学部を選択する
select dpt from dbo.tbl1_4_5_Students
group by dpt
having count(*) = sum(
    case when submit_date is not null then 1 else 0 end
)

関係除算でバスケット解析

テーブル定義

create table tbl1_4_6_Items(
    item nvarchar(10)
)

insert into dbo.tbl1_4_6_Items values
    ('ビール'),
    ('紙オムツ'),
    ('自転車')

create table tbl1_4_6_ShopItems(
    shopname nvarchar(10),
    item nvarchar(10)
)

insert into dbo.tbl1_4_6_ShopItems values
    ('仙台', 'ビール'),
    ('仙台', '紙オムツ'),
    ('仙台', '自転車'),
    ('仙台', 'カーテン'),
    ('東京', 'ビール'),
    ('東京', '紙オムツ'),
    ('東京', '自転車'),
    ('大阪', 'テレビ'),
    ('大阪', '紙オムツ'),
    ('大阪', '自転車')

--Itemsテーブルの商品を全て備えた店を探すSQL(他の物があってもよい)
select si.shopname from dbo.tbl1_4_6_ShopItems si, dbo.tbl1_4_6_Items i
where si.item = i.item
group by si.shopname
having count(si.item) = (select count(item) from dbo.tbl1_4_6_Items)
--shopname
--仙台
--東京
--Itemsテーブルの商品を全て備えた店を探すSQL(他の物があるとダメ)
select si.shopname 
from dbo.tbl1_4_6_ShopItems si
left outer join dbo.tbl1_4_6_Items i
on si.item = i.item
group by si.shopname
having count(si.item) = (select count(item) from dbo.tbl1_4_6_Items)
    and count(i.item) = (select count(item) from dbo.tbl1_4_6_Items)
--shopname
--東京