• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Lisp Tutorial for Pythonista : Day 4
 

Lisp Tutorial for Pythonista : Day 4

on

  • 3,733 views

Common Lispのライブラリである ...

Common Lispのライブラリである clsqlを使ってRDBMSにアクセスする方法の基本部分をお勉強します。意外と簡単にアクセスできちゃうし、clsqlはよく出来てるのでデータのハンドリングとかでも楽できちゃいますよ。あとはプログラマの工夫次第でいくらでも。

Statistics

Views

Total Views
3,733
Views on SlideShare
3,724
Embed Views
9

Actions

Likes
0
Downloads
0
Comments
1

3 Embeds 9

http://paper.li 7
http://s.deeeki.com 1
http://www.linkedin.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel

11 of 1 previous next

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • なんか、どんどん for Pythonistaじゃなくなってきてるけど、細かいことは気にしない!
    お仕事で使う言語としては RDBMS をハンドリングできないと意味ないので、今回は CLSQL つかってデータベースとお話というお話。
    例によって実用というか、とにかくサクサク書いてサクサク使うをモットーにしてるので、ダサいコーディングとか伝統的なイディオムの無視とかやりまくってます。上級Lisper諸氏においては、生暖かく見守ってください。
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Lisp Tutorial for Pythonista : Day 4 Lisp Tutorial for Pythonista : Day 4 Presentation Transcript

    • Lisp tutorial for Pythonista.Day #4 : Work with RDBMS Ransui Iso Strategic Technology Group, X-Listing Co, Ltd.
    • 宿題できましたか?
    • 今日は予告通り SQL !なんだかんだで RDBMS 使えないと 仕事では困っちゃう
    • CLSQL を使います
    • QuickLisp でインストールclsql と clsql­mysql と clsql­postgresql をインストールしてくださいませ
    • REPL 環境下でテストしてみる ● とりあえず selectCL­USER> (use­package :clsql)CL­USER> (connect ("achernar" "stats_master" "<user­name>" "<password>")             :database­type :mysql)#<CLSQL­MYSQL:MYSQL­DATABASE achernar/stats_master/<user­name> OPEN {100343DEE1}>CL­USER> (query "select id, client_id from campaign_base limit 2")((1712 3736) (815 3371))("id" "client_id") ● 多値関数なので…CL­USER> (multiple­value­bind (rows field­names)             (query "select * from campaign_base limit 2")           (dolist (row rows)             (loop :for value :in row                   :for field­name :in field­names                   :do (format t "~a : ~a~%" field­name value))             (terpri))) (terpri) :標準出力に改行を送る関数
    • プログラムで使う場合は● 例によって asdf でロードする●(asdf:oos asdf:load­op :clsql)(asdf:oos asdf:load­op :clsql­mysql) ●(asdf:oos asdf:load­op :clsql­postgresql) ● SLIME の REPL で使う時も手動でロードしとく ● Backend は使いたいやつだけで OK よ● パッケージ名は clsql ● いちいちパッケージ名解決 (clsql:query ... ) とか面倒な人は(use­package :clsql) ● 個人的には use-package はあまりオススメしないけどね。 ● Python で言うところの from clsql import * だし…
    • CLSQL はマニュアルが充実http://clsql.b9.com/manual/index.html ここ読めば普通は困らないと思う
    • これだけだとあまりにアレなのでいくつか Tips など
    • MySQL を使う場合● テーブル名の大文字 / 小文字区別問題 ● Linux 上で動作している MySQL はデフォルトでテーブル名の大文 字と小文字を区別する ( 定義時の名前がそのまま使われる ) ● 標準 SQL では区別しない ● CLSQL は標準準拠 ( 基本的に大文字でサーバに送信する ) テーブル名が見つからないと怒られる● /etc/mysql/my.cnf に以下を追加 ● 追加場所 [mysqld] セクション# for Case insensitivelower_case_table_names          = 1 詳細: http://dev.mysql.com/doc/refman/5.1/ja/identifier-case-sensitivity.html
    • connection オブジェクト● connect 関数 ● データベースへの接続オブジェクトを作成する ● 同じ属性の接続を複数作ろうとするとデフォルトではエラー! ● :if­exists キーワード引数でどうするかを決める – :new 新しく接続オブジェクトを作る – :warn­new 警告出すけどオブジェクトを作る – :error エラーとする – :old すでに開いている接続オブジェクトを返す – :warn­old 警告出して、既存の接続オブジェクトを返す – デフォルト値は *connect­if­exists* 変数で設定できる● connected-databases 関数 ● 現時点で有効な全ての接続オブジェクトをリストで返す● *default-database* 変数 ● 既定の接続オブジェクトを保持する
    • 接続を切る● disconnect 関数を使う ● :database キーワード引数で対象の接続オブジェクトを指定する ● 省略時は clsql:*default­database* が指定されたものとみ なされるCL­USER> (defparameter db­conn nil)CL­USER> (setf db­conn             (connect ("achernar" "stats_master" "xlisting" "xlisting")               :database­type :mysql))CL­USER> (eq db­conn *default­database*)CL­USER> (disconnect :database db­conn)CL­USER> *default­database*
    • SQL Quote の方法● SQL 関数を使えば簡単CL­USER> (format nil "select * from foo where bar in ~a"            (sql ("Hello" "world")))CL­USER> (format nil "select * from foo where bar = ~a"             (sql " 波浪ワールド  Hello World"))CL­USER> (enable­sql­reader­syntax)CL­USER> (let ((msg "Hello lisp world!"))           (sql [select [foo] [bar] :from [baz] :where [= [name] msg]]))CL­USER> (sql [select                 [client_base name]                [agency_base name]                  :from ([client_base] [agency_base])                  :where [= [client_base agency_id] [agency_base id]]]) 値の埋め込みは format 使うよりも SQL テンプレの方がお勧め
    • SQL テンプレ● Lisp の構文そのものが拡張されちゃうので注意 ● グローバルに有効化: (enable-sql-reader-syntax) ● グローバルに無効化: (disable-sql-reader-syntax) ● ローカルに有効化: (locally-enable-sql-reader-syntax) ● ローカルに無効化: (locally-disable-sql-reader-syntax)● [ と ] に意味が追加されてる ● Reader マクロという機能を使っている
    • 取得した行について繰り返し処理● do-query とか loop フォームが便利CL­USER> (do­query ((agency­name client­name)                    (sql [select [agency_base name] [client_base name]                      :from ([agency_base] [client_base])                      :where [and [= [agency_base id] [client_base agency_id]]                                  [= [agency_base id] 22]]]))           (format t "~a : ~a~%" agency­name client­name))CL­USER> (loop :for (agency­name client­name) being each tuple in                     (sql [select [agency_base name] [client_base name]                      :from ([agency_base] [client_base])                      :where [and [= [agency_base id] [client_base agency_id]]                                  [= [agency_base id] 22]]])            :do (format t "~a : ~a~%" agency­name client­name))結果1行毎にガッツり処理したいとき do-queryカウントしたりちょっと加工して収集しなおしたいとか loopて感じで使い分けるといいかも。まぁこのへんは好みというかソースが見やすくなるほうを優先するのが吉。
    • 関数に仕立ててみる● こんな感じとか(defun get­client­info­by­ids (ids)  (let ((result nil))    (multiple­value­bind (rows field­names)        (query (sql [select [*] :from [client_base] :where [in [id] ids]]))              (dolist (row rows)         (push           (loop :for value in row                 :for field­name in field­names                 :collect (cons field­name value)) result)))    result))CL­USER> (get­client­info­by­ids (1 3 5))CL­USER> (dolist (result (get­client­info­by­ids (1 3 5)))           (print (cdr (assoc "name" result :test #string=))))
    • connection pool● こんな感じでやるといいかも(defun get­client­info­by­ids (ids &key (database clsql:*default­database*))  (let ((result nil))    (multiple­value­bind (rows field­names)        (query (sql [select [*] :from [client_base] :where [in [id] ids]])                 :database database)       (dolist (row rows)         (push          (loop :for value in row             :for field­name in field­names             :collect (cons field­name value)) result)))    result))(with­database    (db­conn ("achernar" "stats_master"                "<user­name>" "<password>") :pool t :database­type :mysql)           (get­client­info­by­ids (1 2 3) :database db­conn))
    • create / drop table● ここでもテンプレ使えますCL­USER> (create­table [test_table]                       (([id] integer :not­null :unique :primary­key)                         ([name] (varchar 255) :not­null)                         ([status] boolean :not­null)))CL­USER> (table­exists­p [test_table])CL­USER> (drop­table [test_table])CL­USER> (table­exists­p [test_table])
    • insert / update / delete● それぞれ関数があるので使いましょうCL­USER> (insert­records :into [test_table]                          :attribute (id name status)                         :values (1 "James random Hacker" 1))CL­USER> (select [*] :from [test_table])CL­USER> (update­records [test_table]                          :av­pairs ((name "foo bar")                                     (status 0))                         :where [= [id] 1])CL­USER> (select [*] :from [test_table])CL­USER> (delete­records :from [test_table] :where [= [name] "foo bar"])CL­USER> (select [*] :from [test_table])
    • マニュアルをよく読むべし Lisp 系のマニュアルの書かれ方はちょっと独特だけどCLSQL のマニュアルは例がいっぱいあるので大いに参考にしよう
    • 宿題前回の宿題掲示板のストレージを データベースにしてねちょこっと改造すれは OK のハズなので、簡単でしょ? connection pool を使って with­database フォームを使うのがお勧めかも