hemy connectable which may not
            reflect the exact number of written rows as stipulated in the
            `sqlite3 <https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.rowcount>`__ or
            `SQLAlchemy <https://docs.sqlalchemy.org/en/20/core/connections.html#sqlalchemy.engine.CursorResult.rowcount>`__.

            .. versionadded:: 1.4.0

        Raises
        ------
        ValueError
            When the table already exists and `if_exists` is 'fail' (the
            default).

        See Also
        --------
        read_sql : Read a DataFrame from a table.

        Notes
        -----
        Timezone aware datetime columns will be written as
        ``Timestamp with timezone`` type with SQLAlchemy if supported by the
        database. Otherwise, the datetimes will be stored as timezone unaware
        timestamps local to the original timezone.

        References
        ----------
        .. [1] https://docs.sqlalchemy.org
        .. [2] https://www.python.org/dev/peps/pep-0249/

        Examples
        --------
        Create an in-memory SQLite database.

        >>> from sqlalchemy import create_engine
        >>> engine = create_engine('sqlite://', echo=False)

        Create a table from scratch with 3 rows.

        >>> df = pd.DataFrame({'name' : ['User 1', 'User 2', 'User 3']})
        >>> df
             name
        0  User 1
        1  User 2
        2  User 3

        >>> df.to_sql(name='users', con=engine)
        3
        >>> from sqlalchemy import text
        >>> with engine.connect() as conn:
        ...    conn.execute(text("SELECT * FROM users")).fetchall()
        [(0, 'User 1'), (1, 'User 2'), (2, 'User 3')]

        An `sqlalchemy.engine.Connection` can also be passed to `con`:

        >>> with engine.begin() as connection:
        ...     df1 = pd.DataFrame({'name' : ['User 4', 'User 5']})
        ...     df1.to_sql(name='users', con=connection, if_exists='append')
        2

        This is allowed to support operations that require that the same
        DBAPI connection is used for the entire operation.

        >>> df2 = pd.DataFrame({'name' : ['User 6', 'User 7']})
        >>> df2.to_sql(name='users', con=engine, if_exists='append')
        2
        >>> with engine.connect() as conn:
        ...    conn.execute(text("SELECT * FROM users")).fetchall()
        [(0, 'User 1'), (1, 'User 2'), (2, 'User 3'),
         (0, 'User 4'), (1, 'User 5'), (0, 'User 6'),
         (1, 'User 7')]

        Overwrite the table with just ``df2``.

        >>> df2.to_sql(name='users', con=engine, if_exists='replace',
        ...            index_label='id')
        2
        >>> with engine.connect() as conn:
        ...    conn.execute(text("SELECT * FROM users")).fetchall()
        [(0, 'User 6'), (1, 'User 7')]

        Use ``method`` to define a callable insertion method to do nothing
        if there's a primary key conflict on a table in a PostgreSQL database.

        >>> from sqlalchemy.dialects.postgresql import insert
        >>> def insert_on_conflict_nothing(table, conn, keys, data_iter):
        ...     # "a" is the primary key in "conflict_table"
        ...     data = [dict(zip(keys, row)) for row in data_iter]
        ...     stmt = insert(table.table).values(data).on_conflict_do_nothing(index_elements=["a"])
        ...     result = conn.execute(stmt)
        ...     return result.rowcount
        >>> df_conflict.to_sql(name="conflict_table", con=conn, if_exists="append", method=insert_on_conflict_nothing)  # doctest: +SKIP
        0

        For MySQL, a callable to update columns ``b`` and ``c`` if there's a conflict
        on a primary key.

        >>> from sqlalchemy.dialects.mysql import insert
        >>> def insert_on_conflict_update(table, conn, keys, data_iter):
        ...     # update columns "b" and "c" on primary key conflict
        ...     data = [dict(zip(keys, row)) for row in data_iter]
        ...     stmt = (
        ...         insert(table.table)
        ...         .values(data)
        ...     )
        ...     stmt = stmt.on_duplicate_key_update(b=stmt.inserted.b, c=stmt.inserted.c)
        ...     result = conn.execute(stmt)
        ...     return result.rowcount
        >>> df_conflict.to_sql(name="conflict_table", con=conn, if_exists="append", method=insert_on_conflict_update)  # doctest: +SKIP
        2

        Specify the dtype (especially useful for integers with missing values).
        Notice that while pandas is forced to store the data as floating point,
        the database supports nullable integers. When fetching the data with
        Python, we get back integer scalars.

        >>> df = pd.DataFrame({"A": [1, None, 2]})
        >>> df
             A
        0  1.0
        1  NaN
        2  2.0

        >>> from sqlalchemy.types import Integer
        >>> df.to_sql(name='integers', con=engine, index=False,
        ...           dtype={"A": Integer()})
        3

        >>> with engine.connect() as conn:
        ...   conn.execute(text("SELECT * FROM integers")).fetchall()
        [(1,), (None,), (2,)]
        r