简体   繁体   中英

Insert Database Haskell

I have a list like: [["a","b"],["c","d"],["e","f"]] , ie (row1, row2, row3) I want to insert data. My code is

store xs =
 do conn <- connectSqlite3 "ld.db"
    stmt <- prepare conn "INSERT INTO ld (url, des) VALUES (?,?)"
    executeMany stmt [(head (map (\x -> [toSql x]) xs) ++ last (map (\x -> [toSql x]) xs))]
    commit conn

It is working fine if I use individually store ["a","b"] . But I have failed to insert like store [["a","b"],["c","d"],["e","f"]] . I tried in several ways but failed. We need proper use of map . Thanks.

This will work-

let values = [["a", "b"], ["c", "d"], ["e", "f"]]
sequence $ map store values

Alternatively, you could use the more intuitive-

forM values store

which works sort of like a Haskell version of an imperitive for loop. Think of it like the Java/c/javascript like pseudocode:

for(value in values) 
{
  store(value);
}

You will have to import Control.Monad.

This being said, you might want to refactor this.... You are creating a connection for each insert, which can degrade performance (just pull the connectSqlite3 and commit lines out of the function, and pass conn in as a parameter).


I am editing to add a bit of discussion on types, so that you can better understand what is going on here.

store ["a", "b"]

is of type IO().... This is what main wants, so you are set.

map store values

is of type [IO()], which needs to be converted to IO() before it can be used in main. To some extent, the whole purpose of any Haskell program is to generate a single IO() that main can use to modify the world (input and output). If you hand main a list of these, it doesn't know which one to use.

sequence

is a function that takes a list of IO()'s and "sequences" them into one single IO(), which can be used by main. (For the advanced folks, I know, it actually works for any monad, but I think that might confuse matters at this point).

forM

is just a friendly rewriting of sequence with parameters moved around.

There are two problems with this code:

  1. Lack of proper imports (Database.HDBC.SqlValue for conversion)

  2. Type of store for a single row cannot be the same as store for many rows.

Improved code:

module Main(main) where

import Database.HDBC.Sqlite3
import Database.HDBC
import Database.HDBC.Types
import Database.HDBC.SqlValue
import Data.Convertible.Base

storeOne :: [String] -> IO ()
storeOne xs =
  do conn <- connectSqlite3 "ld.db"
     stmt <- prepare conn "INSERT INTO ld (url, des) VALUES (?,?)"
     execute stmt $ map toSql xs
     commit conn

storeMany :: [[String]] -> IO ()
storeMany xs =
  do conn <- connectSqlite3 "ld.db"
     stmt <- prepare conn "INSERT INTO ld (url, des) VALUES (?,?)"
     executeMany stmt $ map (map toSql) xs
     commit conn

main = do storeOne ["a", "b"]
          storeMany [["a","b"],["c","d"],["e","f"]]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM