{"id":15024045,"url":"https://github.com/sap/sqlalchemy-hana","last_synced_at":"2026-04-01T19:35:26.988Z","repository":{"id":28631460,"uuid":"32150335","full_name":"SAP/sqlalchemy-hana","owner":"SAP","description":"SQLAlchemy Dialect for SAP HANA","archived":false,"fork":false,"pushed_at":"2025-05-08T19:54:10.000Z","size":644,"stargazers_count":136,"open_issues_count":0,"forks_count":56,"subscribers_count":14,"default_branch":"main","last_synced_at":"2025-05-11T05:28:58.205Z","etag":null,"topics":["hana","orm","python","sap-hana","sqlalchemy"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"lavie/runlike","license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SAP.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGES.rst","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-03-13T10:39:42.000Z","updated_at":"2025-05-08T19:54:15.000Z","dependencies_parsed_at":"2022-08-03T03:00:29.649Z","dependency_job_id":"26dd0ff5-bf59-455b-a611-48f2cd5b310d","html_url":"https://github.com/SAP/sqlalchemy-hana","commit_stats":{"total_commits":319,"total_committers":17,"mean_commits":"18.764705882352942","dds":0.6175548589341693,"last_synced_commit":"bbde552a5abe54651f4521d83fa526aa149e2d49"},"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SAP%2Fsqlalchemy-hana","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SAP%2Fsqlalchemy-hana/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SAP%2Fsqlalchemy-hana/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SAP%2Fsqlalchemy-hana/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SAP","download_url":"https://codeload.github.com/SAP/sqlalchemy-hana/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254292040,"owners_count":22046426,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hana","orm","python","sap-hana","sqlalchemy"],"created_at":"2024-09-24T19:59:44.501Z","updated_at":"2026-04-01T19:35:26.978Z","avatar_url":"https://github.com/SAP.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"SQLAlchemy dialect for SAP HANA\n===============================\n\n.. image:: https://api.reuse.software/badge/github.com/SAP/sqlalchemy-hana\n    :target: https://api.reuse.software/info/github.com/SAP/sqlalchemy-hana\n\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\n    :target: https://github.com/psf/black\n\n.. image:: https://coveralls.io/repos/github/SAP/sqlalchemy-hana/badge.svg\n    :target: https://coveralls.io/github/SAP/sqlalchemy-hana\n\nThis dialect allows you to use the SAP HANA database with SQLAlchemy.\nIt uses ``hdbcli`` to connect to SAP HANA.\nPlease notice that sqlalchemy-hana isn't an official SAP product and isn't covered by SAP support.\n\nPrerequisites\n-------------\n* Python 3.10+\n* SQLAlchemy 2.x\n* `hdbcli \u003chttps://help.sap.com/viewer/f1b440ded6144a54ada97ff95dac7adf/latest/en-US/f3b8fabf34324302b123297cdbe710f0.html\u003e`_\n\nInstall\n-------\nInstall from the Python Package Index:\n\n.. code-block:: bash\n\n    $ pip install sqlalchemy-hana\n\nVersioning\n----------\nsqlalchemy-hana follows the semantic versioning standard, meaning that breaking changes will\nonly be added in major releases.\nPlease note, that only the following modules are considered to be part of the public API\n\n- ``sqlalchemy_hana.types``\n- ``sqlalchemy_hana.errors``\n- ``sqlalchemy_hana.elements``\n- ``sqlalchemy_hana.functions``\n\nFor these, only exported members (part of ``__all__`` ) are guaranteed to be stable.\n\nSupported HANA Versions/Editions\n--------------------------------\n* SAP HANA Cloud\n* SAP HANA\n* SAP HANA, express edition\n\nGetting started\n---------------\nIf you do not have access to a SAP HANA server, you can also use the\n`SAP HANA Express edition \u003chttps://www.sap.com/cmp/td/sap-hana-express-edition.html\u003e`_.\n\nAfter installation of sqlalchemy-hana, you can create a engine which connects to a SAP HANA\ninstance. This engine works like all other engines of SQLAlchemy.\n\n.. code-block:: python\n\n    from sqlalchemy import create_engine\n    engine = create_engine('hana://username:password@example.de:30015')\n\nAlternatively, you can use HDB User Store to avoid entering connection-related information manually\neach time you want to establish a connection to an SAP HANA database:\n\n.. code-block:: python\n\n    from sqlalchemy import create_engine\n    engine = create_engine('hana://userkey=my_user_store_key')\n\nYou can create your user key in the user store using the following command:\n\n.. code-block::\n\n\thdbuserstore SET \u003cKEY\u003e \u003chost:port\u003e \u003cUSERNAME\u003e \u003cPASSWORD\u003e\n\nIn case of a tenant database, you may use:\n\n.. code-block:: python\n\n    from sqlalchemy import create_engine\n    engine = engine = create_engine('hana://user:pass@host/tenant_db_name')\n\nUsage\n-----\n\nSpecial CREATE TABLE argument\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSqlalchemy-hana provides a special argument called “hana_table_type” which can be used to\nspecify the type of table one wants to create with SAP HANA (i.e. ROW/COLUMN).\nThe default table type depends on your SAP HANA configuration and version.\n\n.. code-block:: python\n\n    t = Table('my_table', metadata, Column('id', Integer), hana_table_type = 'COLUMN')\n\nCase Sensitivity\n~~~~~~~~~~~~~~~~\nIn SAP HANA, all case insensitive identifiers are represented using uppercase text.\nIn SQLAlchemy on the other hand all lower case identifier names are considered to be case insensitive.\nThe sqlalchemy-hana dialect converts all case insensitive and case sensitive identifiers to the\nright casing during schema level communication.\nIn the sqlalchemy-hana dialect, using an uppercase name on the SQLAlchemy side indicates a case\nsensitive identifier, and SQLAlchemy will quote the name,which may cause case mismatches between\ndata received from SAP HANA.\nUnless identifier names have been truly created as case sensitive (i.e. using quoted names),\nall lowercase names should be used on the SQLAlchemy side.\n\nLIMIT/OFFSET Support\n~~~~~~~~~~~~~~~~~~~~\nSAP HANA supports both ``LIMIT`` and ``OFFSET``, but it only supports ``OFFSET`` in conjunction with\n``LIMIT`` i.e. in the select statement the offset parameter cannot be set without the ``LIMIT``\nclause, hence in sqlalchemy-hana if the user tries to use offset without limit, a limit of\n``2147384648`` would be set, this has been done so that the users can smoothly use ``LIMIT`` or\n``OFFSET`` as in other databases that do not have this limitation.\n``2147384648`` was chosen, because it is the maximum number of records per result set.\n\nRETURNING Support\n~~~~~~~~~~~~~~~~~\nSqlalchemy-hana does not support ``RETURNING`` in the ``INSERT``, ``UPDATE`` and ``DELETE``\nstatements to retrieve result sets of matched rows from ``INSERT``, ``UPDATE`` and ``DELETE``\nstatements because newly generated primary key values are neither fetched nor returned automatically\nin SAP HANA and SAP HANA does not support the syntax ``INSERT... RETURNING...``.\n\nReflection\n~~~~~~~~~~\nThe sqlalchemy-hana dialect supports all reflection capabilities of SQLAlchemy.\nThe Inspector used for the SAP HANA database is an instance of ``HANAInspector`` and offers an\nadditional method which returns the OID (object id) for the given table name.\n\n.. code-block:: python\n\n    from sqlalchemy import create_engine, inspect\n\n    engine = create_engine(\"hana://username:password@example.de:30015\")\n    insp = inspect(engine)  # will be a HANAInspector\n    print(insp.get_table_oid('my_table'))\n\nForeign Key Constraints\n~~~~~~~~~~~~~~~~~~~~~~~\nIn SAP HANA the following ``UPDATE`` and ``DELETE`` foreign key referential actions are available:\n\n* RESTRICT\n* CASCADE\n* SET NULL\n* SET DEFAULT\n\nThe foreign key referential option ``NO ACTION`` does not exist in SAP HANA.\nThe default is ``RESTRICT``.\n\nUNIQUE Constraints\n~~~~~~~~~~~~~~~~~~\nFor each unique constraint an index is created in SAP HANA, this may lead to unexpected behavior\nin programs using reflection.\n\nData types\n~~~~~~~~~~\nAs with all SQLAlchemy dialects, all UPPERCASE types that are known to be valid with SAP HANA are\nimportable from the top level dialect, whether they originate from sqlalchemy types or from the\nlocal dialect.\nTherefore all supported types are part of the ``sqlalchemy_hana.types`` module and can be used from\nthere.\n\nsqlalchemy-hana aims to support as many SQLAlchemy types as possible and to fallback to a similar\ntype of the requested type is not supported in SAP HANA.\nThe following table shows the mapping:\n\n.. list-table::\n    :header-rows: 1\n\n    * - SQLAlchemy type\n      - HANA type\n    * - DATETIME\n      - TIMESTAMP\n    * - NUMERIC\n      - DECIMAL\n    * - String\n      - NVARCHAR\n    * - Unicode\n      - NVARCHAR\n    * - TEXT\n      - NCLOB\n    * - BINARY\n      - VARBINARY\n    * - DOUBLE_PRECISION\n      - DOUBLE\n    * - Uuid\n      - NVARCHAR(32) / VARBINARY(16)\n    * - LargeBinary\n      - BLOB\n    * - UnicodeText\n      - NCLOB\n    * - JSON\n      - NCLOB\n\nPlease note, that some types might not support a length, precision or scale, even if the SQLAlchemy\ntype class accepts them.\nThe type compiler will then just ignore these arguments are render a type which will not lead to a\nSQL error.\n\nThe ``ARRAY`` datatype is not supported because ``hdbcli`` does not yet provide support for it.\n\nThe ``JSON`` datatype only supports saving/updating field contents, but no json-based filters/deep indexing,\nas these are not supported by SAP HANA.\n\nThe ``Uuid`` (note the casing) supports a special flag ``as_varbinary``.\nIf set to true (by default false), the UUID will be stored as a ``VARBINARY(16)`` instead of a ``NVARCHAR(32)``.\nThis does not effect the python side, meaning depending on the ``as_uuid`` flag, either uuid\nobjects or strings are used.\nTo use this feature in a database agnostic way, use\n``UuidType = Uuid().with_variant(sqlalchemy_hana.types.Uuid(as_varbinary=True), \"hana\")``.\nNote, that SAP HANA offers two UUID functions\n(`NEWUID \u003chttps://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-sql-reference-guide/newuid-function-miscellaneous?locale=en-US\u003e`_\nand `SYSUUID \u003chttps://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-sql-reference-guide/sysuuid-function-miscellaneous?locale=en-US\u003e`_\n) which can be used to generate e.g. default values like\n``Column('id', Uuid, server_default=func.NEWUID)``.\n\nThe ``REAL_VECTOR`` datatype is only supported within SAP HANA and needs to be imported from\n``sqlalchemy_hana.types``. See below for more details.\n\nReal Vector\n~~~~~~~~~~~\nBy default, vectors are represented using a python ``list``.\nThis can be changed using the engine parameter ``vector_output_type``, which can be set to\n``list`` (default), ``tuple`` or ``memoryview``.\nNote that this setting is applied globally and cannot be adapted on a column basis.\n\nFor proper typing, the ``REAL_VECTOR`` class is generic and be set to the proper type like\n\n.. code-block:: python\n\n    from sqlalchemy_hana.types import REAL_VECTOR\n\n    Column(\"v1\", REAL_VECTOR[list[float]](length=10))\n\nPlease note, that the generic type and ``vector_output_type`` should be kept in sync; this is not\nenforced.\n\nThe ``sqlalchemy_hana.functions`` package defines certain utility functions like\n``cosine_similarity``.\n\nRegex\n~~~~~\nsqlalchemy-hana supports the ``regexp_match`` and ``regexp_replace``\nfunctions provided by SQLAlchemy.\n\nBound Parameter Styles\n~~~~~~~~~~~~~~~~~~~~~~\nThe default parameter style for the sqlalchemy-hana dialect is ``qmark``, where SQL is rendered\nusing the following style:\n\n.. code-block:: sql\n\n    WHERE my_column = ?\n\nBoolean\n~~~~~~~\nBy default, sqlalchemy-hana uses native boolean types.\nHowever, older versions of sqlalchemy-hana used integer columns to represent these values leading\nto a compatibility gap.\nTo *disable* native boolean support, add ``use_native_boolean=False`` to ``create_engine``.\n\nUsers are encouraged to switch to native booleans.\nThis can be e.g. done by using ``alembic``:\n\n.. code-block:: python\n\n    from sqlalchemy import false\n\n    # assuming a table TAB with a tinyint column named valid\n    def upgrade() -\u003e None:\n        op.add_column(Column(\"TAB\", Column('valid_tmp', Boolean, server_default=false())))\n        op.get_bind().execute(\"UPDATE TAB SET valid_tmp = TRUE WHERE valid = 1\")\n        op.drop_column(\"TAB\", \"valid\")\n        op.get_bind().execute(\"RENAME COLUMN TAB.valid_tmp to valid\")\n        # optionally, remove also the server default by using alter column\n\nComputed columns\n~~~~~~~~~~~~~~~~\nSAP HANA supports two computed/calculated columns:\n\n* \u003ccol\u003e AS \u003cexpr\u003e: the column is fully virtual and the expression is evaluated with each SELECT\n* \u003ccol\u003e GENERATED ALWAYS AS \u003cexpr\u003e: the expression is evaluated during insertion and the value\n    is stored in the table\n\nBy default, sqlalchemy-hana creates a ``GENERATED ALWAYS AS`` if a ``Computed`` column is used.\nIf ``Computed(persisted=False)`` is used, a fully virtual column using ``AS`` is created.\n\nViews\n~~~~~\nsqlalchemy-hana supports the creation and usage of SQL views.\n\nThe views are not bound to the metadata object, therefore each needs to be created/dropped manually\nusing ``CreateView`` and ``DropView``.\nBy using the helper function ``view``, a ``TableClause`` object is generated which can be used in\nselect statements.\nThe returned object has the same primary keys as the underlying selectable.\n\nViews can also be used in ORM and e.g. assigned to the ``__table__`` attribute of declarative base\nclasses.\n\nFor general information about views, please refer to\n`this page \u003chttps://github.com/sqlalchemy/sqlalchemy/wiki/Views\u003e`_.\n\n.. code-block:: python\n\n    from sqlalchemy import Column, Integer, MetaData, String, Table, select\n    from sqlalchemy_hana.elements import CreateView, DropView, view\n\n    engine = None  # a engine bound to a SAP HANA instance\n    metadata = MetaData()\n    stuff = sa.Table(\n        \"stuff\",\n        metadata,\n        Column(\"id\", Integer, primary_key=True),\n        Column(\"data\", String(50)),\n    )\n\n    selectable = select(stuff.c.id, stuff.c.data).where(stuff.c.data == \"something\")\n\n    with engine.begin() as conn:\n        # create a view\n        ddl = CreateView(\"stuff_view\", selectable)\n        conn.execute(ddl)\n\n        # usage of a view\n        stuff_view = view(\"stuff_view\", selectable)\n        select(stuff_view.c.id, stuff_view.c.data).all()\n\n        # drop a view\n        ddl = DropView(\"stuff_view\")\n        conn.execute(ddl)\n\nUpsert\n~~~~~~\nUPSERT statements are supported with some limitations by sqlalchemy-hana.\nCaching is disabled due to implementation details and will not be added until a unified\ninsert/upsert/merge implementation is available in SQLAlchemy (see https://github.com/sqlalchemy/sqlalchemy/issues/8321).\n\n.. code-block:: python\n\n    from sqlalchemy import Column, Integer, MetaData, String, Table\n    from sqlalchemy_hana.elements import upsert\n\n    engine = None  # a engine bound to a SAP HANA instance\n    metadata = MetaData()\n    stuff = sa.Table(\n        \"stuff\",\n        metadata,\n        Column(\"id\", Integer, primary_key=True),\n        Column(\"data\", String(50)),\n    )\n\n    with engine.begin() as conn:\n        statement upsert(stuff).values(id=1, data=\"some\").filter_by(id=1)\n        conn.execute(statement)\n\nIdentity\n~~~~~~~~\nIdentity columns are fully supported but not reflection of those.\nTherefore, alembic support for identity columns is reduced to creation of those.\n\nAuto-increment\n~~~~~~~~~~~~~~\nSAP HANA only supports auto-increment with identity columns, therefore an identity will be rendered\nif needed. This means that the  the following constructs are equivalent:\n\n* ``Column('some', Integer, autoincrement=True)``\n* ``Column('some', Integer, Identity, autoincrement=True)``\n* ``Column('some', Integer, Identity, autoincrement=True)``\n\nNote, that for ``autoincrement=True`` a post-execute statement execution is needed to fetch the\ninserted identity value which might affect performance.\n\nAs an SQLAlchemy specific alternative, a ``sqlalchemy.schema.Sequence`` can be used to simulate\nan auto-increment behavior, as followed:\n\n.. code-block:: python\n\n    t = Table('my_table', metadata, Column('id', Integer, Sequence('id_seq'), primary key=True))\n\nNote, that on SAP HANA side, the column and the sequence are not linked, meaning that the sequence\ncan be e.g. be incremented w/o an actual insert into the table.\n\nasyncio support\n---------------\nasyncio is supported via the\n`SQLAlchemy asyncio extension \u003chttps://docs.sqlalchemy.org/en/20/orm/extensions/asyncio.html\u003e`_.\nFor this, use the ``hana+aiohdbcli`` dialect name.\nThe support is still experimental, therefore some features might not work as expected.\n\nAlembic\n-------\nThe sqlalchemy-hana dialect also contains a dialect for ``alembic``.\nThis dialect is active as soon as ``alembic`` is installed.\nTo ensure version compatibility, install sqlalchemy-hana as followed:\n\n.. code-block:: bash\n\n    $ pip install sqlalchemy-hana[alembic]\n\nError handling for humans\n-------------------------\nsqlalchemy-hana provides the ``sqlalchemy_hana.errors`` module which contains a set of\nspecial exceptions and wrapper methods.\nSQLAlchemy and hdbcli only provide generic exceptions which are sometimes not very helpful and\nmanual effort is needed to extract the relevant information.\nTo make this easier, the module provides two wrapper functions which take a SQLAlchemy or hdbcli\nerror and raise a more specific exception if possible.\n\n.. code-block:: python\n\n    from sqlalchemy_hana.errors import wrap_dbapi_error\n    from sqlalchemy.exc import DBAPIError\n\n    try:\n        # some sqlalchemy code which might raise a DBAPIError\n    except DBAPIError as err:\n        wrap_dbapi_error(err)\n        # if you reach this line, either the wrapped error of DBAPIError was not a hdbcli error\n        # of no more specific exception was found\n\nDevelopment Setup\n-----------------\nThis project uses `uv`.\nTo setup a venv for development use\n`python3.14 -m venv venv \u0026\u0026 pip install uv \u0026\u0026 uv sync --all-groups --all-extras \u0026\u0026 rm -rf venv/`.\nThen use `source .venv/bin/activate` to activate your venv.\n\nTo execute the tests, use ``uv run pytest``.\nThe linters and formatters can be executed using ``pre-commit``: ``uv run pre-commit run -a``.\n\nTesting\n-------\n**Pre-Submit**: Linters, formatters and test matrix\n**Post-Submit**: Linters and formatters\n\nRelease Actions\n---------------\n* Update the version in the pyproject.toml\n* Add an entry in the changelog\n* Push a new tag like vX.X.X to trigger the release\n\nSupport, Feedback, Contributing\n-------------------------------\nThis project is open to feature requests/suggestions, bug reports etc.\nvia `GitHub issues \u003chttps://github.com/SAP/sqlalchemy-hana/issues\u003e`_.\nContribution and feedback are encouraged and always welcome.\nFor more information about how to contribute, the project structure,\nas well as additional contribution information, see our\n`Contribution Guidelines \u003chttps://github.com/SAP/sqlalchemy-hana/blob/main/CONTRIBUTING.md\u003e`_.\n\nSecurity / Disclosure\n---------------------\nIf you find any bug that may be a security problem, please follow our instructions at\n`in our security policy \u003chttps://github.com/SAP/sqlalchemy-hana/security/policy\u003e`_ on how to report it.\nPlease do not create GitHub issues for security-related doubts or problems.\n\nCode of Conduct\n---------------\nWe as members, contributors, and leaders pledge to make participation in our community a\nharassment-free experience for everyone.\nBy participating in this project, you agree to abide by its\n`Code of Conduct \u003chttps://github.com/SAP/.github/blob/main/CODE_OF_CONDUCT.md\u003e`_ at all times.\n\nLicensing\n---------\nCopyright 2026 SAP SE or an SAP affiliate company and sqlalchemy-hana contributors.\nPlease see our `LICENSE \u003chttps://github.com/SAP/sqlalchemy-hana/blob/main/LICENSE\u003e`_\nfor copyright and license information.\nDetailed information including third-party components and their licensing/copyright information\nis available `via the REUSE tool \u003chttps://api.reuse.software/info/github.com/SAP/sqlalchemy-hana\u003e`_.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsap%2Fsqlalchemy-hana","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsap%2Fsqlalchemy-hana","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsap%2Fsqlalchemy-hana/lists"}