Генерираната SQL заявка не връща същото като съответната статична заявка в sqlite3 HDBC

Генерирам SQL заявки в Haskell и ги изпращам в база данни SQLite(3), използвайки HDBC. Сега тази функция връща заявка:

import Database.HDBC.Sqlite3 
import Database.HDBC
data UmeQuery = UmeQuery String [SqlValue] deriving Show

tRunUmeQuery :: UmeQuery -> FilePath -> IO [[SqlValue]]
tRunUmeQuery (UmeQuery q args) dbFile = do
    conn <- connectSqlite3 dbFile
    stat <- prepare conn q
    s <- execute stat args
    res <- fetchAllRows' stat 
    disconnect conn
    return $ res

selectPos targetlt parentlt op pos = let 
    q= "select TARGET.* from levels tl, labeltypes tlt, segments TARGET, 
    (select TARGET.session_id session_id,SECONDARY.labeltype_id labeltype_id, 
    SECONDARY.label_id label_id,min(TARGET.label_id) min_childlabel_id from 
    levels tl, labeltypes tlt, segments TARGET, segments SECONDARY, labeltypes slt, 
    levels sl where TARGET.session_id = SECONDARY.session_id and ((SECONDARY.start 
    <= TARGET.start and TARGET.end <= SECONDARY.end) or (TARGET.start <= SECONDARY.start 
    and SECONDARY.end <= TARGET.end)) and tl.name = ? and sl.name = ? and SECONDARY.label '
    != '' and tl.id = tlt.level_id and sl.id = slt.level_id and tlt.id = TARGET.labeltype_id 
    and slt.id = SECONDARY.labeltype_id group by TARGET.session_id, TARGET.labeltype_id, 
    SECONDARY.label_id) SUMMARY, segments SECONDARY, labeltypes slt, levels sl where 
    TARGET.session_id = SECONDARY.session_id and TARGET.session_id = SUMMARY.session_id 
    and ((SECONDARY.start <= TARGET.start and TARGET.end <= SECONDARY.end) or (TARGET.start 
    <= SECONDARY.start and SECONDARY.end <= TARGET.end)) and tl.name = ? and sl.name = ? 
    and tl.id = tlt.level_id and tlt.id = TARGET.labeltype_id and SUMMARY.labeltype_id = 
    SECONDARY.labeltype_id and SUMMARY.label_id = SECONDARY.label_id and sl.id = slt.level_id 
    and slt.id = SECONDARY.labeltype_id and (TARGET.label_id - SUMMARY.min_childlabel_id +1) = 2 "
    a = [toSql targetlt, toSql parentlt, toSql targetlt, toSql parentlt ]
    in UmeQuery q a

което, когато се приложи към базата данни, връща правилното нещо:

> let a =selectPos "Word" "Utterance" "=" 2
> let b = tRunUmeQuery a testdb 
> b

изходи:

