Haskellでデータベース操作
ぐぐったら2006年の自分の日記がヒットしてしまった…。あの頃から特に進展がないことに落ち込みつつ。
haskelldbは、haskelldb-hdbc、haskelldb-hsql、があって、それぞれHDBC、hsqlなどと関連している?
haskelldbのバージョンは0.13なのでちょっと躊躇する。
hsqlとHDBCでどんな感じのコードになるか。
hsql
HSQLを使ってMySQLに接続 - #3(2006-08-22)
HDBC
http://www.mokehehe.com/realworldhaskell/index.php?%A5%C7%A1%BC%A5%BF%A5%D9%A1%BC%A5%B9%C1%E0%BA%EE
うーん。とりあえずメジャーっぽいHDBCを入れてみる。
aptitude install libpq-dev aptitude install libsqlite3-dev cabal install HDBC-postgresql --global cabal install HDBC-sqlite3 --global
import Database.HDBC import Database.HDBC.Sqlite3 main = do conn <- connectSqlite3 "test.db" ret <- quickQuery' conn "SELECT * from test where id > 2" [] mapM_ putStrLn $ map convRow ret disconnect conn convRow :: [SqlValue] -> String convRow [sqlId, sqlDesc] = show intid ++ ": " ++ desc where intid = (fromSql sqlId)::Integer desc = case fromSql sqlDesc of Just x -> x Nothing -> "NULL" convRow x = fail $ "unexpected result: " ++ show x
で、サンプルをコピペ。
quickQuery'っていうぐらいだから、quickじゃない呼び出し方があるんだろうきっと。
プリペアドステートメントっぽい引数も受け取ってるのでこれで十分な気もする。
HDBC.hsをコピペメモ。
module Database.HDBC (-- * Introduction -- $introduction -- ** Features -- $features -- ** Available Drivers -- $drivers -- * Typing of transfer data SqlValue(..), toSql, fromSql, safeFromSql, nToSql, iToSql, posixToSql, -- * Database Connections IConnection, disconnect, clone, -- ** Wrapped Connections ConnWrapper(..), withWConn, -- ** Preparing Queries run, runRaw, sRun, prepare, quickQuery', quickQuery, -- ** Transaction Handling -- $transactions commit, rollback, withTransaction, -- ** Connection Inquiries hdbcDriverName, hdbcClientVer, proxiedClientName, proxiedClientVer, dbServerVer, dbTransactionSupport, getTables, describeTable, -- * Statements Statement, -- ** Execution execute, executeRaw, sExecute, executeMany, sExecuteMany, -- ** Fetching Results fetchRow, fetchRowAL, fetchRowMap, sFetchRow, fetchAllRows, fetchAllRows', fetchAllRowsAL, fetchAllRowsAL', fetchAllRowsMap, fetchAllRowsMap', sFetchAllRows, sFetchAllRows', getColumnNames, -- ** Statement Inquires describeResult, -- ** Miscellaneous finish, originalQuery, -- * Exceptions SqlError(..), throwSqlError, catchSql, handleSql, sqlExceptions, handleSqlError, -- * Column Types -- | These are defined in "Database.HDBC.ColTypes" but are -- available to programs importing "Database.HDBC" by default as well. -- See "Database.HDBC.ColTypes" for documentation. module Database.HDBC.ColTypes -- * Threading -- $threading -- * Copyright and License -- $legal )
クォーテーションがついているものは Strict version らしい。これはevaluateで取得した値をすべて評価している。遅延させずに実行したいときに使うのだろうか。
quickQueryはSqlValueの二重のリストを受け取るのだが、
ghci> conn <- connectSqlite3 "test1.db" ghci> stmt <- prepare conn "SELECT * from test where id < 2" ghci> execute stmt [] 0 ghci> results <- fetchAllRowsAL stmt
こうするとステートメントを受け取って一行一行fetchするっぽい。
fetchRowやfetchRowMapかな?
*Main> :t fetchRow fetchRow :: Statement -> IO (Maybe [SqlValue]) *Main> :t fetchRowMap fetchRowMap :: Statement -> IO (Maybe (Data.Map.Map String SqlValue))
ちょっとめんどくさそう。
手続き型っぽく考えたらfetch→出力のループを回した方が色々節約できそうな気がするがHaskellだとさっぱり検討がつかない。
まぁ大量のデータを扱う段階になってから考えたらいいかな。