Je me connecte à une base de données SQL Server en utilisant SQLAlchemy (avec le pilote pymssql
).
(('col_1', 1, None, None, None, None, None), ('col_2', 1, None, None, None, None, None), ('col_3', 4, None, None, None, None, None), ('col_4', 3, None, None, None, None, None), ('col_5', 3, None, None, None, None, None))
ce qui se traduit par:
import sqlalchemy conn_string = f'mssql+pymssql://{uid}:{pwd}@{instance}/?database={db};charset=utf8' sql = 'SELECT * FROM FAKETABLE;' engine = sqlalchemy.create_engine(conn_string) connection = engine.connect() result = connection.execute(sql) result.cursor.description
Selon PEP 249 (attribut .description
du curseur):
Les deux premiers éléments (nom et type_code) sont obligatoires, les cinq autres sont facultatifs et sont définis sur Aucun si aucune valeur significative ne peut être fournie.
Je suppose que les entiers (1, 1, 4, 3, 3)
sont des types de colonnes.
Mes deux questions:
FWIW, j'obtiens le même résultat en utilisant raw_connection()
au lieu de connect()
.
Je suis tombé sur trois questions dans le même sens (qui ne répondent pas à cette question spécifique). J'ai besoin d'utiliser l'approche connect()
+ execute()
.
3 Réponses :
Si non, est-il possible d'obtenir les types de données SQL?
La fonction SQL Server sys.dm_exec_describe_first_result_set peut être utilisée pour obtenir le type de données de la colonne SQL directement pour la requête fournie:
CREATE TABLE FAKETABLE(id INT, d DATE, country NVARCHAR(10)); SELECT column_ordinal, name, system_type_name FROM sys.dm_exec_describe_first_result_set('SELECT * FROM FAKETABLE', NULL, 0) ; +-----------------+----------+------------------+ | column_ordinal | name | system_type_name | +-----------------+----------+------------------+ | 1 | id | int | | 2 | d | date | | 3 | country | nvarchar(10) | +-----------------+----------+------------------+Dans votre exemple:
sql = """SELECT column_ordinal, name, system_type_name FROM sys.dm_exec_describe_first_result_set('SELECT * FROM FAKETABLE', NULL, 0) ;"""Pour:
SELECT column_ordinal, name, system_type_name, * FROM sys.dm_exec_describe_first_result_set('here goes query', NULL, 0) ;
Merci, j'espérais que la réponse serait disponible quelque part dans les métadonnées, mais c'est le meilleur que j'ai.
En regardant PEP249 : type_code
ne semble pas être le même à travers un type de base de données différent.
Cette réponse se concentrera donc sur MS SQL Server.
- Comment mapper ces entiers à des types de données (comme char, integer, etc.)?
Vous pouvez créer un dict de type_code
dans type_object
à l'aide du code suivant:
{2: ('BINARY', <DBAPIType 2>), 4: ('DATETIME', <DBAPIType 4>), 5: ('DECIMAL', <DBAPIType 5>), 3: ('NUMBER', <DBAPIType 3>), 1: ('STRING', <DBAPIType 1>)}
Cela produira le dict suivant:
import inspect import pymssql code_map = { type_obj.value: (type_name, type_obj) for type_name, type_obj in inspect.getmembers( pymssql, predicate=lambda x: isinstance(x, pymssql.DBAPIType), ) }
Malheureusement, je n'ai pas accès à une instance en cours d'exécution de MS SQL Server. Je ne suis donc pas en mesure de vérifier si les résultats de type correspondent à votre exemple.
- S'agit-il de types de données SQL? Si non, est-il possible d'obtenir les types de données SQL?
En regardant le PEP et ce résultat: ces champs ne sont pas des types de données SQL. Il s'agit de "Type Object".
L'API DB n'a pas l'air de fournir des méthodes / fonctions pour inspecter les métadonnées des résultats de la requête. L'API fournit simplement un moyen de lier les types de données de SQL aux types python.
Si vous avez besoin d'obtenir le type de données SQL exact, vous devez écrire une requête SQL spécifique au serveur.
Merci, mais il semble que ce ne soit que le mappage du code au type de données. Je suis particulièrement intéressé par les types de données SQL.
Ce pourrait être le pilote lui-même. Ci-dessous, j'ai presque le même code que le vôtre, en utilisant simplement le pilote pyodbc sur AdventureWorks. J'ai choisi une table avec beaucoup de types de données différents et ils sont tous affichés.
(('ProductID', <class 'int'>, None, 10, 10, 0, False), ('Name', <class 'str'>, None, 50, 50, 0, False), ('ProductNumber', <class 'str'>, None, 25, 25, 0, False), ('Color', <class 'str'>, None, 15, 15, 0, True), ('StandardCost', <class 'decimal.Decimal'>, None, 19, 19, 4, False), ('ListPrice', <class 'decimal.Decimal'>, None, 19, 19, 4, False), ('Size', <class 'str'>, None, 5, 5, 0, True), ('Weight', <class 'decimal.Decimal'>, None, 8, 8, 2, True), ('ProductCategoryID', <class 'int'>, None, 10, 10, 0, True), ('ProductModelID', <class 'int'>, None, 10, 10, 0, True), ('SellStartDate', <class 'datetime.datetime'>, None, 23, 23, 3, False), ('SellEndDate', <class 'datetime.datetime'>, None, 23, 23, 3, True), ('DiscontinuedDate', <class 'datetime.datetime'>, None, 23, 23, 3, True), ('ThumbNailPhoto', <class 'bytearray'>, None, 0, 0, 0, True), ('ThumbnailPhotoFileName', <class 'str'>, None, 50, 50, 0, True), ('rowguid', <class 'str'>, None, 36, 36, 0, False), ('ModifiedDate', <class 'datetime.datetime'>, None, 23, 23, 3, False))
Production:
import sqlalchemy conn_string = conn_string = f'mssql+pyodbc://{username}:{pwd}@{instance}/AdventureWorksLT2017?driver=ODBC+Driver+17+for+SQL+Server' sql = 'SELECT TOP 10 * FROM SalesLT.Product;' engine = sqlalchemy.create_engine(conn_string) connection = engine.connect() result = connection.execute(sql) print(result.cursor.description)
Pouvez-vous essayer ce pilote à titre de comparaison?
Merci, c'est utile. Mais j'ai besoin d'utiliser pymssql
.