2009-04-13 28 views
13

Làm cách nào để xác định hàm hoặc thủ tục đa tuyên bố trong việc sử dụng MySQLdb lib trong python?Tạo chức năng thông qua MySQLdb

Ví dụ:

import MySQLdb 

db = MySQLdb.connect(db='service') 

c = db.cursor() 

c.execute("""DELIMITER // 
CREATE FUNCTION trivial_func (radius float) 
    RETURNS FLOAT 

    BEGIN 
    IF radius > 1 THEN 
     RETURN 0.0; 
    ELSE 
     RETURN 1.0; 
    END IF; 
END // 

DELIMITER ;""") 

nào tạo traceback sau:

Traceback (most recent call last): 
    File "proof.py", line 21, in <module> 
    DELIMITER ;""") 
    File "build/bdist.macosx-10.5-i386/egg/MySQLdb/cursors.py", line 173, in execute 
    File "build/bdist.macosx-10.5-i386/egg/MySQLdb/connections.py", line 35, in defaulterrorhandler 
_mysql_exceptions.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 //\nCREATE FUNCTION trivial_func (radius float) \n RETURNS FLOAT\n\n ' at line 1") 

Nếu tôi sao chép SQL cùng trực tiếp vào một khách hàng mysql shell, nó hoạt động như mong đợi

Trả lời

17

Lệnh DELIMITER là một trình khách hệ vỏ của MySQL, và nó chỉ được công nhận bởi chương trình đó (và Trình duyệt truy vấn MySQL). Bạn không cần sử dụng DELIMITER nếu bạn thực thi câu lệnh SQL trực tiếp thông qua API.

Mục đích của DELIMITER là để giúp bạn tránh sự mơ hồ về việc chấm dứt câu lệnh CREATE FUNCTION, khi bản thân tuyên bố có thể chứa ký tự dấu chấm phẩy. Điều này quan trọng trong trình khách shell, theo mặc định, dấu chấm phẩy chấm dứt một câu lệnh SQL. Bạn cần đặt bộ kết thúc câu lệnh cho một số ký tự khác để gửi nội dung của hàm (hoặc trình kích hoạt hoặc thủ tục).

CREATE FUNCTION trivial_func (radius float) 
    RETURNS FLOAT 

    BEGIN 
    IF radius > 1 THEN 
     RETURN 0.0; <-- does this semicolon terminate RETURN or CREATE FUNCTION? 
    ELSE 
     RETURN 1.0; 
    END IF; 
END 

Kể từ khi API thường cho phép bạn gửi một câu lệnh SQL tại một thời điểm, không có sự mơ hồ - giao diện biết rằng bất kỳ dấu chấm phẩy bên trong cơ thể của định nghĩa hàm của bạn không chấm dứt toàn bộ tuyên bố CREATE FUNCTION. Vì vậy, không cần phải thay đổi trình kết thúc câu lệnh bằng DELIMITER.

+0

trừ khi bạn cần. ví dụ: chạy tập lệnh tạo cơ sở dữ liệu. là có bất kỳ cách nào để chỉ cần vượt qua SQL nguyên để MySql? –

+0

@BryanHunt, bạn không thể gửi tập lệnh SQL tùy ý thông qua API SQL động, bởi vì một số lệnh chỉ được khách hàng 'mysql' nhận dạng chứ không phải trình phân tích cú pháp SQL máy chủ. –

+0

Bill, cảm ơn vì đã làm rõ. B –

4

Để thêm vào câu trả lời của Bill Karwin, mẫu mã python sau có thể được sử dụng để thực thi đúng chuỗi nơi DELIMITER được sử dụng, chẳng hạn như tập lệnh tạo cơ sở dữ liệu.

import MySQLdb 

db = MySQLdb.connect(db='service') 
cursor = db.cursor() 

dbString = """DELIMITER // 
CREATE FUNCTION trivial_func (radius float) 
RETURNS FLOAT 

BEGIN 
IF radius > 1 THEN 
    RETURN 0.0; 
ELSE 
    RETURN 1.0; 
END IF; 
END // 

DELIMITER ;""" 

# Find special delimiters 
delimiters = re.compile('DELIMITER *(\S*)',re.I) 
result = delimiters.split(dbString) 

# Insert default delimiter and separate delimiters and sql 
result.insert(0,';') 
delimiter = result[0::2] 
section = result[1::2] 

# Split queries on delimiters and execute 
for i in range(len(delimiter)): 
    queries = section[i].split(delimiter[i]) 
    for query in queries: 
     if not query.strip(): 
      continue 
     cursor.execute(query) 

Điều này sẽ thực hiện một dấu phân tách tại một thời điểm, thay đổi dấu phân cách khi cần.

+0

Điều này đã làm cho tôi. Tôi cũng cần thêm 'query = query.replace ('%', '%%')', để thoát% ký tự trong tệp .sql của tôi. – Lundy

0

Dựa trên nhận xét từ @AaronS. Kịch bản lệnh này sẽ đọc trong một tệp SQL, phân tách nó thành các lệnh SQL rời rạc và đối phó với bất kỳ dấu phân tách nào mà nó tìm thấy.

queries = [] 
    delimiter = ';' 
    query = '' 
    with open('import.sql', 'r') as f: 
     for line in f.readlines(): 
      line = line.strip() 
      if line.startswith('DELIMITER'): 
       delimiter = line[10:] 
      else: 
       query += line+'\n' 
       if line.endswith(delimiter): 
        # Get rid of the delimiter, remove any blank lines and add this query to our list 
        queries.append(query.strip().strip(delimiter)) 
        query = '' 

    for query in queries: 
     if not query.strip(): 
      continue 
     cursor.execute(query) 
    cursor.close() 
Các vấn đề liên quan