2014-09-30 1 views
5

Я генерирую SQL-запросы в Haskell и отправляю их в базу данных SQLite (3) с использованием HDBC. Теперь эта функция возвращает запрос:Сгенерированный SQL-запрос не возвращает то же самое, что и соответствующий статический запрос в sqlite3 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 "2", SqlByteString "6", SqlByteString "0,507488888888889", SqlByteString "0.655905050505051", SqlByteString "четвертый"], [SqlByteString "2", SqlByteString "2", SqlByteString "3", SqlByteString "0.149383838383838", SqlByteString "0.312777777777778", SqlByteString "второй"], [SqlByteString "2", SqlByteString "2", SqlByteString "6", SqlByteString "0.507488888888889", SqlByteString "0,655905050505051", SqlByteString "четвертый"], [SqlByteString "3", SqlByteString " 2" , SqlByteString "3", SqlByteString "0,149383838383838", SqlByteString "0,312777777777778", SqlByteString "второй"], [SqlByteString "3", SqlByteString "2", SqlByteString "6", SqlByteString "0,507488888888889", SqlByteString «+0,655905050505051», SqlByteString «четвёртый»]]

Теперь, когда мне нужно вставить пару небольших динамических частей в запрос, как это (извините, у вас есть, чтобы перейти к концу строки в увидеть это):

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 

[]

Почему второй запрос ничего не возвращает (или, фактически, на самом деле)?

Любые идеи?

Edit:

Ive исследовал этот вопрос дальше, думая, что это, возможно, придется делать с ленивым каким-то образом. Хорошо, теперь изменили к этому:

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 

К сожалению, это не помогает этот вопрос (и когда я: Спринт возвращаемое значение функции в GHCI, он по-прежнему невычисленного). Итак, лень может быть проблемой как-то, но я не знаю, как сделать это полностью оцененным ..? Пожалуйста, какие-нибудь идеи?

+0

Возможно, вы захотите использовать символы новой строки, чтобы команда SQL стала читаемой. Также покажите сгенерированный SQL. –

+0

Сделано! Пожалуйста, помогите мне понять, почему эти два запроса не выполняются одинаково. –

+0

Взгляните на мой ответ и сообщите мне, если я установлю что-то, существенно отличающееся от того, над чем вы работаете. Я честно не могу думать ни о чем другом. Я не могу воспроизвести пустой набор, объединив эти строки (что по существу все, что вы меняете). –

ответ

3

Итак ...просто изложить факты:

  • код мчит он не производит любых синтаксических ошибок или предупреждение (и это для обоего Haskell и SQL, который бежал по Haskell)
  • исходный запрос мчит, но не с опом и позами добавленных (там уже были динамические части к нему)
  • вы получаете пустой набор назад (значение, запрос не возвращает ни одной строки) ...

Если все это верно, это заставляет меня думать, что запрос должен быть действительным, но неправильным. Проверьте данные? Дамп запроса, запустите его вручную. Дай мне знать.

вещи попробовать:

  • Попробуйте откат изменения, чтобы увидеть, если он все еще работает (так что вы знаете, ничего не изменилось, и случайно проверить данные то же самое).
  • Можете ли вы попробовать протестировать более простой запрос?
  • Можете ли вы попробовать сбросить переменную запроса и запустить ее вручную в БД (с изменениями и без изменений)?
  • Вы хотите опубликовать несколько строк своих данных (некоторые строки, которые будут возвращены, некоторые из них не будут), чтобы я мог загрузить его в тестовую таблицу temp с ним?
  • Попробуйте добавить только pos к рабочему запросу (с op жестко) и посмотреть, если это работает
  • Попробуйте добавить только op к рабочему запросу (с pos жестко) и посмотреть, если это работает
  • Марка что вы перечисляете свои переменные в правильном порядке везде

По какой-то причине я продолжаю думать, что это может быть проблема с типом данных с кастингом или что-то в этом роде, но я никогда не работал с Haskell, поэтому я не могу реально угадайте, что еще может произойти.

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

  • format your query правильно, так что легко читается (по крайней мере, немного, так что это не одна огромная строки)
  • обновления вашего вопроса включать спецификации о том, как устанавливаются среда (с версиями программного обеспечения/вещи и прочее)
  • если вы считаете, что проблема связана с лень, try forcing evaluation ...? Но в запросе уже были динамические/переменные части. Я должен был предположить, что у них будет такая же проблема, если бы это было так, и запрос не сработал бы для начала.
  • Это было бы глупо, но вам не удалось изменить, с какой БД вы тянете, не так ли?

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"]] 

так ... в ваших запросах, которые вы разместили в вопросе ... также есть неожиданная разница ... которая не имеет отношения к переменным. Это одна цитата. Не уверен, что только опечатка в копии и вставке или что. Я, очевидно, не может запустить запрос, как это именно потому, что это значительное количество фиктивных таблиц и данных, чтобы придумать ...

enter image description here

редактировать: ха ... Я вернулся к этому снова , Я заметил, что у вас была дополнительная строка над вашим последним 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 ...!

+0

Спасибо за ваши усилия. Я не уверен, что вставил лишний символ '' 'во второй оператор SQL, но я не думаю, что это так. Я получаю 'SqlInt64 2' обратно от' toSql'. Это может быть проблема ..? –

Смежные вопросы