• handling null value in sql query in haskell

    From damien.mattei@gmail.com@21:1/5 to All on Tue Dec 18 03:24:09 2018
    I have this query in SQL used by my Haskell code:

    let name = "A 20"
    let qry_head_WDS = "select DNUM from WDS where DISC = ?" :: Query
    putStrLn "before query WDS"
    bd_rows_WDS <- query conn qry_head_WDS (Only (name::String))
    putStrLn "after query WDS"

    forM_ bd_rows_WDS $ \(Only a) ->
    putStrLn $ Text.unpack a

    works well if there is no NULL values in a database, but if NULL value for field N°BD i got this exception at runtime:

    before query WDS
    *** Exception: UnexpectedNull {errSQLType = "String", errHaskellType =
    "Text", errFieldName = "DNUM", errMessage = "unexpected null in table
    WDS of database sidonie"}
    *Main>

    Can you help me to handle NULL values in the field N°BD

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Benjamin Esham@21:1/5 to damien.mattei@gmail.com on Tue Dec 18 18:08:38 2018
    damien.mattei@gmail.com wrote:

    I have this query in SQL used by my Haskell code:

    let name = "A 20"
    let qry_head_WDS = "select DNUM from WDS where DISC = ?" :: Query
    putStrLn "before query WDS"
    bd_rows_WDS <- query conn qry_head_WDS (Only (name::String))
    putStrLn "after query WDS"

    forM_ bd_rows_WDS $ \(Only a) ->
    putStrLn $ Text.unpack a

    works well if there is no NULL values in a database, but if NULL value for field N°BD i got this exception at runtime: [snip]

    First, what kind of database are you using and which library are you using
    to access it? This may make a difference to the solution.

    I think you may be able to get the result you want by indicating to
    Haskell's type inference that bd_rows_WDS should have type [Maybe Text], not [Only Text], since there actually are NULLs in your database and you need to
    be able to handle them. Try replacing your last line with this:

    forM_ bd_rows_WDS $ \row -> case row of
    Nothing -> putStrLn "The value was NULL"
    Just text -> putStrLn $ Text.unpack text

    It may also be necessary to explicitly mention the type you expect for bd_rows_WDS:

    bd_rows_WDS :: [Maybe Text] <-
    query conn qry_head_WDS (Only (name::String))

    Hope this helps,

    Benjamin

    --
    Benjamin Esham
    https://esham.io

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From damien.mattei@gmail.com@21:1/5 to Benjamin Esham on Wed Dec 19 00:42:48 2018
    On Tuesday, December 18, 2018 at 7:08:39 PM UTC+1, Benjamin Esham wrote:
    damien.mattei@gmail.com wrote:

    I have this query in SQL used by my Haskell code:

    let name = "A 20"
    let qry_head_WDS = "select DNUM from WDS where DISC = ?" :: Query
    putStrLn "before query WDS"
    bd_rows_WDS <- query conn qry_head_WDS (Only (name::String))
    putStrLn "after query WDS"

    forM_ bd_rows_WDS $ \(Only a) ->
    putStrLn $ Text.unpack a

    works well if there is no NULL values in a database, but if NULL value for field N°BD i got this exception at runtime: [snip]

    First, what kind of database are you using and which library are you using
    to access it? This may make a difference to the solution.

    I think you may be able to get the result you want by indicating to
    Haskell's type inference that bd_rows_WDS should have type [Maybe Text], not [Only Text], since there actually are NULLs in your database and you need to be able to handle them. Try replacing your last line with this:

    forM_ bd_rows_WDS $ \row -> case row of
    Nothing -> putStrLn "The value was NULL"
    Just text -> putStrLn $ Text.unpack text

    It may also be necessary to explicitly mention the type you expect for bd_rows_WDS:

    bd_rows_WDS :: [Maybe Text] <-
    query conn qry_head_WDS (Only (name::String))

    Hope this helps,

    Benjamin

    --
    Benjamin Esham
    https://esham.io

    i think it's a good idea Benjamin but unfortunately i get an error i do not understand from compiler:

    *Main> :load UpdateSidonie
    [1 of 1] Compiling Main ( UpdateSidonie.hs, interpreted )

    UpdateSidonie.hs:213:5: error:
    Illegal type signature: ‘[Maybe Text]’
    Type signatures are only allowed in patterns with ScopedTypeVariables
    |
    213 | bd_rows_WDS :: [Maybe Text] <- query conn qry_head_WDS (Only (name::String))
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    Failed, no modules loaded.

    Damien

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Benjamin Esham@21:1/5 to damien.mattei@gmail.com on Wed Dec 19 17:47:18 2018
    damien.mattei@gmail.com wrote:

    On Tuesday, December 18, 2018 at 7:08:39 PM UTC+1, Benjamin Esham wrote:

    damien.mattei@gmail.com wrote:

    I have this query in SQL used by my Haskell code:

    let name = "A 20"
    let qry_head_WDS = "select DNUM from WDS where DISC = ?" :: Query
    putStrLn "before query WDS"
    bd_rows_WDS <- query conn qry_head_WDS (Only (name::String))
    putStrLn "after query WDS"

    forM_ bd_rows_WDS $ \(Only a) ->
    putStrLn $ Text.unpack a

    works well if there is no NULL values in a database, but if NULL value for >> > field N°BD i got this exception at runtime: [snip]

    [snip]

    It may also be necessary to explicitly mention the type you expect for
    bd_rows_WDS:

    bd_rows_WDS :: [Maybe Text] <-
    query conn qry_head_WDS (Only (name::String))

    i think it's a good idea Benjamin but unfortunately i get an error i do
    not understand from compiler:

    *Main> :load UpdateSidonie
    [1 of 1] Compiling Main ( UpdateSidonie.hs, interpreted )

    UpdateSidonie.hs:213:5: error:
    Illegal type signature: ‘[Maybe Text]’
    Type signatures are only allowed in patterns with ScopedTypeVariables
    |
    213 | bd_rows_WDS :: [Maybe Text] <- query conn qry_head_WDS (Only (name::String))
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    Failed, no modules loaded.

    Ah, sorry about that. I forgot that if you want to add a type annotation
    like this you need to be using the ScopedTypeVariables extension. You can do that by adding the line

    {-# LANGUAGE ScopedTypeVariables #-}

    to your source file or by adding the line

    default-extensions: ScopedTypeVariables

    to your cabal file, under either the "executable" or "library" sections depending on which one of those you're creating.

    I /also/ messed up the type I suggested that bd_rows_WDS should be. It's a
    list of Only (Maybe Text), not a list of Maybe Text.

    After playing around with a test database using postgres-simple, I came up
    with this for your code:

    let name = "A 20"
    let qry_head_WDS = "select DNUM from WDS where DISC = ?" :: Query
    putStrLn "before query WDS"
    bd_rows_WDS :: [Only (Maybe Text)]
    <- query conn qry_head_WDS (Only (name::String))
    putStrLn "after query WDS"

    forM_ bd_rows_WDS $ \(Only a) -> case a of
    Just a' -> putStrLn $ Text.unpack a'
    Nothing -> putStrLn "It's null"

    However, in my testing, I found that the type annotation for bd_rows_WDS is actually not needed: Haskell is able to infer the correct type because the lambda that you pass to forM_ tells the compiler unambiguously that each element of bd_rows_WDS has type Only (Maybe Text).

    So to fix your original problem, all you need to do is to change your lambda
    as shown here; you don't need to add that ":: [Only (Maybe Text)]"
    annotation or turn on ScopedTypeVariables. In some situations that may be necessary--or at least more convenient--but it turns out that it's not
    needed here.

    Hope this helps!

    Benjamin

    --
    Benjamin Esham
    https://esham.io

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)