SHOYAN BLOG

相関サブクエリを使って次回契約を取得する

相関サブクエリを使って次回契約を取得します。

Contract table

| id | account_id | start_date | end_date |
| — | — | — | — |
| 1 | 1 | 20140101 | 20141231 |
| 2 | 1 | 20150101 | 20151231 |
| 3 | 1 | 20160101 | 20161231 |
| 4 | 1 | 20170101 | 20171231 |
| 5 | 2 | 20150101 | 20151231 |
| 6 | 2 | 20160101 | 20161231 |

上記のようなaccount_idと開始日、終了日の登録してあるテーブルがあるとします。
現在の契約を取得するのは簡単ですね。

1
2
# 現在契約を取得する
SELECT * FROM contracts WHERE start_date >= 現在日付 AND end_date <= 現在日付

現在契約を取得するのは簡単ですが、その次の契約を取得するとなるとそう単純にはいきません。

そこで、相関サブクエリを使います。
相関サブクエリを使うことで次回契約を取得できます。

1
2
3
4
5
6
7
8
9
10
11
12
# 次回契約を取得する
SELECT *
  FROM contracts As cont
 WHERE start_date = (SELECT MIN(start_date)
                       FROM contracts as c1
                     WHERE c1.start_date > ( SELECT end_date
                                               FROM contracts as c2
                                             WHERE c2.start_date <= '20150528'
                                               AND c2.end_date >= '20150528'
                                               AND c1.account_id = c2.account_id)
                       AND cont.account_id = c1.account_id
                     GROUP BY c1.account_id);

結果

| id | account_id | start_date | end_date |
| — | — | — | — |
| 3 | 1 | 20160101 | 20161231 |
| 6 | 2 | 20160101 | 20161231 |

クエリの説明

クエリの説明をします。

クエリは内側からみていきます。
まずは、一番内側にある、 SELECT end_date ... AND c1.account_id = c2.account_idのクエリです。
このクエリでは現在の契約(ここでは2015/5/28とします)を取得します。

2つめのクエリで、次回以降の契約を取得します。
SELECT MIN(start_date) を使うことで、次回契約のなかで直近の契約を取得できます。
アカウントごとに直近の次回契約を取得したいので、GROUP BY account_id をしています。

c1.account_id = c2.account_id と cont.account_id = c1.account_id は行と行を比較するために必要です。

3つめのクエリ(SELECT * ... WHERE start_date =)で直近の次回契約を条件として、データを取得します。

手元で試したい方は以下のクエリでデータをつくれます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CREATE TABLE `contracts` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `account_id` int(11) DEFAULT NULL,
  `start_date` int(11) DEFAULT NULL,
  `end_date` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `contracts` (`id`, `account_id`, `start_date`, `end_date`)
VALUES
    (1, 1, 20140101, 20141231),
    (2, 1, 20150101, 20151231),
    (3, 1, 20160101, 20161231),
    (4, 1, 20170101, 20171231),
    (5, 2, 20150101, 20151231),
    (6, 2, 20160101, 20161231);

プログラマのための数学勉強会@福岡に登壇してきました

プログラマのための数学勉強会@福岡が2015/9/4にLINE Fukuokaで開催されました。
今回はスピーカーとして参加させていただきました。

「暗号技術を支える素数」というタイトルで、暗号で使われている数式とその仕組みを説明しつつ、素因数分解の困難性が暗号の要だということを説明しました。

他の登壇者のかたのスライド

他の登壇者のかたのスライドを紹介します。

主催者の@tkengo氏のスライドです。
プロジェクトオイラーの問題の紹介と効率的な解き方の解説をされています。

きしださん のスライドです。
画像の機械学習の話しです。
最弱といいながら高度なことをやっているというギャップがおもしろいです。

圏論超絶基礎の基礎の基礎入門

資料はあがっていないようですが、@nobkz先生の独特なプレゼンテーションは圧倒的でした。

会場の様子

