Сгенерированный 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 "second", SqlByString "2" String "2" String "2-й" "0.507488888888889",SqlByteString "0.655905050505051", SqlByteString "четвертый"], [SqlByteString "2", SqlByteString "2", SqlByteString "3", SqlByteString "0,1493877StString" 0,34938B2S77_37BTS37_37BTS37_37B) 2 ", SqlByteString" 2 ", SqlByteString" 6 ", SqlByteString" 0.507488888888889 ", SqlByteString" 0.655905050505051 ", SqlByteString" четвертый "], [SqlByteString" 3 ", Sqlt383838" S38B3838 "S38B3838" S38BY3838 "SID SqlByteString "0.312777777777778",SqlByteString "second"],[SqlByteString "3",SqlByteString "2",SqlByteString "6",SqlByteString "0,5048488888888889",SqlByb505050String "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 

[]

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

Есть идеи?

Редактировать:

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

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, она все еще не оценена). Таким образом, лень может быть проблемой, так или иначе, но я не знаю, как сделать это полностью оцененным..? Пожалуйста, есть идеи?

1 ответ

Решение

Так что... просто констатирую факты

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

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

что попробовать:

  • Попробуйте откатить изменения, чтобы убедиться, что они все еще работают (чтобы вы знали, что ничего не было случайно изменено, и убедитесь, что данные совпадают).
  • Можете ли вы попробовать тестирование с более простым запросом?
  • Можете ли вы попробовать сбросить переменную запроса и запустить ее вручную в БД (с изменениями и без них)?
  • Вы хотите опубликовать несколько строк ваших данных (некоторые строки, которые будут возвращены, некоторые - нет), чтобы я мог загрузить их в тест временной таблицы?
  • Попробуйте добавить просто 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 2014.2.0.0 с этим SQLite3 - sqlite-dll-win64-x64-201409301904.zip в 64- разрядной версии Windows 7 Professional.

редактировать: это тоже работает... (запрос тоже немного другой)

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...!

Другие вопросы по тегам