From db2288ec15c00c0834150e9f2c94903b6e876704 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Thu, 8 May 2014 16:40:56 +0200 Subject: [PATCH] FIX sql handling of timedelta64 columns (GH6921) --- doc/source/io.rst | 9 +++++++-- pandas/io/sql.py | 10 +++++++++- pandas/io/tests/test_sql.py | 13 +++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/doc/source/io.rst b/doc/source/io.rst index a0807088b2cf5..212b2debc98a5 100644 --- a/doc/source/io.rst +++ b/doc/source/io.rst @@ -809,8 +809,6 @@ two extra parameters: String value 'infer' can be used to instruct the parser to try detecting the column specifications from the first 100 rows of the data. Default behaviour, if not specified, is to infer. - As with regular python slices, you can slice to the end of the line - with ``None``, e.g. ``colspecs = [(0, 1), (1, None)]``. - ``widths``: A list of field widths which can be used instead of 'colspecs' if the intervals are contiguous. @@ -3235,6 +3233,13 @@ the database using :func:`~pandas.DataFrame.to_sql`. data.to_sql('data', engine) +.. note:: + + Due to the limited support for timedelta's in the different database + flavors, columns with type ``timedelta64`` will be written as integer + values as nanoseconds to the database and a warning will be raised. + + Reading Tables ~~~~~~~~~~~~~~ diff --git a/pandas/io/sql.py b/pandas/io/sql.py index c18a4aef5355b..d54e3a5f549ca 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -730,7 +730,10 @@ def _sqlalchemy_type(self, arr_or_dtype): except: return DateTime if com.is_timedelta64_dtype(arr_or_dtype): - return Interval + warnings.warn("the 'timedelta' type is not supported, and will be " + "written as integer values (ns frequency) to the " + "database.", UserWarning) + return Integer elif com.is_float_dtype(arr_or_dtype): return Float elif com.is_integer_dtype(arr_or_dtype): @@ -973,6 +976,11 @@ def _sql_type_name(self, dtype): pytype_name = "text" if issubclass(pytype, np.floating): pytype_name = "float" + elif com.is_timedelta64_dtype(pytype): + warnings.warn("the 'timedelta' type is not supported, and will be " + "written as integer values (ns frequency) to the " + "database.", UserWarning) + pytype_name = "int" elif issubclass(pytype, np.integer): pytype_name = "int" elif issubclass(pytype, np.datetime64) or pytype is datetime: diff --git a/pandas/io/tests/test_sql.py b/pandas/io/tests/test_sql.py index 9a34e84c153a0..8b1de89be7acb 100644 --- a/pandas/io/tests/test_sql.py +++ b/pandas/io/tests/test_sql.py @@ -29,12 +29,14 @@ from datetime import datetime from pandas import DataFrame, Series, Index, MultiIndex, isnull +from pandas import to_timedelta import pandas.compat as compat from pandas.compat import StringIO, range, lrange from pandas.core.datetools import format as date_format import pandas.io.sql as sql import pandas.util.testing as tm +from pandas import _np_version_under1p7 try: @@ -480,6 +482,17 @@ def test_date_and_index(self): self.assertTrue(issubclass(df.IntDateCol.dtype.type, np.datetime64), "IntDateCol loaded with incorrect type") + def test_timedelta(self): + # see #6921 + if _np_version_under1p7: + raise nose.SkipTest("test only valid in numpy >= 1.7") + + df = to_timedelta(Series(['00:00:01', '00:00:03'], name='foo')).to_frame() + with tm.assert_produces_warning(UserWarning): + df.to_sql('test_timedelta', self.conn) + result = sql.read_sql_query('SELECT * FROM test_timedelta', self.conn) + tm.assert_series_equal(result['foo'], df['foo'].astype('int64')) + def test_to_sql_index_label(self): temp_frame = DataFrame({'col1': range(4)})