Python Python в стиле SQL объединяет два списка классов - PullRequest
0 голосов
/ 13 декабря 2018

У меня есть два списка объектов: listA<modelA>(), listB<modelB>() на основе моделей ниже.

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String

Base = declarative_base()

class modelA(Base):
    __tablename__ = "TableA"

    rowID = Column(Integer, primary_key=True)
    applicationNo = Column(String)
    accountNum = Column(String)
    sanitizedAccountNum = Column(String)

class modelB(Base):
    __tablename__ = "TableB"

    rowID = Column(Integer, primary_key=True)
    applicationNo = Column(String)
    accountNum = Column(String)
    sanitizedAccountNum = Column(String)

# create SQLAlchemy engine/connection
engine = create_engine("mysql+mysqlconnector://root:usbw@localhost:3307/testDB", echo=False)
dbSession = sessionmaker(bind=engine)
session = dbSession()

# query to pull data from DB 
listA = session.query(modelA).limit(100).all()
listB = session.query(modelB).limit(100).all()

Эти списки заполняются с помощью SqlAlchemy.Каждая из таблиц содержит около миллиона записей в каждой, поэтому я пытаюсь выполнить запрос к части записей за раз.

После извлечения данных из БД я пытаюсь выполнитьСоединение в стиле SQL в двух вышеупомянутых списках, например, запрос SQL ниже:

SELECT a.applicationNo, a.sanitizedAccountNum
FROM listA a
LEFT JOIN listB b on b.applicationNo=a.applicationNo and b.sanitizedAccountNum=a.sanitizedAccountNum
WHERE b.applicationNo IS NULL;

Я пытался использовать DataFrame от Pandas, но не смог получить правильные результаты.

Pandas:

dfA = pd.DataFrame(listA)
dfB = pd.DataFrame(listB)
resultPD = pd.merge(dfA, dfB, how="left"), on=["applicationNo","sanitizedAccountNum"])

Предложение "on" здесь не работает, выдавая "KeyError: 'applicationNo'".Как мне установить столбцы "присоединиться" в приведенном выше запросе для моих моделей?

Трассировка:

Traceback (most recent call last):
  File "dbna.py", line 58, in <module>
    resultPD = pd.merge(dfA, dfB, indicator="i", how="left", on=["applicationNo","sanitizedAccountNum"])
  File "C:\Users\1833\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pandas\core\reshape\merge.py", line 61, in merge validate=validate)
  File "C:\Users\1833\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pandas\core\reshape\merge.py", line 551, in __init__ self.join_names) = self._get_merge_keys()
  File "C:\Users\1833\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pandas\core\reshape\merge.py", line 857, in _get_merge_keys rk, stacklevel=stacklevel))
  File "C:\Users\1833\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pandas\core\generic.py", line 1382, in _get_label_or_level_values raise KeyError(key)
KeyError: 'applicationNo'

Кроме того, это лучший способ для "левого соединения" listA и listB иполучить только те записи из списка A, которых нет в listB, на основании двух указанных выше указанных столбцов?

Изменить (Пример данных): Пример TableA

Пример TableB

ОБНОВЛЕНИЕ:

Как предложил @Philip в своих комментариях ниже, хитрость заключалась в том, чтобы напрямую связать результат БД с DataFrame Pandas вместо привязки ксписок класса (модель), а затем создание DataFrame из этого списка.Эта ссылка , предоставленная им в его комментариях, добилась цели.

1 Ответ

0 голосов
/ 13 декабря 2018

Одно из предложений может заключаться в том, что вы создаете представление либо в MySql, либо в виде запроса, а затем используете это представление с ограничением записи или указав размер фрагмента в пандах.

Создать ВИДв базе данных:

CREATE VIEW AB_joined AS
    SELECT a.applicationNo
        ,a.sanitizedAccountNum
    FROM listA a
    LEFT JOIN listB b ON b.applicationNo = a.applicationNo
        AND b.sanitizedAccountNum = a.sanitizedAccountNum
    WHERE b.applicationNo IS NULL

и используйте query1 в пандах:

query1 = "SELECT * FROM AB_joined"

или используйте просто используйте query2 непосредственно в пандах:

query2 = """
SELECT a.applicationNo
        ,a.sanitizedAccountNum
    FROM listA a
    LEFT JOIN listB b ON b.applicationNo = a.applicationNo
        AND b.sanitizedAccountNum = a.sanitizedAccountNum
    WHERE b.applicationNo IS NULL"""

Затем используйте pandas для чтенияchunksize, вы объединяете разные куски вместе.

result = pd.read_sql_query(query, engine, chunksize=100000)

Более подробную информацию о pandas.read_sql_query можно найти здесь

Еще одно предложение это создать представление непосредственно с sqlalchemy и сделать то, что вы сделали выше.На мой взгляд выбор зависит от цели проекта.Вы можете найти вдохновение для создания представлений в sqlalchemy здесь

Ваш первый вопрос .Я думаю, что запрос должен выглядеть следующим образом:

resultPD = dfA.merge(dfB, left_on="applicationNo", right_on="sanitizedLoanAccount", how="left")

Ваш второй вопрос .Левое соединение - это способ получить только записи из списка A, которых нет в списке B.Вы также используете предложение where, которое добавляет дополнительные правила, для которых следует выбирать строки.

ОБНОВЛЕНИЕ I

Я только что понял, что ваши данные хранятся в виде строк.Не рекомендуется объединять данные в строковых значениях.Если возможно, я бы предложил преобразовать числа, хранящиеся в виде строк, в целые числа.Это может помочь избежать многих проблем.

ОБНОВЛЕНИЕ II - добавлены данные

Я пытался использовать данные, из которых вы сделали снимок экрана.Просто используя два ряда от каждого.

dfA = pd.DataFrame({
    'RowID' : [1,2],
    'ApplicationNo': ['L0008065026','L000969215'],
    'AccountNum': ['34204731277', '006737107100039'],
    'SanatizedAccountNum': ['34204731277', '6737107100039']
    }) 

dfB = pd.DataFrame({
    'RowID' : [1,2],
    'ApplicationNo': ['L43907','L52006'],
    'AccountNum': ['3265470064', '073176310000477'],
    'SanatizedAccountNum': ['3265470064', '73176310000477']
    }) 

resultPD = dfA.merge(dfB, left_on="ApplicationNo", right_on="SanatizedAccountNum", how="left")

С учетом вышесказанного у меня нет проблем с получением результатаPD.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...