[[SqlByteString "1",SqlByteString "2",SqlByteString "3",SqlByteString "0.149383838383838",SqlByteString "0.312777777777778",SqlByteString "втори"],[SqlByteString "1",SqlByteString "SqlByteqBly",String "2",SqlByteString "SqlByteqBly", "0.507488888888889",SqlByteString "0.655905050505051",SqlByteString "fourth"],[SqlByteString "2",SqlByteString "2",SqlByteString "3",SqlByteString "0.149383838383838",SqlByteString "0.312777777777778",SqlByteString "second"],[SqlByteString " 2 ", SqlByTestring" 2 ", SqlByTestring" 6 ", SqlByTestring" 0.50748888888889 ", SqlByTestring" 0.655905050505051 ", SqlByTestring" Четвърти "], [SqlByTestring" 3 ", SqlByTestring" 1 -ти ". SqlByteString "0.312777777777778",SqlByteString "втори"],[SqlByteString "3",SqlByteString "2",SqlByteString "6",SqlByteString "0.507488888888889",SqlByteString "0.65590ByteString","]четири"50505Sql050

Сега, когато трябва да вмъкна няколко малки динамични части в заявката, като това (съжалявам, трябва да превъртите до края на низа, за да видите това):

selectPos targetlt parentlt op pos = let
    q= "select TARGET.* from levels tl, labeltypes tlt, segments TARGET, 
    (select TARGET.session_id session_id,SECONDARY.labeltype_id labeltype_id,
    SECONDARY.label_id label_id,min(TARGET.label_id) min_childlabel_id from 
    levels tl, labeltypes tlt, segments TARGET, segments SECONDARY, labeltypes slt,
     levels sl where TARGET.session_id = SECONDARY.session_id and ((SECONDARY.start 
     <= TARGET.start and TARGET.end <= SECONDARY.end) or (TARGET.start <= SECONDARY.start 
     and SECONDARY.end <= TARGET.end)) and tl.name = ? and sl.name = ? and SECONDARY.label 
     != '' and tl.id = tlt.level_id and sl.id = slt.level_id and tlt.id = TARGET.labeltype_id 
     and slt.id = SECONDARY.labeltype_id group by TARGET.session_id, TARGET.labeltype_id, 
     SECONDARY.label_id) SUMMARY, segments SECONDARY, labeltypes slt, levels sl where 
     TARGET.session_id = SECONDARY.session_id and TARGET.session_id = SUMMARY.session_id 
     and ((SECONDARY.start <= TARGET.start and TARGET.end <= SECONDARY.end) or (TARGET.start
      <= SECONDARY.start and SECONDARY.end <= TARGET.end)) and tl.name = ? and sl.name = ? 
      and tl.id = tlt.level_id and tlt.id = TARGET.labeltype_id and SUMMARY.labeltype_id = 
      SECONDARY.labeltype_id and SUMMARY.label_id = SECONDARY.label_id and sl.id = slt.level_id 
      and slt.id = SECONDARY.labeltype_id and (TARGET.label_id - SUMMARY.min_childlabel_id +1) " 
      ++ op ++ " ? "
    a = [toSql targetlt, toSql parentlt, toSql targetlt, toSql parentlt , toSql pos]
    in UmeQuery q a

и правя същото, получавам:

> let a =selectPos "Word" "Utterance" "=" 2
> let b = tRunUmeQuery a testdb  
> b 

[]

Защо втората заявка не връща нищо (или всъщност същото)?

Някакви идеи?

Редактиране:

Проучих това допълнително, мислейки, че това може да е свързано по някакъв начин с мързелив. Добре, сега е преоформено на това:

selectPos :: String -> String -> String -> Integer -> [[SqlValue]]
selectPos targetlt parentlt op pos = let
    q= foldl' (++)  [] ["select TARGET.* from levels tl, labeltypes tlt, segments TARGET, 
    (select TARGET.session_id session_id,SECONDARY.labeltype_id labeltype_id,SECONDARY.label_id 
    label_id,min(TARGET.label_id) min_childlabel_id from levels tl, labeltypes tlt, segments 
    TARGET, segments SECONDARY, labeltypes slt, levels sl where TARGET.session_id = SECONDARY.session_id "
    ,matchstring , " and tl.name = ? and sl.name = ? and SECONDARY.label != '' and tl.id = tlt.level_id 
    and sl.id = slt.level_id and tlt.id = TARGET.labeltype_id and slt.id = SECONDARY.labeltype_id 
    group by TARGET.session_id, TARGET.labeltype_id, SECONDARY.label_id) SUMMARY, segments SECONDARY, 
    labeltypes slt, levels sl where TARGET.session_id = SECONDARY.session_id and TARGET.session_id = 
    SUMMARY.session_id " , matchstring , " and tl.name = ? and sl.name = ? and tl.id = tlt.level_id 
    and tlt.id = TARGET.labeltype_id and SUMMARY.labeltype_id = SECONDARY.labeltype_id and SUMMARY.label_id
     = SECONDARY.label_id and sl.id = slt.level_id and slt.id = SECONDARY.labeltype_id and 
     (TARGET.label_id - SUMMARY.min_childlabel_id +1) " , op , " ? "]  
    a = [toSql targetlt, toSql parentlt, toSql targetlt, toSql parentlt , toSql (pos :: Integer)]
    in UmeQuery q a

За съжаление, това не помага на проблема (и когато :sprint върнатата стойност на функцията в ghci, тя все още не е оценена). Така че мързелът може да е проблемът по някакъв начин, но не знам как да направя това напълно оценено..? Моля, някакви идеи?


person Fredrik Karlsson    schedule 30.09.2014    source източник
comment
Може да искате да използвате нови редове, така че SQL командата да стане четлива. Също така покажете генерирания SQL.   -  person CL.    schedule 03.10.2014
comment
Свършен! Моля, помогнете ми да разбера защо тези две заявки не се изпълняват по един и същи начин.   -  person Fredrik Karlsson    schedule 03.10.2014
comment
Погледнете отговора ми и ме уведомете, ако настроя нещо, което е значително различно от това, на което работите. Честно казано не се сещам за нищо друго. Не мога да възпроизведа празен набор чрез конкатениране на тези низове (което по същество е всичко, което променяте).   -  person gloomy.penguin    schedule 06.10.2014


Отговори (1)


И така... само за да изложа фактите:

  • вашият код се изпълнява, той не създава никакви синтактични грешки или предупреждения (и това е както за haskell, така и за sql, който се изпълнява от haskell)
  • оригиналната заявка се изпълнява, но не с добавени op и pos (вече имаше динамични части към нея)
  • получавате празен набор обратно (което означава, че заявката не връща редове)...

Ако всички тези неща са верни, това ме кара да вярвам, че заявката трябва да е валидна, но грешна. Проверете данните? Изхвърлете заявката, стартирайте я ръчно. Кажи ми.

неща, които да опитате:

  • Опитайте да върнете обратно промените, за да видите дали все още работи (за да знаете, че нищо не е променено случайно и да проверите дали данните са същите).
  • Можете ли да опитате да тествате с по-проста заявка?
  • Можете ли да опитате да изхвърлите променливата на заявката и да я стартирате ръчно в DB (със и без промени)?
  • Искате ли да публикувате няколко реда от вашите данни (някои редове, които ще бъдат върнати, други – не), за да мога да ги заредя в тестова таблица с тях?
  • Опитайте да добавите само pos към работещата заявка (с твърдо кодиран op) и вижте дали това работи
  • Опитайте да добавите само op към работещата заявка (с твърдо кодиран pos) и вижте дали това работи
  • Уверете се, че изброявате вашите променливи в правилния ред навсякъде

По някаква причина продължавам да мисля, че може да е проблем с типа на данните с кастинг или нещо подобно, но никога не съм работил с Haskell, така че не мога да предположа какво друго може да се случи.

Други предложения:

  • форматирайте заявката си правилно, така че да е лесна за четене (поне малко, така че да не е един огромен низ)
  • актуализирайте въпроса си, за да включите спецификации за това как е настроена вашата среда (с версии на софтуер/неща и други неща)
  • ако смятате, че проблемът е свързан с мързел, опитайте да принудите оценка... ? Но заявката вече имаше динамични/променливи части към нея. Трябва да предположа, че те биха имали същия проблем, ако случаят беше такъв, и заявката нямаше да работи от самото начало.
  • това би било глупаво, но не сте променили базата данни, от която теглите, нали?

sqlite> select * from temp;
temp_id     temp_name
----------  ----------
1           one
2           two
3           three
import Database.HDBC.Sqlite3 
import Database.HDBC

testdb = "C:\\Users\\Kim!\\test.db"

data UmeQuery = UmeQuery String [SqlValue] deriving Show

tRunUmeQuery :: UmeQuery -> FilePath -> IO [[SqlValue]]

tRunUmeQuery (UmeQuery q args) dbFile = do
    conn <- connectSqlite3 dbFile
    stat <- prepare conn q
    s <- execute stat args
    res <- fetchAllRows' stat 
    disconnect conn
    return $ res
     
selectPos temp_id op = let 
   q = "select temp_id, temp_name from temp where temp_id = " ++ op ++ " ?";  
   a = [ toSql temp_id ] 
   in UmeQuery q a
> let a = selectPos (1::Int) "="
> let b = tRunUmeQuery a testdb 
> b
[[SqlByteString "1",SqlByteString "one"]]

> let a = selectPos (1::Int) ">"
> let b = tRunUmeQuery a testdb 
> b
[[SqlByteString "2",SqlByteString "two"],[SqlByteString "3",SqlByteString "three"]] 

Бърза бележка: Никога не съм докосвал Haskell или SQLite преди днес. Работя с Haskell Platform 2014.2.0.0 с този SQLite3 - sqlite-dll-win64-x64-201409301904.zip на Windows 7 Professional 64bit.

редактиране: това също работи... (заявката също е малко по-различна)

import Data.List

selectPos temp_id op temp_name = let 
   q = foldl' (++)  [] [
       "select temp_id, temp_name        " ++ 
       "from   temp                      " ++
       "where  temp_id " , op , " ? or   " ++
       "       temp_name = ?             "]
   a = [ toSql (temp_id::Int), toSql temp_name ]  
   in UmeQuery q a

> let a = selectPos 1 ">" "one"
> let b = tRunUmeQuery a testdb 
> b
[[SqlByteString "1",SqlByteString "one"],[SqlByteString "2",SqlByteString "two"],[SqlByteString "3",SqlByteString "three"]] 

редактиране: и това работи...

sqlite> insert into temp values (4, "Word"); 
sqlite> insert into temp values (5, "Utterance");

selectPos targetlt parentlt op pos = let 
   q = " select temp_id, temp_name        \
       \ from   temp                      \
       \ where  temp_name = ?  or         \
       \        temp_name = ?  or         \
       \        temp_name = ?  or         \
       \        temp_name = ?  or         \
       \        temp_id "++op++" ?        "
   a = [toSql targetlt, toSql parentlt, 
        toSql targetlt, toSql parentlt, 
        toSql (pos::Int) ]
   in UmeQuery q a

> let a = selectPos "Word" "Utterance" "=" 2
> let b = tRunUmeQuery a testdb 
> b
[[SqlByteString "2",SqlByteString "two"],[SqlByteString "4",SqlByteString "Word"],[SqlByteString "5",SqlByteString "Utterance"]]

така че... във вашите заявки, които сте публикували във въпроса... има и неочаквана разлика... която не е свързана с променливите. Това е единичен цитат. Не съм сигурен дали просто правописна грешка при копиране и поставяне или какво. Очевидно не мога да изпълня вашата заявка така, както е точно, защото това е значително количество фалшиви таблици и данни, които трябва да се измислят...

въведете описание на изображението тук

редактиране: ха... Върнах се отново към това. Забелязах, че имаш допълнителен ред над последния си selectPos пример, който не използвах. Трябваше да го направя така, за да заработи... [[SqlValue]] или IO [[SqlValue]] като последната стойност не работи за мен; грешки (просто опитвам неща, не знам дали някоя от тези стойности наистина има смисъл).

selectPos :: String -> String -> String -> Integer -> UmeQuery
selectPos targetlt parentlt op pos = let 
   q = " select temp_id, temp_name        \
       \ from   temp                      \
       \ where  temp_name = ?  or         \
       \        temp_name = ?  or         \
       \        temp_name = ?  or         \
       \        temp_name != ?  or        \
       \        temp_id "++op++" ?        "
   a = [toSql targetlt, toSql parentlt, 
        toSql targetlt, toSql parentlt, 
        toSql pos ]
   in UmeQuery q a

> let a = selectPos "Word" "Utterance" "=" 2
> let b = tRunUmeQuery a testdb 
> b
[[SqlByteString "1",SqlByteString "one"],[SqlByteString "2",SqlByteString "two"],[SqlByteString "3",SqlByteString "three"],[SqlByteString "4",SqlByteString "Word"],[SqlByteString "5",SqlByteString "Utterance"]] 

така или иначе по този въпрос... щастлив съм, че трябва да напиша първата си програма на Haskell днес...!

person gloomy.penguin    schedule 05.10.2014
comment
Благодаря ви за вашите усилия. Не съм сигурен какво е вмъкнало допълнителния 'char във втория SQL оператор, но не мисля, че това е всичко. Получавам SqlInt64 2 обратно от toSql. Възможно ли е това да е проблемът..? - person Fredrik Karlsson; 07.10.2014