Skip to content

Выполнение запросов в MSSQL

Warning

Методы ниже загружают все строки из БД в память драйвера Spark, и только потом конвертируют их в DataFrame.

НЕ используйте их для чтения больших объемов данных. Вместо этого используйте DBReader или MSSQL.sql.

Как использовать

Существует 2 способа выполнения запросов в MSSQL

Использование MSSQL.fetch

Используйте этот метод для выполнения запросов SELECT, которые возвращают небольшое количество строк, например, для чтения конфигурации MSSQL или данных из справочной таблицы. Метод возвращает Spark DataFrame.

Метод принимает MSSQL.FetchOptions.

Соединение, открытое с использованием этого метода, следует затем закрыть с помощью connection.close() или with connection:.

Warning

Пожалуйста, учитывайте типы данных MSSQL.

Поддержка синтаксиса в MSSQL.fetch

Этот метод поддерживает любой синтаксис запросов, поддерживаемый MSSQL, например:

  • ✅︎ SELECT ... FROM ...
  • ✅︎ WITH alias AS (...) SELECT ...
  • ✅︎ SELECT func(arg1, arg2) FROM DUAL - вызов функции
  • SET ...; SELECT ...; - несколько запросов не поддерживаются

Примеры с MSSQL.fetch

```python
    from onetl.connection import MSSQL

    mssql = MSSQL(...)

    df = mssql.fetch(
        "SELECT value FROM some.reference_table WHERE key = 'some_constant'",
        options=MSSQL.FetchOptions(queryTimeout=10),
    )
    mssql.close()
    value = df.collect()[0][0]  # получение значения из первой строки и первого столбца
```

Использование MSSQL.execute

Используйте этот метод для выполнения операций DDL и DML. Каждый вызов метода выполняет операцию в отдельной транзакции и затем фиксирует ее.

Метод принимает MSSQL.ExecuteOptions.

Соединение, открытое с использованием этого метода, следует затем закрыть с помощью connection.close() или with connection:.

Поддержка синтаксиса в MSSQL.execute

Этот метод позволяет использовать любой синтаксис запросов, поддерживаемый MSSQL, например:

  • ✅︎ CREATE TABLE ..., CREATE VIEW ...
  • ✅︎ ALTER ...
  • ✅︎ INSERT INTO ... AS SELECT ...
  • ✅︎ DROP TABLE ..., DROP VIEW ..., TRUNCATE TABLE и т.д.
  • ✅︎ EXEC procedure(arg1, arg2) ... или {call procedure(arg1, arg2)} - специальный синтаксис для вызова процедуры
  • ✅︎ DECLARE ... BEGIN ... END - выполнение PL/SQL-выражения
  • ✅︎ другие запросы, не упомянутые здесь
  • SET ...; SELECT ...; - несколько запросов не поддерживаются

Примеры с MSSQL.execute

```python
    from onetl.connection import MSSQL

    mssql = MSSQL(...)

    mssql.execute("DROP TABLE schema.table")
    mssql.execute(
        """
        CREATE TABLE schema.table (
            id bigint GENERATED ALWAYS AS IDENTITY,
            key VARCHAR2(4000),
            value NUMBER
        )
        """,
        options=MSSQL.ExecuteOptions(queryTimeout=10),
    )
```

Опции

onetl.connection.db_connection.mssql.options.MSSQLFetchOptions

Bases: JDBCFetchOptions

Source code in onetl/connection/db_connection/mssql/options.py
27
28
class MSSQLFetchOptions(JDBCFetchOptions):
    __doc__ = JDBCFetchOptions.__doc__.replace("SomeDB", "MSSQL")  # type: ignore[assignment, union-attr]

fetchsize = None class-attribute instance-attribute

How many rows to fetch per round trip.

Tuning this option can influence performance of reading.

.. warning:: Default value depends on driver. For example, Oracle has default fetchsize=10.

query_timeout = Field(default=None, alias='queryTimeout') class-attribute instance-attribute

The number of seconds the driver will wait for a statement to execute. Zero means there is no limit.

This option depends on driver implementation, some drivers can check the timeout of each query instead of an entire JDBC batch.

parse(options) classmethod

If a parameter inherited from the ReadOptions class was passed, then it will be returned unchanged. If a Dict object was passed it will be converted to ReadOptions.

Otherwise, an exception will be raised

Source code in onetl/impl/generic_options.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@classmethod
def parse(
    cls: type[T],
    options: GenericOptions | dict | None,
) -> T:
    """
    If a parameter inherited from the ReadOptions class was passed, then it will be returned unchanged.
    If a Dict object was passed it will be converted to ReadOptions.

    Otherwise, an exception will be raised
    """

    if not options:
        return cls()

    if isinstance(options, dict):
        return cls.parse_obj(options)

    if not isinstance(options, cls):
        raise TypeError(
            f"{options.__class__.__name__} is not a {cls.__name__} instance",
        )

    return options

onetl.connection.db_connection.mssql.options.MSSQLExecuteOptions

Bases: JDBCExecuteOptions

Source code in onetl/connection/db_connection/mssql/options.py
31
32
class MSSQLExecuteOptions(JDBCExecuteOptions):
    __doc__ = JDBCExecuteOptions.__doc__.replace("SomeDB", "MSSQL")  # type: ignore[assignment, union-attr]

fetchsize = None class-attribute instance-attribute

How many rows to fetch per round trip.

Tuning this option can influence performance of reading.

.. warning:: Default value depends on driver. For example, Oracle has default fetchsize=10.

query_timeout = Field(default=None, alias='queryTimeout') class-attribute instance-attribute

The number of seconds the driver will wait for a statement to execute. Zero means there is no limit.

This option depends on driver implementation, some drivers can check the timeout of each query instead of an entire JDBC batch.

parse(options) classmethod

If a parameter inherited from the ReadOptions class was passed, then it will be returned unchanged. If a Dict object was passed it will be converted to ReadOptions.

Otherwise, an exception will be raised

Source code in onetl/impl/generic_options.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@classmethod
def parse(
    cls: type[T],
    options: GenericOptions | dict | None,
) -> T:
    """
    If a parameter inherited from the ReadOptions class was passed, then it will be returned unchanged.
    If a Dict object was passed it will be converted to ReadOptions.

    Otherwise, an exception will be raised
    """

    if not options:
        return cls()

    if isinstance(options, dict):
        return cls.parse_obj(options)

    if not isinstance(options, cls):
        raise TypeError(
            f"{options.__class__.__name__} is not a {cls.__name__} instance",
        )

    return options