2014-12-19 14 views
5

Ich benutze PostgreSQL 9.4 und den tollen JSONB-Feldtyp. Ich versuche, ein Feld in einem Dokument abzufragen. Die folgenden Arbeiten in der psql CLIPostgreSQL jsonb, `?` Und JDBC

SELECT id FROM program WHERE document -> 'dept' ? 'CS' 

Wenn ich versuche, die gleiche Abfrage über meine Scala App zu laufen, erhalte ich die folgenden Fehler. Ich verwende Play-Framework und Anorm, so dass die Abfrage sieht wie folgt aus

SQL(s"SELECT id FROM program WHERE document -> 'dept' ? {dept}") 
.on('dept -> "CS") 
.... 

SQLException: : No value specified for parameter 5. (SimpleParameterList.java:223)

(in meinem eigentlichen Abfragen mehr Parameter sind)

Ich kann durch Gießen meine Parameter dieses Problem umgehen zu geben jsonb und den Operator @> verwenden, um die Eindämmung zu überprüfen.

SQL(s"SELECT id FROM program WHERE document -> 'dept' @> {dept}::jsonb") 
.on('dept -> "CS") 
.... 

Ich bin nicht so scharf auf die Arbeit herum. Ich weiß nicht, ob es Leistungseinbußen für die Besetzung gibt, aber es ist ein zusätzliches Tippen und nicht offensichtlich.

Gibt es noch etwas, das ich tun kann?

+0

Entweder fügen Sie den Code nicht richtig ein oder Sie haben Syntaxfehler: 'SQL (s" SELECT ID FROM Programm WHERE Dokument -> 'Abt'? {Abt.} .on ('Abt. -> "CS") ' → 'on' muss auf' SQL (...) 'angewendet werden, nicht Teil der Anweisungszeichenfolge sein, da es dort zu sein scheint =' SQL ("..."). On (...) '. Hinweis Diese Stringinterpolation ist nutzlos – cchantep

+0

Ich habe den ganzen Aufruf nicht in SQL eingefügt, weil das für meine Frage irrelevant ist. Es gibt einen Aufruf zum 'apply' nach dem 'on' – Jason

+0

Ich hätte besser einen Code einfügen können, der hat gültige Syntax, wenn Sie eine passende Antwort wünschen – cchantep

Antwort

7

Als Workaround zur Vermeidung der? Operator, könnten Sie eine new operator genau das gleiche tun.

Dies ist der Code des ursprünglichen Betreibers:

CREATE OPERATOR ?(
    PROCEDURE = jsonb_exists, 
    LEFTARG = jsonb, 
    RIGHTARG = text, 
    RESTRICT = contsel, 
    JOIN = contjoinsel); 

SELECT '{"a":1, "b":2}'::jsonb ? 'b'; -- true 

einen anderen Namen verwenden, ohne Konflikte, wie # - # und erstellen Sie einen neuen:

CREATE OPERATOR #-#(
    PROCEDURE = jsonb_exists, 
    LEFTARG = jsonb, 
    RIGHTARG = text, 
    RESTRICT = contsel, 
    JOIN = contjoinsel); 

SELECT '{"a":1, "b":2}'::jsonb #-# 'b'; -- true 

Mit diesen neuen Betreibern in deinem Code und es sollte funktionieren.

Überprüfen Sie pgAdmin -> pg_catalog -> Operatoren für alle Operatoren, die ein? im Namen.

4

In JDBC (und Standard-SQL) ist das Fragezeichen als Parameter-Platzhalter reserviert. Andere Verwendungen sind nicht erlaubt.

Siehe Does the JDBC spec prevent '?' from being used as an operator (outside of quotes)? und die discussion on jdbc-spec-discuss.

Der aktuelle PostgreSQL-JDBC-Treiber transformiert alle Vorkommen (außerhalb von Text oder Kommentaren) eines Fragezeichens in einen PostgreSQL-spezifischen Parameter-Platzhalter. Ich bin mir nicht sicher, ob das PostgreSQL-JDBC-Projekt etwas getan hat (wie das Einführen eines Escape, wie in den obigen Links beschrieben), um dies noch zu lösen. Ein kurzer Blick auf den Code und die Dokumentation deutet darauf hin, dass sie es nicht taten, aber ich habe nicht zu tief gegraben.

Nachtrag: Wie in the answer by bobmarksie gezeigt, aktuelle Versionen des PostgreSQL-JDBC-Treiber unterstützt nun das Fragezeichen zu entkommen, indem sie es verdoppelt (dh verwenden ?? statt ?).

+0

Siehe meine Antwort (http: // stac koverflow.com/a/35359516/1692179) - Escape ist verfügbar und beschrieben (Stand Februar 2016) in der PosgreSQL-Dokumentation. – bobmarksie

+0

@bobmarksie Danke, ich habe eine Notiz von diesem hinzugefügt. –

2

Ich hatte das gleiche Problem vor ein paar Tagen und nach einigen Untersuchungen fand ich dies.

https://jdbc.postgresql.org/documentation/head/statement.html

In JDBC, the question mark (?) is the placeholder for the positional parameters of a PreparedStatement. There are, however, a number of PostgreSQL operators that contain a question mark. To keep such question marks in a SQL statement from being interpreted as positional parameters, use two question marks (??) as escape sequence. You can also use this escape sequence in a Statement, but that is not required. Specifically only in a Statement a single (?) can be used as an operator.

Mit 2 Fragezeichen schien gut zu funktionieren für mich - ich folgende Treiber wurde mit (dargestellt Maven Abhängigkeit verwendet wird) ...

<dependency> 
     <groupId>org.postgresql</groupId> 
     <artifactId>postgresql</artifactId> 
     <version>9.4-1201-jdbc41</version> 
    </dependency> 

... und MyBatis für die Erstellung der SQL-Abfragen und es schien gut zu funktionieren. Scheint einfacher/sauberer als das Erstellen eines PostgreSQL-Operators.

SQL ging von z.B.

select * from user_docs where userTags ?| array['sport','property'] 

... bis ...

select * from user_docs where userTags ??| array['sport','property'] 

Hoffentlich funktioniert dies mit Ihrem Szenario!

Verwandte Themen