Spec-Zone.ru › MySQL Connectors 1.0

9.3 Выполнение нескольких операторов

Connector/Python может выполнять как отдельный оператор, так и несколько операторов. Этот раздел описывает поддержку нескольких операторов и соответствующих разделителей.

Примечание

До Connector/Python 9.2.0 для выполнения нескольких операторов требовался параметр multi. Этот параметр давал несогласованные результаты и был удален в версии 9.2.0.

Пример базового использования:

sql_operation = """
SET @a=1, @b='2024-02-01';
SELECT @a, LENGTH('hello'), @b;
SELECT @@version;
"""

with cnx.cursor() as cur:
    # Execute SQL; it can contain one or multiple statements
    cur.execute(sql_operation)

    # Fetch result set, see other examples for additional information

Также поддерживаются пользовательские разделители (с Connector/Python 9.2.0), включая сценарии, которые включают разделители и несколько операторов. Примером служит файл образца базы данных Sakila sakila-schema.sql:

with cnx.cursor() as cur:
    with open(
        os.path.join("/path/to/files", "sakila-schema.sql"), encoding="utf-8"
    ) as code:
        cur.execute(code.read())

    # Fetch result set, see other examples for additional information

Сопоставление результатов нескольких операторов

Необязательный параметр map_results (по умолчанию False) устанавливает соответствие между каждым оператором и его набором результатов.

sql_operation = ...

with cnx.cursor() as cur:
    # Execute SQL; it can contain one or multiple statements
    cur.execute(sql_operation, map_results=True)

    # Fetch result set, see other examples for additional information

Многострочный оператор или сценарий MySQL состоит из одного или нескольких отдельных операторов. Существуют два типа отдельных операторов:

  • Simple: такие операторы не содержат объявления тела BEGIN-END.

  • Compound: такие операторы содержат объявление тела BEGIN-END, например:

    CREATE PROCEDURE dorepeat(p1 INT)
    BEGIN
        SET @x = 0;
        REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
    END;
    

Connector/Python использует пользовательские разделители для разделения многострочного оператора на отдельные операторы при обработке составных отдельных операторов, аналогично тому, как это делает клиент MySQL. Для простых отдельных операторов пользовательские разделители необязательны, но могут быть использованы.

Если при работе с составными отдельными операторами разделители не используются, сопоставление оператор-результат может привести к непредсказуемым результатам. Если сопоставление отключено, составные отдельные операторы могут или не могут использовать разделители.

Пример использования смешанных простых и составных операторов:

DROP PROCEDURE IF EXISTS dorepeat;

DELIMITER //

CREATE PROCEDURE dorepeat(p1 INT)
BEGIN
    SET @x = 0;
    REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
END//

DELIMITER ;

SELECT @x;

Connector/Python выполняет предварительную обработку для обработки разделителей, что может повлиять на производительность при работе с большими сценариями. Также существуют ограничения при работе с пользовательскими разделителями:

  • Unsupported delimiters: следующие символы не поддерживаются соединителем в операторах DELIMITER:

    double quote: "
    single quote: '
    hash: #
    slash plus star: /*
    star plus slash: */
    

    Избегайте использования этих символов в качестве разделителей.

  • DELIMITER: слово DELIMITER и любые его комбинации в нижнем и верхнем регистре, такие как delimiter, DeLiMiter и т. д., считаются ключевыми словами соединителя. Пользователи должны указывать их в кавычках при использовании в многострочных операторах для целей, отличных от объявления фактического разделителя оператора; таких как имена таблиц, столбцов, переменных, в комментариях и т. д. Пример:

    CREATE TABLE `delimiter` (begin INT, end INT); -- I am a `DELimiTer` comment
    

Получение наборов результатов

Базовое использование (сопоставление отключено):

sql_operation = """
SET @a=1, @b='2024-02-01';
SELECT @a, LENGTH('hello'), @b;
SELECT @@version;
"""

with cnx.cursor() as cur:
    # Execute a statement; it can be single or multi.
    cur.execute(sql_operation)

    # Fetch result sets and do something with them
    result_set = cur.fetchall()

    # do something with result set
    ...

    while cur.nextset():
        result_set = cur.fetchall()
        # do something with result set
        ...

Выполнение многострочного оператора генерирует один или несколько наборов результатов, другими словами, набор наборов результатов. Первый набор результатов доступен после завершения выполнения. Вы можете получить (с помощью fetchall()) текущий набор результатов и обработать его или нет, и перейти к следующему.

В качестве альтернативы используйте метод API курсора nextset() для перемещения по наборам результатов. Этот метод позволяет курсору перейти к следующему доступному набору, отбрасывая любые оставшиеся строки из текущего набора.

При выполнении, генерирующем только один набор результатов, что происходит, когда ваш сценарий содержит только один оператор, вызов nextset() можно опустить, так как ожидается не более одного набора результатов. Вызов вернет None, так как больше наборов нет.

Использование сопоставления оператор-набор результатов:

sql_operation = ...

with cnx.cursor() as cur:
    # Execute a statement; it can be single or multi.
    cur.execute(sql_operation, map_results=True)

    # Fetch result sets and do something with them.
    # statement 1 is `SET @a=1, @b='2025-01-01'`,
    # result set from statement 1 is `[]` - aka, an empty set.
    result_set, statement = cur.fetchall(), cur.statement
    # do something with result set
    ...

    # 1st call to `nextset()` will load the result set from statement 2,
    # statement 2 is `SELECT @a, LENGTH('hello'), @b`,
    # result set from statement 2 is `[(1, 5, '2025-01-01')]`.
    #
    # 2nd call to `nextset()` will load the result set from statement 3,
    # statement 3 is `SELECT @@version`,
    # result set from statement 3 is `[('9.2.0',)]`.
    #
    # 3rd call to `nextset()` will return `None` as there are no more sets,
    # leading to the end of the consumption process of result sets.
    while cur.nextset():
        result_set, statement = cur.fetchall(), cur.statement
        # do something with result set
        ...

При отключенном сопоставлении (map_results=False), все наборы результатов связаны с одним оператором, который предоставляется при вызове execute(). Другими словами, свойство statement не меняется во время потребления наборов результатов, что отличается от случая с включенным сопоставлением, когда свойство statement возвращает оператор, вызвавший текущий набор результатов. Следовательно, значение оператора изменяется соответственно при прохождении по наборам результатов.

Сокращенный способ получения наборов результатов

Доступно сокращение команд API, связанных с извлечением, для получения наборов результатов. Этот пример эквивалентен ранее представленному рабочему процессу.

sql_operation = '''
SET @a=1, @b='2025-01-01';
SELECT @a, LENGTH('hello'), @b;
SELECT @@version;
'''
with cnx.cursor() as cur:
    cur.execute(sql_operation, map_results=True)
    for statement, result_set in cur.fetchsets():
        # do something with result set

Метод fetchsets() возвращает генератор, где каждый элемент — это кортеж из 2 элементов; первый элемент — оператор, вызвавший набор результатов, а второй — сам набор результатов. Если сопоставление отключено, оператор не изменится при прохождении по наборам результатов.

Если оператор не нужен, рассмотрите этот более простой вариант:

sql_operation = ...
with cnx.cursor() as cur:
    cur.execute(...)
    for _, result_set in cur.fetchsets():
        # do something with result set

© 2025 Oracle
Licensed under the GPLv2 License.
https://docs.oracle.com/cd/E17952_01/connector-python-en/connector-python-multi.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API