Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PostgreSQLの範囲型と排他制約

 PostgreSQLの範囲型と排他制約

Avatar for ISHIDA Akio

ISHIDA Akio

December 17, 2013
Tweet

More Decks by ISHIDA Akio

Other Decks in Programming

Transcript

  1. 組み込みの範囲型 範囲型 元の型 離散的か int4range integer ◦ int8range bigint ◦

    numrange numeric × tsrange timestamp × tstzrange timestamp with timezone × daterange date ◦
  2. こうなります create table members ( birthday date, period daterange, name_en

    text ); insert into members(birthday, period, name_en) values ('1988-10-20', '[2001-08-26, 2012-05-18]', 'Risa Niigaki'), ('1988-12-23', '[2003-01-19, 2010-12-15]', 'Eri Kamei'), ('1989-11-11', '[2003-01-19, 2013-05-21]', 'Reina Tanaka'), ('1989-07-13', '[2003-01-19,]', 'Sayumi Michishige'), ('1985-02-26', '[2003-01-19, 2007-06-01]', 'Miki Fujimoto'), ...
  3. こうなります create table level1 ( level int, exp_range int4range, primary

    key(level), exclude using gist (exp_range with &&) ); insert into level1 values (1, '[0,11)'), (2, '[11,59)'), (3, '[59,164)');
  4. 範囲型の作り方色々 '[0,10)' 0以上10未満 '[0,10]' 0以上10以下 '[0,)' 0以上(上限値なし) '[,)' 上限も下限もなし 'empty'

    空の範囲 int4range(0, 10) コンストラクタ関数 [0,10)と同じ int4range(0, 10, '[]') [0,10]と同じ
  5. 離散的、正規化 -- 0以上11未満(11は含まない) -- 離散的な範囲型では正規化される =# select int4range '[0,10]'; int4range

    ----------- [0,11) (1 行) =# select v, int4range '[,11)' @> v from generate_series(10, 12) as s(v); v | ?column? ----+---------- 10 | t 11 | f 12 | f (3 行)
  6. 使用例 -- 二人の在籍期間の重複日数 =# with q(n1, n2, p) as (

    select m1.name_en, m2.name_en, m1.period * m2.period from members m1 join members m2 on(m1.name_en < m2.name_en) ) select n1, n2, upper(p) - lower(p) from q where not isempty(p) order by 3; n1 | n2 | ?column? ------------------+-------------------+---------- ... Reina Tanaka | Sayumi Michishige | 3776 Ai Takahashi | Risa Niigaki | 3688 Reina Tanaka | Risa Niigaki | 3408 Risa Niigaki | Sayumi Michishige | 3408
  7. 範囲型のEXCLUDE制約 =# select * from level1; level | exp_range -------+-------------

    1 | [0,11) 2 | [11,59) 3 | [59,164) ... =# insert into level1 values(100, '[11,12)'); ERROR: 重複キーの値が排除制約 "level1_exp_range_excl" に 違反しています DETAIL: キー (exp_range)=([11,12)) が既存のキー (exp_range) =([11,59)) と競合しています
  8. タイプ レベル 開始 終了 100万 1 0 11 100万 2

    11 59 100万 3 59 164 150万 1 0 16 150万 2 16 99 150万 3 89 246
  9. スカラ型と範囲型の組み合わせ -- gistは標準では = を使えない create extension btree_gist; create table

    level2 ( exp_type int, level int, exp_range int4range, primary key(exp_type, level), exclude using gist (exp_type with =, exp_range with &&) ); insert into level2 values (100, 1, '[0,11)'), (100, 2, '[11,59)'), ... (150, 1, '[0,16)'), (150, 2, '[16,89)'),