> ## Documentation Index
> Fetch the complete documentation index at: https://docs.activeviam.com/llms.txt
> Use this file to discover all available pages before exploring further.

# atoti.Session.query_mdx()

#### Session.query\_mdx(mdx: [str](https://docs.python.org/3/library/stdtypes.html#str), /, \*, context: [Mapping](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping)\[[str](https://docs.python.org/3/library/stdtypes.html#str), [bool](https://docs.python.org/3/library/functions.html#bool) | [int](https://docs.python.org/3/library/functions.html#int) | [float](https://docs.python.org/3/library/functions.html#float) | [str](https://docs.python.org/3/library/stdtypes.html#str)] = frozendict(\{}), explain: [Literal](https://docs.python.org/3/library/typing.html#typing.Literal)\[False] = False, keep\_totals: [bool](https://docs.python.org/3/library/functions.html#bool) = False, mode: [Literal](https://docs.python.org/3/library/typing.html#typing.Literal)\['pretty'] = 'pretty') → [MdxQueryResult](./atoti.mdx_query_result#atoti.MdxQueryResult)

#### Session.query\_mdx(mdx: [str](https://docs.python.org/3/library/stdtypes.html#str), /, \*, context: [Mapping](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping)\[[str](https://docs.python.org/3/library/stdtypes.html#str), [bool](https://docs.python.org/3/library/functions.html#bool) | [int](https://docs.python.org/3/library/functions.html#int) | [float](https://docs.python.org/3/library/functions.html#float) | [str](https://docs.python.org/3/library/stdtypes.html#str)] = frozendict(\{}), explain: [Literal](https://docs.python.org/3/library/typing.html#typing.Literal)\[False] = False, keep\_totals: [bool](https://docs.python.org/3/library/functions.html#bool) = False, mode: [Literal](https://docs.python.org/3/library/typing.html#typing.Literal)\['pretty', 'raw'] = 'pretty') → [DataFrame](https://pandas.pydata.org/pandas-docs/version/2.3/reference/api/pandas.DataFrame.html#pandas.DataFrame)

#### Session.query\_mdx(mdx: [str](https://docs.python.org/3/library/stdtypes.html#str), /, \*, context: [Mapping](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping)\[[str](https://docs.python.org/3/library/stdtypes.html#str), [bool](https://docs.python.org/3/library/functions.html#bool) | [int](https://docs.python.org/3/library/functions.html#int) | [float](https://docs.python.org/3/library/functions.html#float) | [str](https://docs.python.org/3/library/stdtypes.html#str)] = frozendict(\{}), explain: [Literal](https://docs.python.org/3/library/typing.html#typing.Literal)\[True], keep\_totals: [bool](https://docs.python.org/3/library/functions.html#bool) = False, mode: [Literal](https://docs.python.org/3/library/typing.html#typing.Literal)\['pretty', 'raw'] = 'pretty') → [object](https://docs.python.org/3/library/functions.html#object)

Execute an MDX query.

In JupyterLab with [`atoti-jupyterlab`](./atoti_jupyterlab#module-atoti_jupyterlab) installed, query results can be converted to interactive widgets with the Convert to Widget Below action available in the command palette or by right clicking on the representation of the returned Dataframe.

* **Parameters:**
  * **mdx** –

    The MDX `SELECT` query to execute.

    Regardless of the axes on which levels and measures appear in the MDX, the returned DataFrame will have all levels on rows and measures on columns.

    ### Example

    ```pycon theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
    >>> from datetime import date
    >>> df = pd.DataFrame(
    ...     columns=["Country", "Date", "Price"],
    ...     data=[
    ...         ("China", date(2020, 3, 3), 410.0),
    ...         ("France", date(2020, 1, 1), 480.0),
    ...         ("France", date(2020, 2, 2), 500.0),
    ...         ("France", date(2020, 3, 3), 400.0),
    ...         ("India", date(2020, 1, 1), 360.0),
    ...         ("India", date(2020, 2, 2), 400.0),
    ...         ("UK", date(2020, 2, 2), 960.0),
    ...     ],
    ... )
    >>> table = session.read_pandas(
    ...     df,
    ...     keys={"Country", "Date"},
    ...     table_name="Prices",
    ... )
    >>> cube = session.create_cube(table)
    ```

    This MDX:

    ```pycon theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
    >>> mdx = (
    ...     "SELECT"
    ...     "  NON EMPTY Hierarchize("
    ...     "    DrilldownLevel("
    ...     "      [Prices].[Country].[ALL].[AllMember]"
    ...     "    )"
    ...     "  ) ON ROWS,"
    ...     "  NON EMPTY Crossjoin("
    ...     "    [Measures].[Price.SUM],"
    ...     "    Hierarchize("
    ...     "      DrilldownLevel("
    ...     "        [Prices].[Date].[ALL].[AllMember]"
    ...     "      )"
    ...     "    )"
    ...     "  ) ON COLUMNS"
    ...     "  FROM [Prices]"
    ... )
    ```

    Returns this DataFrame:

    ```pycon theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
    >>> session.query_mdx(mdx, keep_totals=True)
                       Price.SUM
    Date       Country
    Total               3,510.00
    2020-01-01            840.00
    2020-02-02          1,860.00
    2020-03-03            810.00
               China      410.00
    2020-01-01 China
    2020-02-02 China
    2020-03-03 China      410.00
               France   1,380.00
    2020-01-01 France     480.00
    2020-02-02 France     500.00
    2020-03-03 France     400.00
               India      760.00
    2020-01-01 India      360.00
    2020-02-02 India      400.00
    2020-03-03 India
               UK         960.00
    2020-01-01 UK
    2020-02-02 UK         960.00
    2020-03-03 UK
    ```

    But, if it was displayed into a pivot table, would look like this:

    |        |            | Country    | Price.sum  |
    | ------ | ---------- | ---------- | ---------- |
    | Total  | 2020-01-01 | 2020-02-02 | 2020-03-03 |
    | Total  | 3,510.00   | 840.00     | 1,860.00   |
    | China  | 410.00     |            |            |
    | France | 1,380.00   | 480.00     | 500.00     |
    | India  | 760.00     | 360.00     | 400.00     |
    | UK     | 960.00     |            | 960.00     |
  * **context** –

    Context values to use when executing the query.

    See [`shared_context`](./atoti.Cube.shared_context#atoti.Cube.shared_context) for some of the available context values.
  * **explain** – When `True`, execute the query but, instead of returning its result, return an explanation of how it was executed containing a summary, global timings, and the query plan and all its retrievals.
  * **keep\_totals** – Whether the resulting DataFrame should contain, if they are present in the query result, the grand total and subtotals.
    Totals can be useful but they make the DataFrame harder to work with since its index will have some empty values.
  * **mode** –

    The query mode.

    * `"pretty"` is best for queries returning small results.
    * `"raw"` is best for benchmarks or large exports:
      * A faster and more efficient endpoint reducing the data transfer from Java to Python will be used.
      * The Convert to Widget Below action provided by [`atoti-jupyterlab`](./atoti_jupyterlab#module-atoti_jupyterlab) will not be available.

<Callout icon="link">
  **See also**:
  [`atoti.Cube.query()`](./atoti.Cube.query#atoti.Cube.query)
</Callout>
