2013-05-21 11 views
6

Używam Java 1.7 i JDBC 4 oraz Postgres. Próbuję użyć PreparedStatement z tablicą, aby wypełnić klauzulę SQL in. Ale wygenerowany SQL wydaje się mieć w sobie "{" i "}". Oto kod:PostgreSQL w klauzuli i 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)); 

Powstały SQL wygląda następująco:

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

Który, nie może pracować. Jest to, jak powinna wyglądać:

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

lub

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

Co ja tu brakuje?

Odpowiedz

4

Gdy twoje pole bazy danych jest typu array, możesz użyć PreparedStatement.setArray(), aby wysłać tablicę do zapytania. Ale w twoim przypadku nie jest to tablica, a raczej zmienna liczba argumentów i nie możesz tego zrobić. tj.

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

może przyjmować tylko jeden parametr. Jeśli chcesz 3 parametry mają być przekazywane, trzeba zrobić

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

A czy ptmt.setString(n, "String") trzykrotnie.

Jeśli twoja liczba argumentów nie jest stała, skonstruuj zapytanie dynamicznie, chociaż stracisz wydajność.

1

Uważam, że jest to problem PgJDBC. Powinien on być naprawdę pisania konstruktora Array lub tablicę dosłowne z wyraźną obsadzie, np:

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

lub

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

Jako obejście powinieneś być w stanie napisać:

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

.. chociaż nie testowałem tego, aby to zweryfikować.

Proszę rozważyć zapisanie tego jako testu jednostkowego dla PgJDBC i przesłanie go do projektu PgJDBC przez github jako raport o błędzie. Zobacz, jak działają istniejące testy jednostkowe i po prostu dodaj kolejne. To wszystko jest bardzo proste JUnit.

+0

Naprawdę miałem nadzieję, że będę mógł wykonać tę pracę. Ale kiedy próbuję: wybierz * z danych zespołu, gdzie teamdata.teamid w ("{" t11 "," t54 "}" :: text []), otrzymuję "Żaden operator nie odpowiada podanej nazwie i typowi argumentu. Być może będziesz musiał dodać wyraźne odlewy typów. " W moim przypadku kolumna id jest varcharem. Przepraszam, że zmieniłem zapytanie, ale to jest faktyczne zapytanie, którego używam. –

+0

@DooDah Upewnij się, że możesz uruchomić go ręcznie za pomocą 'psql' najpierw, opracuj poprawne zapytanie i typy. Następnie dostosuj się do PgJDBC. ':: text []' jest po prostu obsadą; podobnie można rzucić na 'varchar []'. Chociaż w praktyce Pg traktuje je jako ten sam typ danych, więc nie jestem pewien, czy to jest problem. –

+0

Gotcha. Spróbuję. Nadal uczę się niektórych podlantów z PostgreSu. Dzięki za wskazówkę. Spróbuję również przesłać to jako test jednostkowy dla sterownika PgJDBC. –

2

PostgreSQL ma kilka array capabilities, które poradzą sobie z tą sytuacją.

Najpierw jest to funkcja nieprawdziwa, dostępna od 8.4. Trochę cludgy, ale skuteczne.

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

Następny jest operator przecięcia macierzy.

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

Przekształca wartość kolumny do tablicy z jednego elementu, a następnie sprawdza przecięcia z tablicy, które skonfigurowano jako parametr.

Najlepiej jak mogę stwierdzić, są one równoważne funkcjonalnie, ale nie sprawdziłem, które mogą być bardziej wydajne.

+0

Możliwym minusem dla 'id id in (SELECT * FROM unnest (?))' Jest to, że 'getParameterMetaData' kończy się niepowodzeniem z wyjątkiem:" ERROR: nie można określić typu polimorficznego, ponieważ wejście ma typ "unknown" ". Inne podejście, które zasugerowałeś, "where ARRAY [id] &&?", Nie ma tego problemu. –