2014-09-30 9 views
5

Sto generando query SQL in Haskell e li invio a un database SQLite (3) utilizzando HDBC. Ora, questa funzione restituisce una query:Query SQL generata che non restituisce la stessa query statica corrispondente in 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 

che, una volta applicato al database restituisce la cosa giusta:

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

uscite:

[[SqlByteString "1", SqlByteString "2", SqlByteString "3", SqlByteString "0,149383838383838", SqlByteString "0,312777777777778", SqlByteString "secondo"], [SqlByteString "1", SqlByteString "2", SqlByteString "6", SqlByteString "0,507488888888889", SqlByteString "0,655905050505051", SqlByteString "quarto"], [SqlByteString "2", SqlByteString "2", SqlByteString "3", SqlByteString "0,149383838383838", SqlByteString "0,312777777777778", SqlByteString "secondo"], [SqlByteString "2", SqlByteString "2", SqlByteString "6", SqlByteString "0,507488888888889", SqlByteString "0,655905050505051", SqlByteString "quarto"], [SqlByteString "3", SqlByteString " 2" , SqlByteString "3", SqlByteString "0,149383838383838", SqlByteString "0,312777777777778", SqlByteString "secondo"], [SqlByteString "3", SqlByteString "2", SqlByteString "6", SqlByteString "0,507488888888889", SqlByteString "0,655905050505051", SqlByteString "quarto"]]

Ora, quando ho bisogno di inserire un paio di piccole parti dinamiche nella query, come questo (mi dispiace, si deve scorrere fino alla fine della stringa da vedere questo):

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 

e fare la stessa cosa, ottengo:

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

[]

Come mai la seconda query non restituisce nulla (o, la stessa cosa in realtà)?

Qualche idea?

Edit:

Ive ha studiato questo ulteriore, pensando che questo possa avere a che fare con pigro in qualche modo. Ok, l'ora è stato rimodellato per questo:

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 

Purtroppo, questo non aiuta il problema (e quando ho: Movimento il valore di ritorno della funzione in ghci, è ancora non valutata). Quindi, la pigrizia potrebbe essere il problema in qualche modo, ma non so come farlo pienamente valutato ..? Per favore, qualche idea?

+0

È possibile utilizzare le nuove righe in modo che il comando SQL diventi leggibile. Mostra anche l'SQL generato. –

+0

Fatto! Per favore aiutami a capire perché queste due domande non vengono eseguite allo stesso modo. –

+0

Dai un'occhiata alla mia risposta e fammi sapere se ho impostato qualcosa che è significativamente diverso da quello su cui stai lavorando. Onestamente non riesco a pensare ad altro. Non riesco a riprodurre un set vuoto concatenando quelle stringhe (che è essenzialmente tutto ciò che cambi). –

risposta

3

Quindi ...solo a comunicare i fatti:

  • il codice viene eseguito non produce eventuali errori di sintassi o avvisi (e questo è sia per il Haskell e l'SQL che è la corsa per la Haskell)
  • la query originale viene eseguito, ma non con op e pos aggiunto (c'erano parti già dinamiche ad esso)
  • si ottiene un insieme vuoto indietro (significato, la query non restituisce alcuna riga) ...

Se tutte queste cose sono vere, mi porta a credere che la query deve essere valida ma sbagliata. Controllare i dati? Scarica la query, eseguila manualmente. Fammi sapere.

cose da provare:

  • provare a rotolare indietro le modifiche per vedere se funziona ancora (in modo da sapere niente è stato accidentalmente cambiato e per verificare i dati è lo stesso).
  • Puoi provare a testare con una query più semplice?
  • Puoi provare a scaricare la variabile di query e eseguirla manualmente nel DB (con e senza modifiche)?
  • Vuoi pubblicare alcune righe dei tuoi dati (alcune righe che verranno restituite, altre no?) Quindi posso caricarlo in un test di tabella temporanea con esso?
  • Prova ad aggiungere solo pos alla query di lavoro (con op hard-coded) e vedere se funziona
  • Prova ad aggiungere solo op alla query di lavoro (con pos hard-coded) e vedere se funziona
  • Marchio Ovunque tu stia elencando le tue variabili nell'ordine corretto ovunque

Per qualche ragione, continuo a pensare che potrebbe essere un problema di tipo di dati con il casting o qualcosa del genere ma non ho mai lavorato con Haskell quindi non posso davvero indovina su cos'altro potrebbe succedere.

Altre suggestioni:

  • format your query correttamente quindi è facilmente leggibile (almeno un po ', quindi non è una enorme stringa)
  • aggiornare la tua domanda per includere specifiche su come il vostro ambiente è impostata up (con versioni di software/cose e cose)
  • se pensi che il problema sia legato alla pigrizia, try forcing evaluation ...? Ma la query aveva già parti dinamiche/variabili. Dovrei supporre che avrebbero lo stesso problema, se questo fosse il caso, e la query non avrebbe funzionato per cominciare.
  • questo sarebbe sciocco, ma non ti è capitato di cambiare il DB da cui stai tirando, vero?

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

nota rapida: non ho mai toccato Haskell o SQLite prima di oggi. Sto eseguendo Haskell Platform 2014.2.0.0 con questo SQLite3 - sqlite-dll-win64-x64-201409301904.zip su Windows 7 Professional a 64 bit.

edit: questo funziona anche ... (query è una lil diverso, troppo)

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

edit: e questo funziona ...

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

così ... nelle tue domande che hai postato nella domanda ... c'è anche una differenza inaspettata ... che non ha a che fare con le variabili. È una singola citazione. Non sono sicuro se solo un refuso in copia e incolla o cosa. Io, ovviamente, non possono eseguire la query in quanto è proprio perché questa è una notevole quantità di tabelle finte e dati a venire con ...

enter image description here

edit: hah ... sono tornato in questo nuovo . Ho notato che avevi una riga in più sopra l'ultimo esempio selectPos che non stavo usando. Ho dovuto farlo in questo modo per farlo funzionare ... [[SqlValue]] o IO [[SqlValue]] come l'ultimo valore non ha funzionato per me; errori (sto solo provando le cose, non so se uno di questi valori abbia davvero senso).

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

in entrambi i casi ... Sono felice di aver scritto il mio primo programma Haskell oggi ...!

+0

Grazie per il vostro impegno. Non sono sicuro di cosa abbia inserito il carattere extra '' 'nella seconda istruzione SQL, ma non penso che sia così. Ricevo un 'SqlInt64 2' da' toSql'. Questo potrebbe essere il problema ..? –

Problemi correlati