Lisp tutorial for Pythonista.Day #4 : Work with RDBMS                                                          Ransui Iso ...
宿題できましたか?
今日は予告通り SQL !なんだかんだで RDBMS 使えないと   仕事では困っちゃう
CLSQL を使います
QuickLisp でインストールclsql と clsql­mysql と clsql­postgresql       をインストールしてくださいませ
REPL 環境下でテストしてみる ●   とりあえず selectCL­USER> (use­package :clsql)CL­USER> (connect ("achernar" "stats_master" "<user­name>" "...
プログラムで使う場合は●   例によって asdf でロードする●(asdf:oos asdf:load­op :clsql)(asdf:oos asdf:load­op :clsql­mysql) ●(asdf:oos asdf:load­o...
CLSQL はマニュアルが充実http://clsql.b9.com/manual/index.html      ここ読めば普通は困らないと思う
これだけだとあまりにアレなのでいくつか Tips など
MySQL を使う場合●   テーブル名の大文字 / 小文字区別問題      ●   Linux 上で動作している MySQL はデフォルトでテーブル名の大文            字と小文字を区別する ( 定義時の名前がそのまま使われる )...
connection オブジェクト●   connect 関数      ●   データベースへの接続オブジェクトを作成する      ●   同じ属性の接続を複数作ろうとするとデフォルトではエラー!      ●   :if­exists キ...
接続を切る●   disconnect 関数を使う      ●   :database キーワード引数で対象の接続オブジェクトを指定する      ●   省略時は clsql:*default­database* が指定されたものとみ   ...
SQL Quote の方法●   SQL 関数を使えば簡単CL­USER> (format nil "select * from foo where bar in ~a"            (sql ("Hello" "world")))C...
SQL テンプレ●   Lisp の構文そのものが拡張されちゃうので注意     ●   グローバルに有効化:   (enable-sql-reader-syntax)     ●   グローバルに無効化:   (disable-sql-rea...
取得した行について繰り返し処理●   do-query とか loop フォームが便利CL­USER> (do­query ((agency­name client­name)                    (sql [select [...
関数に仕立ててみる●   こんな感じとか(defun get­client­info­by­ids (ids)  (let ((result nil))    (multiple­value­bind (rows field­names)   ...
connection pool●   こんな感じでやるといいかも(defun get­client­info­by­ids (ids &key (database clsql:*default­database*))  (let ((resul...
create / drop table●   ここでもテンプレ使えますCL­USER> (create­table [test_table]                       (([id] integer :not­null :uni...
insert / update / delete●   それぞれ関数があるので使いましょうCL­USER> (insert­records :into [test_table]                          :attribu...
マニュアルをよく読むべし    Lisp 系のマニュアルの書かれ方はちょっと独特だけどCLSQL のマニュアルは例がいっぱいあるので大いに参考にしよう
宿題前回の宿題掲示板のストレージを   データベースにしてねちょこっと改造すれは OK のハズなので、簡単でしょ?         connection pool を使って with­database フォームを使うのがお勧めかも
Upcoming SlideShare
Loading in …5
×

Lisp Tutorial for Pythonista : Day 4

5,660 views

Published on

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

Published in: Technology
1 Comment
1 Like
Statistics
Notes
  • なんか、どんどん for Pythonistaじゃなくなってきてるけど、細かいことは気にしない!
    お仕事で使う言語としては RDBMS をハンドリングできないと意味ないので、今回は CLSQL つかってデータベースとお話というお話。
    例によって実用というか、とにかくサクサク書いてサクサク使うをモットーにしてるので、ダサいコーディングとか伝統的なイディオムの無視とかやりまくってます。上級Lisper諸氏においては、生暖かく見守ってください。
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
5,660
On SlideShare
0
From Embeds
0
Number of Embeds
10
Actions
Shares
0
Downloads
0
Comments
1
Likes
1
Embeds 0
No embeds

No notes for slide

Lisp Tutorial for Pythonista : Day 4

  1. 1. Lisp tutorial for Pythonista.Day #4 : Work with RDBMS Ransui Iso Strategic Technology Group, X-Listing Co, Ltd.
  2. 2. 宿題できましたか?
  3. 3. 今日は予告通り SQL !なんだかんだで RDBMS 使えないと 仕事では困っちゃう
  4. 4. CLSQL を使います
  5. 5. QuickLisp でインストールclsql と clsql­mysql と clsql­postgresql をインストールしてくださいませ
  6. 6. 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) :標準出力に改行を送る関数
  7. 7. プログラムで使う場合は● 例によって 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 * だし…
  8. 8. CLSQL はマニュアルが充実http://clsql.b9.com/manual/index.html ここ読めば普通は困らないと思う
  9. 9. これだけだとあまりにアレなのでいくつか Tips など
  10. 10. 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
  11. 11. connection オブジェクト● connect 関数 ● データベースへの接続オブジェクトを作成する ● 同じ属性の接続を複数作ろうとするとデフォルトではエラー! ● :if­exists キーワード引数でどうするかを決める – :new 新しく接続オブジェクトを作る – :warn­new 警告出すけどオブジェクトを作る – :error エラーとする – :old すでに開いている接続オブジェクトを返す – :warn­old 警告出して、既存の接続オブジェクトを返す – デフォルト値は *connect­if­exists* 変数で設定できる● connected-databases 関数 ● 現時点で有効な全ての接続オブジェクトをリストで返す● *default-database* 変数 ● 既定の接続オブジェクトを保持する
  12. 12. 接続を切る● 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*
  13. 13. 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 テンプレの方がお勧め
  14. 14. SQL テンプレ● Lisp の構文そのものが拡張されちゃうので注意 ● グローバルに有効化: (enable-sql-reader-syntax) ● グローバルに無効化: (disable-sql-reader-syntax) ● ローカルに有効化: (locally-enable-sql-reader-syntax) ● ローカルに無効化: (locally-disable-sql-reader-syntax)● [ と ] に意味が追加されてる ● Reader マクロという機能を使っている
  15. 15. 取得した行について繰り返し処理● 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て感じで使い分けるといいかも。まぁこのへんは好みというかソースが見やすくなるほうを優先するのが吉。
  16. 16. 関数に仕立ててみる● こんな感じとか(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=))))
  17. 17. 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))
  18. 18. 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])
  19. 19. 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])
  20. 20. マニュアルをよく読むべし Lisp 系のマニュアルの書かれ方はちょっと独特だけどCLSQL のマニュアルは例がいっぱいあるので大いに参考にしよう
  21. 21. 宿題前回の宿題掲示板のストレージを データベースにしてねちょこっと改造すれは OK のハズなので、簡単でしょ? connection pool を使って with­database フォームを使うのがお勧めかも

×