Ich greife mit Python auf IRIS-Datenbanken mit JDBC (oder ODBC) zu. Ich möchte die Daten in einen pandas-Datenrahmen abrufen, um die Daten zu bearbeiten und daraus Diagramme zu erstellen. Bei der Verwendung von JDBC ist ein Problem mit der String-Verarbeitung aufgetreten. Dieser Beitrag soll helfen, falls jemand anderes die gleichen Probleme hat. Oder wenn es einen einfacheren Weg gibt, dieses Problem zu lösen, lassen Sie es mich in den Kommentaren wissen!
Ich verwende OSX und bin mir daher nicht sicher, wie einzigartig mein Problem ist. Ich verwende Jupyter Notebooks, obwohl der Code im Allgemeinen derselbe wäre, wenn Sie ein anderes Python-Programm oder Framework verwenden würden.
Wenn ich Daten aus der Datenbank abrufe, werden die Spaltenbeschreibungen und alle Zeichenfolgendaten als Datentyp java.lang.String zurückgegeben. Wenn Sie Zeichenfolgendaten drucken, sieht das so aus: „(p,a,i,n,i,n,t,h,e,r,e,a,r)“ anstelle des erwarteten „painintherear“.
Dies liegt wahrscheinlich daran, dass Zeichenfolgen des Datentyps java.lang.String beim Abrufen mit JDBC als Iterable oder Array durchkommen. Dies kann passieren, wenn die von Ihnen verwendete Python-Java-Brücke (z. B. JayDeBeApi, JDBC) java.lang.String nicht automatisch in einem einzigen Schritt in einen Python-String konvertiert.
Pythons str-String-Darstellung hingegen hat den gesamten String als eine einzige Einheit. Wenn Python einen normalen String abruft (z. B. über ODBC), wird dieser nicht in einzelne Zeichen aufgeteilt.
Um dieses Problem zu beheben, müssen Sie sicherstellen, dass java.lang.String korrekt in den str-Typ von Python konvertiert wird. Sie können diese Konvertierung explizit bei der Verarbeitung der abgerufenen Daten verarbeiten, sodass sie nicht als iterierbare Datei oder Zeichenliste interpretiert wird.
Es gibt viele Möglichkeiten, diese Zeichenfolgenmanipulation durchzuführen; Das habe ich getan.
import pandas as pd import pyodbc import jaydebeapi import jpype def my_function(jdbc_used) # Some other code to create the connection goes here cursor.execute(query_string) if jdbc_used: # Fetch the results, convert java.lang.String in the data to Python str # (java.lang.String is returned "(p,a,i,n,i,n,t,h,e,r,e,a,r)" Convert to str type "painintherear" results = [] for row in cursor.fetchall(): converted_row = [str(item) if isinstance(item, jpype.java.lang.String) else item for item in row] results.append(converted_row) # Get the column names and ensure they are Python strings column_names = [str(col[0]) for col in cursor.description] # Create the dataframe df = pd.DataFrame.from_records(results, columns=column_names) # Check the results print(df.head().to_string()) else: # I was also testing ODBC # For very large result sets get results in chunks using cursor.fetchmany(). or fetchall() results = cursor.fetchall() # Get the column names column_names = [column[0] for column in cursor.description] # Create the dataframe df = pd.DataFrame.from_records(results, columns=column_names) # Do stuff with your dataframe
Bei Verwendung einer ODBC-Verbindung werden Zeichenfolgen nicht zurückgegeben oder sind NA.
Wenn Sie eine Verbindung zu einer Datenbank herstellen, die Unicode-Daten (z. B. Namen in verschiedenen Sprachen) enthält, oder wenn Ihre Anwendung Nicht-ASCII-Zeichen speichern oder abrufen muss, müssen Sie sicherstellen, dass die Daten bei der Weitergabe zwischen den korrekt codiert bleiben Datenbank und Ihrer Python-Anwendung.
Dieser Code stellt sicher, dass Zeichenfolgendaten beim Senden und Abrufen von Daten an die Datenbank mithilfe von UTF-8 codiert und decodiert werden. Dies ist besonders wichtig, wenn Sie mit Nicht-ASCII-Zeichen arbeiten oder die Kompatibilität mit Unicode-Daten sicherstellen.
def create_connection(connection_string, password): connection = None try: # print(f"Connecting to {connection_string}") connection = pyodbc.connect(connection_string ";PWD=" password) # Ensure strings are read correctly connection.setdecoding(pyodbc.SQL_CHAR, encoding="utf8") connection.setdecoding(pyodbc.SQL_WCHAR, encoding="utf8") connection.setencoding(encoding="utf8") except pyodbc.Error as e: print(f"The error '{e}' occurred") return connection
connection.setdecoding(pyodbc.SQL_CHAR, binding="utf8")
Teilt pyodbc mit, wie Zeichendaten aus der Datenbank dekodiert werden sollen, wenn SQL_CHAR-Typen abgerufen werden (normalerweise Zeichenfelder mit fester Länge).
connection.setdecoding(pyodbc.SQL_WCHAR, binding="utf8")
Legt die Dekodierung für SQL_WCHAR-Breitzeichentypen fest (d. h. Unicode-Zeichenfolgen wie NVARCHAR oder NCHAR in SQL Server).
connection.setencoding(encoding="utf8")
Stellt sicher, dass alle von Python an die Datenbank gesendeten Zeichenfolgen oder Zeichendaten mit UTF-8 codiert werden,
Das bedeutet, dass Python seinen internen str-Typ (der Unicode ist) bei der Kommunikation mit der Datenbank in UTF-8-Bytes übersetzt.
JAVA installieren – dmg verwenden
https://www.oracle.com/middleeast/java/technologies/downloads/#jdk23-mac
Shell aktualisieren, um die Standardversion festzulegen
$ /usr/libexec/java_home -V Matching Java Virtual Machines (2): 23 (arm64) "Oracle Corporation" - "Java SE 23" /Library/Java/JavaVirtualMachines/jdk-23.jdk/Contents/Home 1.8.421.09 (arm64) "Oracle Corporation" - "Java" /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home /Library/Java/JavaVirtualMachines/jdk-23.jdk/Contents/Home $ echo $SHELL /opt/homebrew/bin/bash $ vi ~/.bash_profile
Fügen Sie JAVA_HOME zu Ihrem Pfad hinzu
export JAVA_HOME=$(/usr/libexec/java_home -v 23) export PATH=$JAVA_HOME/bin:$PATH
Holen Sie sich den JDBC-Treiber
https://intersystems-community.github.io/iris-driver-distribution/
Legen Sie die JAR-Datei irgendwo ab... Ich habe sie in $HOME abgelegt
$ ls $HOME/*.jar /Users/myname/intersystems-jdbc-3.8.4.jar
Es wird davon ausgegangen, dass Sie ODBC eingerichtet haben (ein Beispiel für einen anderen Tag, der Hund hat meine Notizen gefressen...).
Hinweis: Dies ist ein Hack meines echten Codes. Beachten Sie die Variablennamen.
import os import datetime from datetime import date, time, datetime, timedelta import pandas as pd import pyodbc import jaydebeapi import jpype def jdbc_create_connection(jdbc_url, jdbc_username, jdbc_password): # Path to JDBC driver jdbc_driver_path = '/Users/yourname/intersystems-jdbc-3.8.4.jar' # Ensure JAVA_HOME is set os.environ['JAVA_HOME']='/Library/Java/JavaVirtualMachines/jdk-23.jdk/Contents/Home' os.environ['CLASSPATH'] = jdbc_driver_path # Start the JVM (if not already running) if not jpype.isJVMStarted(): jpype.startJVM(jpype.getDefaultJVMPath(), classpath=[jdbc_driver_path]) # Connect to the database connection = None try: connection = jaydebeapi.connect("com.intersystems.jdbc.IRISDriver", jdbc_url, [jdbc_username, jdbc_password], jdbc_driver_path) print("Connection successful") except Exception as e: print(f"An error occurred: {e}") return connection def odbc_create_connection(connection_string): connection = None try: # print(f"Connecting to {connection_string}") connection = pyodbc.connect(connection_string) # Ensure strings are read correctly connection.setdecoding(pyodbc.SQL_CHAR, encoding="utf8") connection.setdecoding(pyodbc.SQL_WCHAR, encoding="utf8") connection.setencoding(encoding="utf8") except pyodbc.Error as e: print(f"The error '{e}' occurred") return connection # Parameters odbc_driver = "InterSystems ODBC" odbc_host = "your_host" odbc_port = "51773" odbc_namespace = "your_namespace" odbc_username = "username" odbc_password = "password" jdbc_host = "your_host" jdbc_port = "51773" jdbc_namespace = "your_namespace" jdbc_username = "username" jdbc_password = "password" # Create connection and create charts jdbc_used = True if jdbc_used: print("Using JDBC") jdbc_url = f"jdbc:IRIS://{jdbc_host}:{jdbc_port}/{jdbc_namespace}?useUnicode=true&characterEncoding=UTF-8" connection = jdbc_create_connection(jdbc_url, jdbc_username, jdbc_password) else: print("Using ODBC") connection_string = f"Driver={odbc_driver};Host={odbc_host};Port={odbc_port};Database={odbc_namespace};UID={odbc_username};PWD={odbc_password}" connection = odbc_create_connection(connection_string) if connection is None: print("Unable to connect to IRIS") exit() cursor = connection.cursor() site = "SAMPLE" table_name = "your.TableNAME" desired_columns = [ "RunDate", "ActiveUsersCount", "EpisodeCountEmergency", "EpisodeCountInpatient", "EpisodeCountOutpatient", "EpisodeCountTotal", "AppointmentCount", "PrintCountTotal", "site", ] # Construct the column selection part of the query column_selection = ", ".join(desired_columns) query_string = f"SELECT {column_selection} FROM {table_name} WHERE Site = '{site}'" print(query_string) cursor.execute(query_string) if jdbc_used: # Fetch the results results = [] for row in cursor.fetchall(): converted_row = [str(item) if isinstance(item, jpype.java.lang.String) else item for item in row] results.append(converted_row) # Get the column names and ensure they are Python strings (java.lang.String is returned "(p,a,i,n,i,n,t,h,e,a,r,s,e)" column_names = [str(col[0]) for col in cursor.description] # Create the dataframe df = pd.DataFrame.from_records(results, columns=column_names) print(df.head().to_string()) else: # For very large result sets get results in chunks using cursor.fetchmany(). or fetchall() results = cursor.fetchall() # Get the column names column_names = [column[0] for column in cursor.description] # Create the dataframe df = pd.DataFrame.from_records(results, columns=column_names) print(df.head().to_string()) # # Build charts for a site # cf.build_7_day_rolling_average_chart(site, cursor, jdbc_used) cursor.close() connection.close() # Shutdown the JVM (if you started it) # jpype.shutdownJVM()
Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.
Copyright© 2022 湘ICP备2022001581号-3