Akses pangkalan data IRIS dengan ODBC atau JDBC menggunakan Python

Linda Hamilton
Lepaskan: 2024-09-29 06:14:02
asal
272 orang telah melayarinya

Access IRIS database with ODBC or JDBC using Python

Masalah dengan Rentetan

Saya sedang mengakses pangkalan data IRIS dengan JDBC (atau ODBC) menggunakan Python. Saya mahu mengambil data ke dalam bingkai data panda untuk memanipulasi data dan membuat carta daripadanya. Saya menghadapi masalah dengan pengendalian rentetan semasa menggunakan JDBC. Siaran ini adalah untuk membantu jika orang lain mempunyai masalah yang sama. Atau, jika ada cara yang lebih mudah untuk menyelesaikan masalah ini, beritahu saya dalam ulasan!

Saya menggunakan OSX, jadi saya tidak pasti betapa uniknya masalah saya. Saya menggunakan Buku Nota Jupyter, walaupun kodnya secara amnya adalah sama jika anda menggunakan mana-mana program atau rangka kerja Python yang lain.

Masalah JDBC

Apabila saya mengambil data daripada pangkalan data, penerangan lajur dan sebarang data rentetan dikembalikan sebagai jenis data java.lang.String. Jika anda mencetak data data rentetan ia akan kelihatan seperti: "(p,a,i,n,i,n,t,h,e,r,e,a,r)" bukannya "painintheraar" yang dijangkakan.

Ini mungkin kerana rentetan aksara jenis data java.lang.String datang melalui sebagai lelaran atau tatasusunan apabila diambil menggunakan JDBC. Ini boleh berlaku jika jambatan Python-Java yang anda gunakan (cth., JayDeBeApi, JDBC) tidak secara automatik menukar java.lang.String kepada Python str dalam satu langkah.

Perwakilan rentetan str Python, sebaliknya, mempunyai keseluruhan rentetan sebagai satu unit. Apabila Python mendapatkan semula str biasa (cth. melalui ODBC), ia tidak berpecah kepada aksara individu.

Penyelesaian JDBC

Untuk menyelesaikan isu ini, anda mesti memastikan bahawa java.lang.String ditukar dengan betul kepada jenis str Python. Anda boleh mengendalikan penukaran ini secara eksplisit apabila memproses data yang diambil supaya ia tidak ditafsirkan sebagai senarai aksara atau aksara yang boleh diubah.

Terdapat banyak cara untuk melakukan manipulasi rentetan ini; inilah yang saya lakukan.

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
Salin selepas log masuk

Masalah ODBC

Apabila menggunakan sambungan ODBC, rentetan tidak dikembalikan atau NA.

Jika anda menyambung ke pangkalan data yang mengandungi data Unikod (cth., nama dalam bahasa berbeza) atau jika aplikasi anda perlu menyimpan atau mendapatkan semula aksara bukan ASCII, anda mesti memastikan bahawa data kekal dikodkan dengan betul apabila dihantar antara pangkalan data dan aplikasi Python anda.

Penyelesaian ODBC

Kod ini memastikan data rentetan dikodkan dan dinyahkod menggunakan UTF-8 apabila menghantar dan mendapatkan semula data ke pangkalan data. Ia amat penting apabila berurusan dengan aksara bukan ASCII atau memastikan keserasian dengan data Unicode.

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
Salin selepas log masuk

connection.setdecoding(pyodbc.SQL_CHAR, encoding="utf8")

Memberitahu pyodbc cara menyahkod data aksara daripada pangkalan data apabila mengambil jenis SQL_CHAR (biasanya, medan aksara panjang tetap).

connection.setdecoding(pyodbc.SQL_WCHAR, encoding="utf8")

Menetapkan penyahkodan untuk SQL_WCHAR, jenis aksara lebar (iaitu, rentetan Unicode, seperti NVARCHAR atau NCHAR dalam SQL Server).

connection.setencoding(encoding="utf8")

Memastikan bahawa sebarang rentetan atau data aksara yang dihantar daripada Python ke pangkalan data akan dikodkan menggunakan UTF-8,
bermakna Python akan menterjemahkan jenis str dalamannya (iaitu Unicode) ke dalam UTF-8 bait apabila berkomunikasi dengan pangkalan data.


Menyatukan semuanya

Pasang JDBC

Pasang JAVA - gunakan dmg

https://www.oracle.com/middleeast/java/technologies/downloads/#jdk23-mac

Kemas kini shell untuk menetapkan versi lalai

$ /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
Salin selepas log masuk

Tambah JAVA_HOME pada laluan anda

export JAVA_HOME=$(/usr/libexec/java_home -v 23)
export PATH=$JAVA_HOME/bin:$PATH
Salin selepas log masuk

Dapatkan pemandu JDBC

https://intersystems-community.github.io/iris-driver-distribution/

Letakkan fail balang di suatu tempat... Saya letakkan di $HOME

$ ls $HOME/*.jar
/Users/myname/intersystems-jdbc-3.8.4.jar
Salin selepas log masuk

Kod contoh

Ia menganggap anda telah menyediakan ODBC (contoh untuk hari lain, anjing itu makan nota saya...).

Nota: ini adalah godam kod sebenar saya. Perhatikan nama pembolehubah.

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()
Salin selepas log masuk

Atas ialah kandungan terperinci Akses pangkalan data IRIS dengan ODBC atau JDBC menggunakan Python. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan