2013-05-21 9 views
6

Sto utilizzando Java 1.7 e JDBC 4 e Postgres. Sto cercando di utilizzare un PreparedStatement con un array per riempire una clausola SQL in. Ma l'SQL generato sembra avere "{" e "}" in esso. Ecco il codice:Postgres SQL in clausola e setArray()

PreparedStatement ptmt = 
     connection.prepareStatement("select * from foo where id in (?)"); 
String[] values = new String[3]; 
values[0] = "a"; 
values[1] = "b"; 
values[2] = "c"; 
ptmt.setArray(1, connection.createArrayOf("text", values)); 

Lo SQL risultante è simile a questo:

select * from foo where id in ('{"a","b","c"}') 

Il che, non può funzionare. Questo è come dovrebbe apparire:

select * from foo where id in ("a","b","c") 

o

select * from foo where id in ('a','b','c') 

Che cosa mi manca qui?

risposta

4

Quando il campo del database è di tipo array, è possibile utilizzare PreparedStatement.setArray() per inviare una matrice alla query. Ma, nel tuo caso, non è veramente una matrice, piuttosto è una variabile no di argomenti, e non puoi farlo. Ad esempio

PreparedStatement ptmt = connection.prepareStatement("select * from foo where id in (?)"); 

può richiedere un solo parametro. Se si vuole 3 parametri da passare, quello che dovete fare

PreparedStatement ptmt = connection.prepareStatement("select * from foo where id in (?, ?, ?)"); 

E fate ptmt.setString(n, "String") tre volte.

Se il no di argomenti non è costante, quindi costruisci la query dinamicamente, anche se perdi l'efficienza.

1

Considererei questo un problema di PgJDBC. E 'in realtà dovrebbe essere scrivendo un costruttore di array o un array letterale con un cast esplicito, ad esempio:

select * from foo where id in (ARRAY['a','b','c']) 

o

select * from foo where id in ('{"a","b","c"}'::text[]) 

Per risolvere il problema si dovrebbe essere in grado di scrivere:

"select * from foo where id in ((?)::text[])" 

.. anche se non l'ho provato per verificarlo.

Considerare di scrivere come test di unità per PgJDBC e inviarlo al progetto PgJDBC tramite github come segnalazione di errore. Guarda come funzionano i test unitari esistenti e aggiungine un altro. È tutto molto semplice JUnit.

+0

Speravo davvero di poter fare questo lavoro. Ma quando provo: selezionare * da teamdata dove teamdata.teamid in ('{"t11", "t54"}' :: testo []), ottengo "Nessun operatore corrisponde al nome e al tipo di argomento specificato. Potrebbe essere necessario aggiungere cast di tipi espliciti. " Nel mio caso, la colonna id è un varchar. Mi dispiace di aver cambiato la query, ma è la query effettiva che sto usando. –

+0

@DooDah Assicurati di eseguirlo a mano con 'psql' prima, elabora la query ei tipi corretti. Quindi adattarsi a PgJDBC. ':: text []' è solo un cast; puoi cast in modo simile a 'varchar []'. Sebbene in pratica Pg li tratterà come lo stesso tipo di dati, quindi non sono sicuro che questo sia il problema. –

+0

Gotcha. Ci proveremo. Sto ancora imparando alcuni dei sublimi di Postgres. Grazie per il consiglio. Cercherò anche di inviarlo come test unitario per il driver PgJDBC. –

2

PostgreSQL ha un paio di array capabilities che può gestire questa situazione.

La prima è la funzione più inutile, disponibile da 8.4. Un po 'pesante, ma efficace.

select * from foo where id in (SELECT * FROM unnest(?)); 

Avanti è l'operatore di intersezione della matrice.

select * from foo where ARRAY[id] && ?; 

converte il valore della colonna in una matrice con un singolo elemento e quindi verifica la presenza di intersezione con la matrice che si configura come un parametro.

Come meglio posso dire, questi sono funzionalmente equivalenti, ma non ho controllato quale potrebbe essere più performante.

+0

Un possibile svantaggio di 'dove id in (SELECT * FROM unnest (?))' È che causa il fallimento di 'getParameterMetaData' con un'eccezione:" ERRORE: impossibile determinare il tipo polimorfico perché l'input ha tipo "sconosciuto" ". L'altro approccio suggerito, 'dove ARRAY [id] &&?', Non ha questo problema. –