«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Доступ к базе данных IRIS с помощью ODBC или JDBC с использованием Python

Доступ к базе данных IRIS с помощью ODBC или JDBC с использованием Python

Опубликовано 15 ноября 2024 г.
Просматривать:974

Access IRIS database with ODBC or JDBC using Python

Проблемы со строками

Я получаю доступ к базам данных IRIS с помощью JDBC (или ODBC) с использованием Python. Я хочу получить данные в фрейм данных pandas для управления данными и создания на их основе диаграмм. У меня возникла проблема с обработкой строк при использовании JDBC. Этот пост поможет, если у кого-то еще возникнут такие же проблемы. Или, если есть более простой способ решить эту проблему, дайте мне знать в комментариях!

Я использую OSX, поэтому не уверен, насколько уникальна моя проблема. Я использую Jupyter Notebooks, хотя код, как правило, будет таким же, если вы используете любую другую программу или фреймворк Python.

Проблема JDBC

Когда я извлекаю данные из базы данных, описания столбцов и любые строковые данные возвращаются как тип данных java.lang.String. Если вы распечатаете строковые данные, они будут выглядеть так: «(p,a,i,n,i,n,t,h,e,r,e,a,r)» вместо ожидаемого «painintheear».

Вероятно, это связано с тем, что строки символов типа данных java.lang.String при получении с помощью JDBC передаются как итерация или массив. Это может произойти, если используемый вами мост Python-Java (например, JayDeBeApi, JDBC) не преобразует java.lang.String в строку Python автоматически за один шаг.

Строковое представление Python в Python, напротив, представляет всю строку как одну единицу. Когда Python получает обычную строку (например, через ODBC), она не разбивается на отдельные символы.

Решение JDBC

Чтобы устранить эту проблему, необходимо убедиться, что java.lang.String правильно преобразован в тип Python str. Вы можете явно выполнить это преобразование при обработке извлеченных данных, чтобы оно не интерпретировалось как итерация или список символов.

Существует множество способов манипулирования строками; вот что я сделал.

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

Проблема ODBC

При использовании соединения ODBC строки не возвращаются или имеют значение NA.

Если вы подключаетесь к базе данных, содержащей данные Unicode (например, имена на разных языках), или если вашему приложению необходимо хранить или извлекать символы, отличные от ASCII, вы должны убедиться, что данные остаются правильно закодированными при передаче между базу данных и ваше приложение Python.

Решение ODBC

Этот код гарантирует, что строковые данные кодируются и декодируются с использованием UTF-8 при отправке и получении данных в базу данных. Это особенно важно при работе с символами, отличными от ASCII, или при обеспечении совместимости с данными 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

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

Сообщает pyodbc, как декодировать символьные данные из базы данных при извлечении типов SQL_CHAR (обычно символьных полей фиксированной длины).

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

Задает декодирование для SQL_WCHAR, типов расширенных символов (т. е. строк Юникода, таких как NVARCHAR или NCHAR в SQL Server).

connection.setencoding(encoding="utf8")

Гарантирует, что любые строки или символьные данные, отправленные из Python в базу данных, будут закодированы с использованием UTF-8,
это означает, что Python преобразует свой внутренний тип str (Unicode) в байты UTF-8 при взаимодействии с базой данных.


Собираем все это вместе

Установить JDBC

Установите JAVA - используйте dmg

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

Обновите оболочку, чтобы установить версию по умолчанию

$ /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

Добавьте JAVA_HOME в свой путь

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

Получите драйвер JDBC

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

Поместите jar-файл куда-нибудь... Я поместил его в $HOME

$ ls $HOME/*.jar
/Users/myname/intersystems-jdbc-3.8.4.jar

Пример кода

Предполагается, что вы настроили ODBC (пример на другой день, собака съела мои записи...).

Примечание: это взлом моего настоящего кода. Обратите внимание на имена переменных.

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()
Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/intersystems/access-iris-database-with-odbc-or-jdbc-using-python-54ok?1. В случае нарушения прав обращайтесь по адресу [email protected]. удалить его
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3