2014-09-16 6 views
5

ich mit dem folgenden Code in Python gerade arbeitete, eine PostgreSQL-Abfrage mit subprocess Aufruf:Python Syntax: Subprocess Aufruf PostgreSQL Query "Fehler: Nur ASCII-Zeichen erlaubt"

import subprocess 
claimer_name = 'a_name' 
startdate = '2014-04-01' 
enddate = '2018-04-01' 

data = subprocess.check_output(['/usr/bin/psql -U user_name "SELECT c.asset_id, c.video_id, 
c.claim_id, c.claim_date FROM db.claim c JOIN db.claim_history h ON c.claim_id = h.claim_id JOIN 
db.users_email e ON LOWER(e.email) = LOWER(h.email) JOIN m.auth_user u ON e.user_id = u.id WHERE 
h.list_order = 1 AND c.claim_origin = ‘Descriptive Search’ AND c.claim_date >= \"%s\" AND  
c.claim_date < \"%s\" AND concat(u.first_name, concat(chr(32), 
u.last_name)) = \"%s\""' % (startdate, enddate, claimer_name)], shell=True) 

Wie kann ich die einzigen entweichen kann zitiert um 'Deskriptive Suche'? Das Ausführen dieses Code as-ist der Fehler gibt Only ASCII characters are allowed in an identifier.

ich versucht habe:

  1. [''Descriptive Search'']
  2. [\'Descriptive Search\']
  3. [""Descriptive Search""]
  4. [concat('Descriptive', concat(chr(32), 'Search'))]

und Zuweisen einer Variable: i = 'Descriptive Search', und dann c.claim_origin = \"%s\".

Jedoch ergeben diese Versuche die gleichen ASCII characters Fehler. String-Formatierung unter Verwendung arbeitet für meine andere Variablen in Ordnung (startdate, enddate, claimer_name) und ich bin ratlos, warum es nicht funktioniert, für die Zeichenfolge ‚Beschreibende Search‘.

Mit PostgreSQL 9.3.

Jede Hilfe oder Punkte in die richtige Richtung wäre toll; Vielen Dank!

+5

Egad. Es gibt so viele mögliche Fehlerquellen. Bitte tu dir selbst einen Gefallen und verwende eine PostgreSQL-Treiberbibliothek für Python, etwa [Psycopg2] (https://wiki.postgresql.org/wiki/Psycopg2_Tutorial). Durch die Shell zu gehen, muss dir Kopfschmerzen bereiten, wenn es nicht schon passiert ist. Und während du dabei bist, lies über kleine [Bobby Tables] (http://bobby-tables.com/). – Amadan

+0

Danke, @Amadan Großartiger Vorschlag - ich werde einen Blick darauf werfen. Danke auch für den Link. – Daniel

+1

+1 für ** zeigt Ihren Code ** und den ** genauen Fehlertext **. Gut für dich. Bitte fügen Sie in Zukunft auch die PostgreSQL-Version hinzu, aber +1 gute Frage. –

Antwort

6

Es gibt so viele Dinge falsch mit diesem.

  • Sie sollten psycopg2 eher verwenden als zu versuchen, zu psql zu berappen, um die Datenbank zu sprechen;

  • Da Sie keine richtige Datenbankbindung verwenden, können Sie Platzierungsparameter (vorbereitete Anweisungen) nicht richtig verwenden. Daher müssen Sie selbst mit Literalen umgehen, um Risiken und Fehler zu vermeiden.

  • Wenn Sie Befehle über subprocess aufrufen, sollten Sie die Shell möglichst nicht verwenden. Es ist ein weiterer Punkt möglichen Versagens, und in diesem Fall völlig unnötig;

  • Lange Zeichenketten sollten in der Regel """ in Python zitiert werden, um die Notwendigkeit zu vermeiden verschachtelt " s;

  • Der Ausdruck concat(u.first_name, concat(chr(32), u.last_name)) ist unnötig verzerrt. Schreiben Sie einfach u.first_name || ' ' || u.last_name oder format('%s %s', u.first_name, u.last_name);

  • Sie "double quotes" mit Literalen zu zitieren in Sie ersetzen, die ungültige SQL ist. Sie werden gemäß der Dokumentation als Bezeichner behandelt. So c.claim_date < \"%s\" wird mit einem Fehler wie no column "2014-04-01";

  • Sie verwenden echte einfache Anführungszeichen, keine Apostrophe, wenn Sie ‘Descriptive Search‘ angeben. Bei einer Vermutung haben Sie den Code in einem Textverarbeitungsprogramm bearbeitet, nicht mit einem Texteditor des Programmierers. Sie wollen Apostrophe, 'Descriptive Search', wenn in SQL-Angabe.

Weil Sie Apostrophe (U + 2018) statt Apostrophe (U + 0027) verwendet Descriptive Search die Zeichenkette zu zitieren, PostgreSQL erkannte sie nicht als wörtliche und versuchte, es als eine Kennung zu analysieren . ist jedoch kein zulässiges Zeichen in einem nicht angegebenen Bezeichner. Daher hat er den angezeigten Fehler gemeldet.

Siehe the documentation on identifiers and literals.

Hier ist, was Sie getan haben sollten:

import psycopg2 
import datetime 
claimer_name = 'a_name' 
startdate = datetime.date(2014, 1, 1) 
enddate = datetime.date(2018, 1, 1) 

conn = psycopg2.connect("user=user_name") 
curs = conn.cursor() 
curs.execute(""" 
    SELECT 
     c.asset_id, 
     c.video_id, 
     c.claim_id, 
     c.claim_date 
    FROM db.claim c 
     JOIN db.claim_history h ON c.claim_id = h.claim_id 
     JOIN db.users_email e ON LOWER(e.email) = LOWER(h.email) 
     JOIN m.auth_user u ON e.user_id = u.id 
    WHERE h.list_order = 1 
     AND c.claim_origin = 'Descriptive Search' 
     AND c.claim_date >= %s 
     AND c.claim_date < %s 
     AND u.first_name || ' ' || u.last_name = %s 
    """, (startdate, enddate, claimer_name) 
) 
results = curs.fetchall() 

Achten Sie besonders auf die Tatsache, dass ich nicht Verwendung Pythons haben über % String-Formatierung Operator. Die Einträge %s sind Platzierungsparameter, die durch psycopg2 richtig ersetzt werden. siehe passing parameters to SQL queries.

+0

Danke für all das, @CraigRinger! Es macht alles Sinn und ist sehr hilfreich. – Daniel