2016-07-22 4 views
3

Wenn ich versuche, einen Datenrahmen mit einem Textindex speichern in einer MySQL-Datenbank, die ich den Fehler „BLOB/TEXT-Spalte in Schlüsselspezifikation ohne Schlüssellänge verwendet“ erhalten, zum Beispiel:Können Pandas mit MySQL Textindizes unterstützen?

import pandas as pd 
import sqlalchemy as sa 
df = pd.DataFrame(
    {'Id': ['AJP2008H', 'BFA2010Z'], 
    'Date': pd.to_datetime(['2010-05-05', '2010-07-05']), 
    'Value': [74.2, 52.3]}) 
df.set_index(['Id', 'Date'], inplace=True) 
engine = sa.create_engine(db_connection) 
conn = engine.connect() 
df.to_sql('test_table_index', conn, if_exists='replace') 
conn.close() 

wird den Fehler erzeugen :

InternalError: (pymysql.err.InternalError) 
(1170, "BLOB/TEXT column 'Id' used in key specification without a key length") 
[SQL: 'CREATE INDEX `ix_test_table_index_Id` ON test_table_index (`Id`)'] 

Wenn ich den Index nicht einstellen, funktioniert es gut. Gibt es eine Möglichkeit, sie zu speichern, ohne direkt auf SQLAlchemy zu verweisen, um zuerst die Tabelle zu erstellen?

(Dies ist meine aktuelle SQLAlchemy Abhilfe:

table = Table(
      name, self.metadata, 
      Column('Id', String(ID_LENGTH), primary_key=True), 
      Column('Date', DateTime, primary_key=True), 
      Column('Value', String(VALUE_LENGTH))) 
sa.MetaData().create_all(engine) # Creates the table if it doens't exist 

)

Antwort

5

Sie explizit eine SQLAlchemy data type angeben können, dtype Argument, wenn to_sql() Methode aufrufen:

In [48]: from sqlalchemy.types import VARCHAR 

In [50]: df 
Out[50]: 
        Value 
Id  Date 
AJP2008H 2010-05-05 74.2 
BFA2010Z 2010-07-05 52.3 

In [51]: df.to_sql('test_table_index', conn, if_exists='replace', 
        dtype={'Id': VARCHAR(df.index.get_level_values('Id').str.len().max())}) 

Sagen wir es überprüfen die MySQL-Seite:

mysql> show create table test_table_index\G 
*************************** 1. row *************************** 
     Table: test_table_index 
Create Table: CREATE TABLE `test_table_index` (
    `Id` varchar(8) DEFAULT NULL, 
    `Date` datetime DEFAULT NULL, 
    `Value` double DEFAULT NULL, 
    KEY `ix_test_table_index_Id` (`Id`), 
    KEY `ix_test_table_index_Date` (`Date`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 
1 row in set (0.00 sec) 


mysql> select * from test_table_index; 
+----------+---------------------+-------+ 
| Id  | Date    | Value | 
+----------+---------------------+-------+ 
| AJP2008H | 2010-05-05 00:00:00 | 74.2 | 
| BFA2010Z | 2010-07-05 00:00:00 | 52.3 | 
+----------+---------------------+-------+ 
2 rows in set (0.00 sec) 

jetzt wollen wir es wieder in einen neuen DF lesen:

In [52]: x = pd.read_sql('test_table_index', conn, index_col=['Id','Date']) 

In [53]: x 
Out[53]: 
        Value 
Id  Date 
AJP2008H 2010-05-05 74.2 
BFA2010Z 2010-07-05 52.3 

Sie die maximale Länge des Objektspalte auf diese Weise finden:

In [75]: df.index.get_level_values('Id').str.len().max() 
Out[75]: 8 
+0

Große Antwort, ich hatte gehofft, dass es sein könnte, eine generische Weise ein bisschen wie [sql_length in sqlalchemy] (http://docs.sqlalchemy.org/en/latest/dialects/mysql.html#index-length), Pandas einfach eine Länge zu geben, die es für Textfelder verwenden sollte Wenn wir also to_sql aufrufen, brauchen wir nichts über die Spaltentypen zu wissen. Wahrscheinlich nicht dann. – danio

+1

@danio, ich habe meine Antwort aktualisiert - etwas generischer gemacht ... – MaxU

Verwandte Themen