SQLServerでランキングを求めるとき -- OVERの使い方(OLAP関数)
「最後に買ったもの」を調べる
SQLで「誰が・何を・いつ買った」という買い物データから「その人が最後に買ったもの」を調べようとすると案外難しい。
データイメージ
PERSON GOODS PURCHASE_DATE +-------+-------+-------------- Tom Orange 2015-2-19 Tom Apple 2015-2-17 Nancy Apple 2015-2-19 Nancy Potato 2015-2-17
期待する結果
PERSON GOODS PURCHASE_DATE +-------+-------+-------------- Tom Orange 2015-2-19 Nancy Apple 2015-2-19
MAXのA列に該当するレコードのB列といったデータを取り出してくださいと言われて少々答えに窮したのでここにメモしておく。
こういうデータを取り出すときは相関サブクエリかOLAP関数を使うとできる。
おすすめはOLAP関数を使うやり方で、相関サブクエリを使うとどうしてもSQL文が読みにくくなる。
JSHintの設定ファイル
JSHintはデフォルトだと全然チェックしない
JSLintが鬱陶しいからJSHintを使っている人は多いと思う。
ところが、JSHintはデフォルトだとチェック基準がすごく甘くてチェックとして機能しない。
AnsibleのHost Variablesの使いどころ
Host Variables とは?
Inventory — Ansible Documentation
[atlanta] host1 http_port=80 maxRequestsPerChild=808 host2 http_port=303 maxRequestsPerChild=909
Host Variablesは上記引用の通り、インベントリのホストのセクションに併記する値なのだが、これの使いどころって何なんだろうと最初のころ疑問に思っていた。
なぜならAnsibleはインベントリ以外にも変数に値を渡せる箇所がたくさんあるからだ。
ところがAnsibleを使い込んでいくうちにHost Variablesを使った方がうまくいくケースが存在することが次第にわかってきた(以下)。
特定の環境だけSSHの接続情報が違うとき
例えば
- development.ini 開発環境のDB/サーバーの設定値
- production.ini 本番環境の設定値
このように環境別にインベントリを分けて管理する場合に、特定のサーバーだけSSHに2022番ポートで接続しなければならないときにHost Variablesは役立つ。
[development.ini]
[webservers] 192.108.22.3 ansible_ssh_port=2022 192.108.22.6
[production.ini]
[webservers] 192.108.25.35 192.108.25.36
こんな風に。
複数のサーバーで冗長化しつつも、master/slaveの役割分担しているとき
本番環境に1号機と2号機の2台サーバーを用意してそれぞれwebアプリを稼働させるけれども、1号機にはcrontabを設定しバッチサーバーとしても稼働させる場合を想定する。
そして、もし1号機が故障したら2号機をバッチサーバーとして動かす運用とする。
つまり
[通常時]
サーバー | web | バッチ |
---|---|---|
1号機 | ○ | ○ |
2号機 | ○ | × |
[1号機 障害時]
サーバー | web | バッチ |
---|---|---|
1号機 | - | - |
2号機 | ○ | ○ |
このように構成を変える運用を想定する。
こういうときもHost Variablesが役立つ。
[roles/batch-server/tasks/main.yml]
- name: とあるジョブ {{ switching }} cron: name='some job' job='cd /var/www/some/src; /var/www/some/bin/python manage.py somejob' user=www hour='*/1' minute=5 state={{ 'present' if switching == 'on' else 'absent' }} sudo: yes
[build.yml]
- hosts: servers roles: - { role: batch-server, switching: 'on', when: master == 'yes' } - { role: batch-server, switching: 'off', when: master != 'yes' }
[production.ini]
[servers] 192.168.22.3 master=yes 192.168.22.7 master=no
実行コマンド
$ ansible-playbook -i production.ini build.yml
上記コマンドでデプロイする。
もし障害が起きて1号機が使えなくなったらproduction.iniを
[servers] # 192.168.22.3 master=no 192.168.22.7 master=yes
このように2号機をmaster=yesと書き換えて同じコマンドでデプロイすれば簡単にcrontabを仕掛けたり外したりできる。
Ansibleのハンドラが起動するのはタスクがchangedを返したときだけ
Ansibleのハンドラとは
Ansibleのタスクには `notify` という属性を追加してコールバック処理を呼ぶよう設定できる。
[roles/nginx/tasks/main.yml]
- name: nginx config ensure template: src=my.nginx.conf.j2 dest=/etc/nginx/conf.d/your.conf sudo: yes notify: restart nginx
[roles/nginx/handlers/main.yml]
- name: restart nginx service: name=nginx state=restarted sudo: yes
こう書いておくと roles/nginx/templates/my.nginx.conf.j2 から生成した内容が /etc/nginx/conf.d/your.conf の内容を変更したときに、自律的にnginxを再起動してくれる。
この挙動を一般に「nginxの設定を変えたら自動的に再起動される」などと呼ぶ。
ところがわざわざ下線を引いたけれども、Ansibleのプレイブックを実行したタイミングで `nginx config ensure` のタスクが `CHANGED` を返さないとハンドラは起動しない。
だから
- プレイブックを起動。(A -> B -> C) の順にタスクを実行。
- nginxの設定ファイル配置をBのタイミングで行ったが、Cに指定した別のタスクが失敗した。
- ハンドラはすべてのタスクが終わった後に動くのでCが失敗した時点で処理が終わってしまう。
- もう一度プレイブックを動かすとBのタスクではもはやCHANGEDとは評価されないのでnginxが再起動されないまま放置される。
このような事態が起きうる。
役に立つのかわからない --force-handlers オプション
そういう事態を想定して、 `ansible-playbook` コマンドには `--force-handlers` というオプションが用意されている。
これを指定してプレイブックを動かすと、たとえタスクが失敗してもハンドラの起動まで進めてくれる。
とはいえ、指定し忘れると結局アウトなのだ。
よくわからないのだが、Ansibleには「ハンドラのタスクを指定して動かす」仕組みが無いので、nginxの設定ファイル配置以降のタスクが予期せず失敗した場合にやり直す方法が無い。
どうしたらいいのか?
仕方が無いのでこんな方法で対処してみた。
Role -- register/changed を利用
[roles/nginx/tasks/main.yml]
- name: 1. nginxの設定ファイルを配置 template: src=my.nginx.conf.j2 dest=/etc/nginx/conf.d/your.conf sudo: yes register: nginx_conf notify: restart nginx ... (他の雑多なタスク) ... - name: 2. nginxが起動していること service: name=nginx state=started sudo: yes - name: 3. nginxを強制的に再起動 service: name=nginx state=restarted sudo: yes when: nginx_restart is defined and not nginx_conf.changed tags: - deploy
実行コマンド
[通常時]
$ ansible-playbook -i foo.ini some.yml
[やり直しするとき]
$ ansible-playbook -i foo.ini some.yml -t deploy -e 'nginx_restart=yes'
こうしておけば
- 1のタスクでnginxの設定が変わったらハンドラから再起動される
- 3のタスクはコマンドラインからnginx_restartを指定したときだけ動く
- 1から動くハンドラと3のタスクによってnginx再起動が2度実行されることもない
ひとり言
なんかややこしいことをしている気がするのだが・・・
もっと簡潔な方法は無いのか。