2 Stimmen

Warum schlägt das Erstellen einer Tabelle mit Python fehl, während es mit Cli gelingt?

Hier ist eine Frage für Sie mysql + python Leute da draußen.

Warum funktioniert diese mysql sql Befehlsfolge nicht, wenn ich es durch Python ausführen, aber es tut, wenn ich es über die mysql CLI ausführen?

#!/usr/bin/env python

import oursql as mysql
import sys, traceback as tb
import logging

# some other stuff...

class MySqlAuth(object):
    def __init__(self, host = None, db = None, user = None, pw = None, port = None):
        self.host = 'localhost' if host is None else host
        self.db = 'mysql' if db is None else db
        self.user = 'root' if user is None else user
        self.pw = pw
        self.port = 3306 if port is None else port

    @property
    def cursor(self):
        auth_dict = dict()
        auth_dict['host'] = self.host
        auth_dict['user'] = self.user
        auth_dict['passwd'] = self.pw
        auth_dict['db'] = self.db
        auth_dict['port'] = self.port
        conn = mysql.connect(**auth_dict)
        cur = conn.cursor(mysql.DictCursor)
        return cur

def ExecuteNonQuery(auth, sql):
    try:
        cur = auth.cursor
        log.debug('SQL:  ' + sql)
        cur.execute(sql)
        cur.connection.commit()
        return cur.rowcount
    except:
        cur.connection.rollback()
        log.error("".join(tb.format_exception(*sys.exc_info())))
    finally:
        cur.connection.close()

def CreateTable(auth, table_name):

    CREATE_TABLE = """
    CREATE TABLE IF NOT EXISTS %(table)s ( 
              uid VARCHAR(120) PRIMARY KEY
            , k VARCHAR(1000) NOT NULL
            , v BLOB
            , create_ts TIMESTAMP NOT NULL
            , mod_ts TIMESTAMP NOT NULL
            , UNIQUE(k)
            , INDEX USING BTREE(k)
            , INDEX USING BTREE(mod_ts) );
    """
    ExecuteNonQuery(auth, CREATE_TABLE % { 'table' : table_name })

    CREATE_BEFORE_INSERT_TRIGGER = """
    DELIMITER //
    CREATE TRIGGER %(table)s_before_insert BEFORE INSERT ON %(table)s
    FOR EACH ROW
    BEGIN
        SET NEW.create_ts = NOW();
        SET NEW.mod_ts = NOW();
        SET NEW.uid = UUID();
    END;// DELIMIETER ;
    """
    ExecuteNonQuery(auth, CREATE_BEFORE_INSERT_TRIGGER % { 'table' : table_name })

    CREATE_BEFORE_INSERT_TRIGGER = """
    DELIMITER //
    CREATE TRIGGER %(table)s_before_update BEFORE UPDATE ON %(table)s
    FOR EACH ROW
    BEGIN
        SET NEW.mod_ts = NOW();
    END;// DELIMIETER ;
    """
    ExecuteNonQuery(auth, CREATE_BEFORE_UPDATE_TRIGGER % { 'table' : table_name })

# some other stuff

Die Fehlermeldung, die ich erhalte, wenn ich das Python-Programm ausführe, lautet wie folgt:

2012-01-15 11:53:00,138 [4214 MainThread mynosql.py] DEBUG SQL:  
    DELIMITER //
    CREATE TRIGGER nosql_before_insert BEFORE INSERT ON nosql
    FOR EACH ROW
    BEGIN
        SET NEW.create_ts = NOW();
        SET NEW.mod_ts = NOW();
        SET NEW.uid = UUID();
    END;// DELIMIETER ;

2012-01-15 11:53:00,140 [4214 MainThread mynosql.py] ERROR Traceback (most recent call last):
  File "./mynosql.py", line 39, in ExecuteNonQuery
    cur.execute(sql)
  File "cursor.pyx", line 120, in oursql.Cursor.execute (oursqlx/oursql.c:15856)
  File "cursor.pyx", line 111, in oursql.execute (oursqlx/oursql.c:15728)
  File "statement.pyx", line 157, in oursql._Statement.prepare (oursqlx/oursql.c:7750)
  File "statement.pyx", line 127, in oursql._Statement._raise_error (oursqlx/oursql.c:7360)
ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DELIMITER //\n    CREATE TRIGGER nosql_before_insert BEFORE INSERT ON nosql\n    F' at line 1", None)

2voto

Tudor Constantin Punkte 25366

Obwohl der Fehler, den Sie erhalten, anscheinend von der ersten DELIMITER // Aussage haben Sie einen Tippfehler bei der letzten Erwähnung von DELIMITER - Sie haben es geschrieben DELIMIETER ; - Versuchen Sie, dies zu ändern und sehen Sie, ob Ihr Problem dadurch gelöst wird.

Update

Sie haben 2 Tippfehler für dasselbe DELIMIETER ; - Ich glaube, der Fehler tritt auf, kurz nachdem der Interpreter den ersten gefunden hat:

 DELIMITER //
    CREATE TRIGGER %(table)s_before_insert BEFORE INSERT ON %(table)s
    FOR EACH ROW
    BEGIN
        SET NEW.create_ts = NOW();
        SET NEW.mod_ts = NOW();
        SET NEW.uid = UUID();
    END;// DELIMIETER ; <-- this one is wrong, it should be DELIMITER

2voto

Sie können Abfragen nur einzeln an mysql übergeben; es liegt am Client, sicherzustellen, dass der Abfragetext nur eine einzige gültige Anweisung ist.

Der MySQL-Client tut dies, indem er die eingegebene Abfrage tokenisiert und nach Anweisungstrennzeichen sucht. Im Fall einer Trigger-Definition funktioniert das nicht, weil die Definition Semikolons (das Standard-Anweisungstrennzeichen) enthalten kann, und deshalb müssen Sie dem Client sagen, dass er Anweisungen auf andere Weise trennen soll, indem Sie die DELIMITER Befehl.

Die MySQLdb (und andere) Python-Api's erfordern keine solche Anweisungstrennung; der Programmierer ist verpflichtet, Anweisungen auf einmal an query .

Versuchen Sie, die DELIMITER Anweisungen ganz aus Ihren Abfragen zu entfernen (wenn sie über die Python-Api übergeben werden).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X