暗号技術を支える素数についての発表

Balloonbrosさん(@balloonbros)が投稿した写真 -

当日は多くのかたに参加いただきました。

LINEで勉強会でした

Balloonbrosさん(@balloonbros)が投稿した写真 -

今回、カメラマンとして参加してくれた@keita_kawamoto

主催者tkengo。楽しかった!ありがとう!

Balloonbrosさん(@balloonbros)が投稿した写真 -

主催者の@tkengo氏。
最近、ブログをリニューアルしたとのことです。

Twiterまとめ

プログラマのための数学勉強会@福岡まとめ

会場を提供してくださったLINE Fukuokaのみなさん、忙しい中足を運んでくださった参加者、登壇者のみなさん、主催の@tkengo氏、ありがとうございました!

Rspecのコードリーディング

bundle exec rspecを実行したときの処理を追ってみた。
まずは、binをみてみる。

vendor/bundle/ruby/2.1.0/bin/rspec

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env ruby
#
# This file was generated by RubyGems.
#
# The application 'rspec-core' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require 'rubygems'

version = ">= 0"

if ARGV.first
  str = ARGV.first
  str = str.dup.force_encoding("BINARY") if str.respond_to? :force_encoding
  if str =~ /\A_(.*)_\z/ and Gem::Version.correct?($1) then
    version = $1
    ARGV.shift
  end
end

gem 'rspec-core', version
load Gem.bin_path('rspec-core', 'rspec', version)

loadメソッドにGem.bin_pathで生成されるものを渡している。

Gem.bin_path(‘rspec-core’, ‘rspec’, “>=0”)をpryで実行すると以下の文字列が取得できた。

1
=> "/Users/shoyan/Development/rails-sample/vendor/bundle/ruby/2.1.0/gems/rspec-core-3.3.1/exe/rspec"

rspec-core-3.3.1/exe/rspecをみてみると、たった3行のコードがあるだけだった。

1
2
3
4
#!/usr/bin/env ruby

require 'rspec/core'
RSpec::Core::Runner.invoke

RSpec::Core::Runner.invokeはrspecを実行するトリガーのようだ。

rspec-core-3.3.1/lib/rspec/core/runner.rbをみてみる。

# Provides the main entry point to run a suite of RSpec examples.
というコメントがあった。
Rspec examplesのスイートを実行する主要なエントリポイントを提供する と書いてある。

self.invokeをみると、disable_autorunとrunを実行して、runの戻り値が0でない場合はexitをrunの戻り値で実行している。

1
2
3
4
5
6
#Runs the suite of specs and exits the process with an appropriate exit
def self.invoke
  disable_autorun!
  status = run(ARGV, $stderr, $stdout).to_i
  exit(status) if status != 0
end

ここで重要なのがrunなので、runの処理をおっていく。
runはself.runとrunがあるが、ここで実行されているのは、self.runのほう。

self.runはoptionsを取得して、それをnewして戻り値のインスタンスのrunメソッドを実行している。
ここでrunが実行される。

1
2
3
4
5
6
7
8
9
10
# Configures and runs a spec suite.
#
# @param err [IO] error stream
# @param out [IO] output stream
def run(err, out)
   setup(err, out)
   run_specs(@world.ordered_example_groups).tap do
     persist_example_statuses
   end
end

runメソッドはsetupとrun_specsを実行している。

setupはerror streamとoutput streamをセットしたり、オプションの設定をしたり、rspec関連のファイルを読み込んでいる。

run_specでテストを実行している。
run_specは全てのテストが成功したら0を返す。
テストに失敗したり何かしらの設定に失敗したら1を返す。

RailsをDBなしで使う

RailsはデフォルトではDBを利用する設定になっているので、普通にrails newすると、Gemfileにsqlite3が定義されたりdatabase.ymlが作成されてしまいます。

DBなしでRailsを使いたい場合は、以下のコマンドを実行します。

1
$ rails new application_name -O