2015年9月5日土曜日

PostgreSQL 無かったらINSERT文について

SQLはSELECT * FROM xxxくらいしか叩けない自分ですが、
DBを構築する必要が出てきたので色々と勉強中です。

早速ですが、DBにINSERTしたいレコードと同じものが無い場合のみINSERTしたい場合どうするか悩みました。

一度レコードの存在をSELECTで調べてその結果を一時的に保持して、
無ければ次にINSERTをすることも考えましたが、一度にそれをしたい!

早速ネットを調べてみると同じような質問が当然のごとくありました。
Postgres: INSERT if does not exist already

そして、この質問に対して次の様な回答がありました。
INSERT INTO example_table
    (id, name)
SELECT 1, 'John'
WHERE
    NOT EXISTS (
        SELECT id FROM example_table WHERE id = 1
    );

ほんのわずかなレースコンディションがあるようですが、これでやりたいことはできるようです。
しかし、なぜこれがうまく動くのかが理解できない!

で、INSERT、SELECT、NOT EXISTSをそれぞれ調べて次のことが分かり無事に理解できました。

  • NOT EXISTは続くSELECTの結果が無い場合trueを返す
  • SELECT 1, 'John'は1, 'John'を表示する
  • INSERT は()の後にSELECT文を書いてその結果を代入することができる
つまり、
  1. SELECT id FROM example_table WHERE id = 1で入れたいレコードがあるかを調べる
  2. WHERE NOT EXISTSで無かった場合実行するという条件を付ける
  3. 条件がtrueであった場合、SELECT 1, 'John'で代入したい値を指定する
  4. その値をINSERTする
ということだと理解しました。



2015年8月19日水曜日

Pythonの変数スコープ

Pythonのサンプルプログラムを見ていて気になることがあった。
例外処理でtry-catch-finallyの外側で変数宣言をしていないのに、tryとfinallyそれぞれで同じ変数を参照していた。 
try:
    instance = SomeClass()
    instance.getSomething()

except Exception, e:
    print 'Error %s' % e

finally:
    if instance is not None:
        instance.doSomething()

JavaやC++ではこのような書き方はエラーになるので非常に違和感があった。
そこで調べてみたところ、 Pythonでは変数のスコープは基本的に

  • クラス
  • 関数

この二つしかなくif分や例外等の制御構文ではスコープは存在しないということだった。
参考:Python の名前空間とスコープ

2015年8月18日火曜日

PythonとMacPorts

Pythonを勉強中で環境を構築中。

基本的に必要なモジュールはMacPortsを使ってインストールをしているが、MacPortsでPythonをインストールするとデフォルトでMacに存在するPythonとバッティングする。

virtualenvとかを使えばうまく切り分けられるのだろうが、まだあまり理解できていない。

ひとまず、MacPorts側でどのPythonを使うのかは次のコマンドで設定ができる。
 $ sudo port select python

すると次のように選択肢を表示してくれるので使いたいものを選ぶ
 Available versions for python:
 none
 python25-apple
 python26-apple
 python27 (active)
 python27-apple

 $ sudo port select python

2015年6月21日日曜日

Fragmentでバックキーイベントを拾う際の注意点


Fragmentでバックキーが押されたことを検知したくてこちらのサイトに紹介してある方法と同じように実装をしてみた。
しかし、バックキーが押されたイベントを拾うことができなかった。

 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.myfragment, container, false);

    view.setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN)
                Log.w(TAG, “on pressed back key”);
            return false;
        }

    });

    view.setFocusableInTouchMode(true);

    return view;
}

もっとよく調べてみると、バックキー等のハードウェアキーのイベントを拾うためにはそのViewにフォーカスが当たっている必要があることがわかった。
テキストエディット等はタッチすればフォーカスが当たるがFragmentは別の方法でフォーカスを当てる必要がある。

  • 方法1:レイアウトファイルに書いたFragmentの属性にandroid:focusable = "true"を入れる
  • 方法2:javaのコード上でrequestForcus()を呼ぶ

したがって、先ほどのコードは下記のように書く必要がある。

 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.myfragment, container, false);

    view.setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN)
                Log.w(TAG, “on pressed back key”);
            return false;
        }

    });

    view.setFocusableInTouchMode(true);
    view.requestFocus();

    return view;
}

2015年6月14日日曜日

Copy as cURL に感動

ウェブページの内容をスクリプトで解析したいということがよくある。
当然結果はcurl等のコマンドラインツールで実行したテキストの形式で受け取りたい。
なので、ブラウザで送るリクエストと同等のものをcurlのオプションや引数の設定をして作らなければならない。

いままではchromeの開発ツールにあるNetworkタグのリクエスト内容を見て位置からコマンドを作っていた。

ふと、リクエストを右クリックしてみると"Copy as cURL"なるものがあった。


まさかと思い試してみると、期待通りcurlのコマンドが!
curl 'http://seica.info/search/hinmoku.aspx' -H 'Cookie: ASP.NET_SessionId=hu2sjzkjdvf2ll3emwmw4xyv; __utmt=1; __utma=19271098.1453152246.1434261901.1434261901.1434261901.1; __utmb=19271098.16.10.1434261901; __utmc=19271098; __utmz=19271098.1434261901.1.1.utmcsr=naro.affrc.go.jp|utmccn=(referral)|utmcmd=referral|utmcct=/nfri/contens/open-db/' -H 'Origin: http://seica.info' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: ja,en-US;q=0.8,en;q=0.6' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Cache-Control: max-age=0' -H 'Referer: http://seica.info/search/hinmoku.aspx' -H 'Connection: keep-alive' --data '__EVENTTARGET=&__EVENTARGUMENT=&__LASTFOCUS=&__VIEWSTATE=%2FwEPDwUKLTE2NzE0NTU5O...(略)

おそらくweb開発をやっている方からすると当たり前の機能なのでしょうか、
私は・・・感動しました!

2015年6月13日土曜日

AndroidアプリWhat's This公開

以前に作ったアプリの知見を生かしつつ、新しい技術を取り入れることを目標としてWhat's Thisというアプリを作りました。

【ざっくりとした使い方と機能】
・ユーザが事前に任意の画像に対してアプリより対象物の指定と名前、よみがなの設定を行う
・設定後の画像の対象物をユーザがタッチすると、名前が表示され、よみがなが音声として流れる


子供がものの名前を覚えるときに使ったり、人の名前を覚えるときに使って貰えればと思っています。
ご興味がありましたら是非使ってみてください。

https://play.google.com/store/apps/details?id=com.nsunrize.whatsthis&hl=ja






2015年5月9日土曜日

メモリを節約しながら画面サイズに合わせたBitmapの表示方法



CanvasにBitmap(画像ファイル)を表示させるときに、縮小もしくは拡大して表示したいということがある。 このときよく使われる方法はBitmap.createBitmapを呼び出してサイズを変更したBitmapを新しく作る方法であるが、 createという言葉の通り新しくBitmapオブジェクトが生成されることになるためメモリを食ってしまう。

 もっと良い方法が無いか試してみたところ、drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)を 使えばメモリを消費せずに描画できることがわかった。 
第二引数のRectはnullで良いらしいので、第三引数のRectに表示したい画像の座標を入れてやればOKで無事に メモリを節約した状態で拡大縮小表示ができた。